xref: /titanic_41/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelKeys.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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 		REFRELE(session_p, ses_lock_held);
453 		return (rv);
454 	}
455 
456 	/* Make the CRYPTO_OBJECT_WRAP_KEY ioctl call. */
457 	obj_wrapkey.wk_session = session_p->k_session;
458 	obj_wrapkey.wk_mechanism.cm_type = k_mech_type;
459 	obj_wrapkey.wk_mechanism.cm_param = pMechanism->pParameter;
460 	obj_wrapkey.wk_mechanism.cm_param_len = pMechanism->ulParameterLen;
461 	obj_wrapkey.wk_wrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
462 	obj_wrapkey.wk_wrapping_key.ck_obj_id = wrappingkey_p->k_handle;
463 	obj_wrapkey.wk_object_handle = key_p->k_handle;
464 	obj_wrapkey.wk_wrapped_key_len = *pulWrappedKeyLen;
465 	obj_wrapkey.wk_wrapped_key = (char *)pWrappedKey;
466 
467 	while ((r = ioctl(kernel_fd, CRYPTO_WRAP_KEY, &obj_wrapkey)) < 0) {
468 		if (errno != EINTR)
469 			break;
470 	}
471 	if (r < 0) {
472 		rv = CKR_FUNCTION_FAILED;
473 	} else {
474 		rv = crypto2pkcs11_error_number(obj_wrapkey.wk_return_value);
475 	}
476 
477 	/*
478 	 * Besides rv == CKR_OK, we will set the value of pulWrappedKeyLen
479 	 * when the applciation-supplied wrapped key buffer is too small.
480 	 * The situation that the application only asks for the length of
481 	 * the wrapped key is covered in rv == CKR_OK.
482 	 */
483 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
484 		*pulWrappedKeyLen = obj_wrapkey.wk_wrapped_key_len;
485 	}
486 
487 	REFRELE(session_p, ses_lock_held);
488 	return (rv);
489 }
490 
491 
492 CK_RV
493 C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
494     CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey,
495     CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate,
496     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
497 {
498 	CK_RV			rv = CKR_OK;
499 	kernel_session_t	*session_p;
500 	kernel_object_t		*unwrappingkey_p;
501 	kernel_object_t		*new_objp = NULL;
502 	kernel_slot_t		*pslot;
503 	boolean_t		ses_lock_held = B_FALSE;
504 	CK_BBOOL		is_pri_obj;
505 	CK_BBOOL		is_token_obj = FALSE;
506 	CK_MECHANISM_INFO	info;
507 	uint32_t		k_mi_flags;
508 	CK_BYTE			*clear_key_val = NULL;
509 	CK_ULONG 		ulDataLen;
510 	CK_ATTRIBUTE_PTR	newTemplate = NULL;
511 	CK_ULONG		templ_size;
512 	crypto_mech_type_t	k_mech_type;
513 	crypto_object_unwrap_key_t obj_unwrapkey;
514 	int r;
515 
516 	if (!kernel_initialized)
517 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
518 
519 	if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL) {
520 		return (CKR_ARGUMENTS_BAD);
521 	}
522 
523 	if ((pTemplate == NULL) && (ulAttributeCount != 0)) {
524 		return (CKR_ARGUMENTS_BAD);
525 	}
526 
527 	/* Obtain the session pointer. */
528 	rv = handle2session(hSession, &session_p);
529 	if (rv != CKR_OK)
530 		return (rv);
531 
532 	/* Obtain the wrapping key object pointer. */
533 	HANDLE2OBJECT(hUnwrappingKey, unwrappingkey_p, rv);
534 	if (rv != CKR_OK) {
535 		goto failed_exit;
536 	}
537 
538 	/*
539 	 * If the HW provider doesn't support C_UnwrapKey, we will try
540 	 * to emulate it in the library.
541 	 */
542 	pslot = slot_table[session_p->ses_slotid];
543 	if ((pslot->sl_func_list.fl_object_create == B_FALSE) &&
544 	    (pslot->sl_func_list.fl_key_unwrap == B_FALSE)) {
545 		rv = get_mechanism_info(pslot, pMechanism->mechanism, &info,
546 		    &k_mi_flags);
547 		if (rv != CKR_OK) {
548 			goto failed_exit;
549 		}
550 
551 		/*
552 		 * If the mechanism flag doesn't have CKF_UNWRAP, and it's
553 		 * an unwrapping of a secret key object, then help this
554 		 * out with a decryption followed by an object creation.
555 		 */
556 		if (!(k_mi_flags & CRYPTO_FG_UNWRAP) &&
557 		    (k_mi_flags & CRYPTO_FG_DECRYPT) &&
558 		    (is_secret_key_template(pTemplate, ulAttributeCount))) {
559 
560 			/* First allocate space for the recovered key value */
561 			clear_key_val = malloc(ulWrappedKeyLen);
562 			if (clear_key_val == NULL) {
563 				rv = CKR_HOST_MEMORY;
564 				goto failed_exit;
565 			}
566 
567 			rv = kernel_decrypt_init(session_p, unwrappingkey_p,
568 			    pMechanism);
569 			if (rv != CKR_OK) {
570 				goto failed_exit;
571 			}
572 
573 			ulDataLen = ulWrappedKeyLen;
574 			rv = kernel_decrypt(session_p, pWrappedKey,
575 			    ulWrappedKeyLen, clear_key_val, &ulDataLen);
576 			if (rv != CKR_OK) {
577 				goto failed_exit;
578 			}
579 
580 			/* Now add the CKA_VALUE attribute to template */
581 			templ_size = ulAttributeCount * sizeof (CK_ATTRIBUTE);
582 			newTemplate = malloc(templ_size +
583 			    sizeof (CK_ATTRIBUTE));
584 			if (newTemplate == NULL) {
585 				rv = CKR_HOST_MEMORY;
586 				goto failed_exit;
587 			}
588 
589 			bcopy(pTemplate, newTemplate, templ_size);
590 			newTemplate[ulAttributeCount].type = CKA_VALUE;
591 			newTemplate[ulAttributeCount].pValue = clear_key_val;
592 			newTemplate[ulAttributeCount].ulValueLen = ulDataLen;
593 
594 			/* Finally create the key, based on the new template */
595 			rv = kernel_add_object(newTemplate,
596 			    ulAttributeCount + 1, phKey, session_p);
597 			(void) free(clear_key_val);
598 			(void) free(newTemplate);
599 			REFRELE(session_p, ses_lock_held);
600 			return (rv);
601 		} else {
602 			rv = CKR_FUNCTION_FAILED;
603 			goto failed_exit;
604 		}
605 	}
606 
607 	/*
608 	 * If we come here, the HW provider must have registered the unwrapkey
609 	 * entry.  Therefore, the unwrap key will be performed in the HW
610 	 * provider.
611 	 */
612 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
613 	if (rv != CKR_OK) {
614 		goto failed_exit;
615 	}
616 
617 	/* Create an object wrapper for the new key in the library first */
618 	new_objp = calloc(1, sizeof (kernel_object_t));
619 	if (new_objp == NULL) {
620 		rv = CKR_HOST_MEMORY;
621 		goto failed_exit;
622 	}
623 
624 	/* Process the attributes */
625 	rv = process_object_attributes(pTemplate, ulAttributeCount,
626 	    &obj_unwrapkey.uk_attributes, &is_token_obj);
627 	if (rv != CKR_OK) {
628 		goto failed_exit;
629 	}
630 
631 	/* Cannot create a token object with a READ-ONLY session. */
632 	if (is_token_obj && session_p->ses_RO) {
633 		free_object_attributes(obj_unwrapkey.uk_attributes,
634 		    ulAttributeCount);
635 		rv = CKR_SESSION_READ_ONLY;
636 		goto failed_exit;
637 	}
638 
639 	/* Make the CRYPTO_UNWRAP_KEY ioctl call. */
640 	obj_unwrapkey.uk_session = session_p->k_session;
641 	obj_unwrapkey.uk_mechanism.cm_type = k_mech_type;
642 	obj_unwrapkey.uk_mechanism.cm_param = pMechanism->pParameter;
643 	obj_unwrapkey.uk_mechanism.cm_param_len = pMechanism->ulParameterLen;
644 	obj_unwrapkey.uk_unwrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
645 	obj_unwrapkey.uk_unwrapping_key.ck_obj_id = unwrappingkey_p->k_handle;
646 	obj_unwrapkey.uk_wrapped_key = (char *)pWrappedKey;
647 	obj_unwrapkey.uk_wrapped_key_len = ulWrappedKeyLen;
648 	obj_unwrapkey.uk_count = ulAttributeCount;
649 
650 	while ((r = ioctl(kernel_fd, CRYPTO_UNWRAP_KEY, &obj_unwrapkey)) < 0) {
651 		if (errno != EINTR)
652 			break;
653 	}
654 	if (r < 0) {
655 		rv = CKR_FUNCTION_FAILED;
656 	} else {
657 		rv = crypto2pkcs11_error_number(obj_unwrapkey.uk_return_value);
658 	}
659 
660 	free_object_attributes(obj_unwrapkey.uk_attributes, ulAttributeCount);
661 	if (rv != CKR_OK) {
662 		goto failed_exit;
663 	}
664 
665 	/* Get the CKA_PRIVATE value for the unwrapped key. */
666 	rv = get_cka_private_value(session_p, obj_unwrapkey.uk_object_handle,
667 	    &is_pri_obj);
668 	if (rv != CKR_OK) {
669 		goto failed_exit;
670 	}
671 
672 	/*
673 	 * Store the kernel object handle in the new key object wrapper and
674 	 * initialize it.
675 	 */
676 	new_objp->k_handle = obj_unwrapkey.uk_object_handle;
677 	new_objp->is_lib_obj = B_FALSE;
678 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
679 	new_objp->extra_attrlistp = NULL;
680 
681 	if (is_pri_obj)
682 		new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
683 	else
684 		new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
685 
686 	if (is_token_obj)
687 		new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
688 	else
689 		new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
690 
691 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
692 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
693 
694 	/*
695 	 * Add the new object to the slot's token object list if it is a
696 	 * a token object. Otherwise, add it to the session's object list.
697 	 */
698 	if (is_token_obj) {
699 		pslot = slot_table[session_p->ses_slotid];
700 		kernel_add_token_object_to_slot(new_objp, pslot);
701 	} else {
702 		kernel_add_object_to_session(new_objp, session_p);
703 	}
704 
705 	*phKey = (CK_OBJECT_HANDLE)new_objp;
706 	REFRELE(session_p, ses_lock_held);
707 	return (rv);
708 
709 failed_exit:
710 	if (new_objp != NULL)
711 		(void) free(new_objp);
712 
713 	if (clear_key_val != NULL)
714 		(void) free(clear_key_val);
715 
716 	if (newTemplate != NULL)
717 		(void) free(newTemplate);
718 
719 	REFRELE(session_p, ses_lock_held);
720 	return (rv);
721 }
722 
723 
724 CK_RV
725 C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
726     CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
727     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
728 {
729 	CK_RV			rv = CKR_OK;
730 	kernel_session_t	*session_p;
731 	kernel_object_t		*basekey_p;
732 	kernel_object_t		*new_objp;
733 	kernel_slot_t		*pslot;
734 	boolean_t		ses_lock_held = B_FALSE;
735 	CK_BBOOL		is_pri_obj;
736 	CK_BBOOL		is_token_obj = FALSE;
737 	crypto_mech_type_t	k_mech_type;
738 	crypto_derive_key_t	obj_dk;
739 	int r;
740 
741 	if (!kernel_initialized)
742 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
743 
744 	/* Obtain the session pointer. */
745 	rv = handle2session(hSession, &session_p);
746 	if (rv != CKR_OK)
747 		return (rv);
748 
749 	if ((pMechanism == NULL) || (phKey == NULL)) {
750 		rv = CKR_ARGUMENTS_BAD;
751 		goto failed_exit;
752 	}
753 
754 	if ((pTemplate == NULL && ulAttributeCount != 0) ||
755 	    (pTemplate != NULL && ulAttributeCount == 0)) {
756 		rv = CKR_ARGUMENTS_BAD;
757 		goto failed_exit;
758 	}
759 
760 	/* Obtain the base key object pointer. */
761 	HANDLE2OBJECT(hBaseKey, basekey_p, rv);
762 	if (rv != CKR_OK) {
763 		goto failed_exit;
764 	}
765 
766 	/* Get the kernel's internal mechanism number. */
767 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
768 	if (rv != CKR_OK) {
769 		goto failed_exit;
770 	}
771 
772 	/* Create an object wrapper in the library for the generated key. */
773 	new_objp = calloc(1, sizeof (kernel_object_t));
774 	if (new_objp == NULL) {
775 		rv = CKR_HOST_MEMORY;
776 		goto failed_exit;
777 	}
778 
779 	/* Process the attributes */
780 	rv = process_object_attributes(pTemplate, ulAttributeCount,
781 	    &obj_dk.dk_attributes, &is_token_obj);
782 	if (rv != CKR_OK) {
783 		goto failed_exit;
784 	}
785 
786 	/* Cannot create a token object with a READ-ONLY session. */
787 	if (is_token_obj && session_p->ses_RO) {
788 		free_object_attributes(obj_dk.dk_attributes, ulAttributeCount);
789 		rv = CKR_SESSION_READ_ONLY;
790 		goto failed_exit;
791 	}
792 
793 	/* Call the CRYPTO_DERIVE_KEY ioctl */
794 	obj_dk.dk_session = session_p->k_session;
795 	obj_dk.dk_mechanism.cm_type = k_mech_type;
796 	obj_dk.dk_mechanism.cm_param = pMechanism->pParameter;
797 	obj_dk.dk_mechanism.cm_param_len = pMechanism->ulParameterLen;
798 	obj_dk.dk_base_key.ck_format = CRYPTO_KEY_REFERENCE;
799 	obj_dk.dk_base_key.ck_obj_id = basekey_p->k_handle;
800 	obj_dk.dk_count = ulAttributeCount;
801 
802 	while ((r = ioctl(kernel_fd, CRYPTO_DERIVE_KEY, &obj_dk)) < 0) {
803 		if (errno != EINTR)
804 			break;
805 	}
806 	if (r < 0) {
807 		rv = CKR_FUNCTION_FAILED;
808 	} else {
809 		rv = crypto2pkcs11_error_number(obj_dk.dk_return_value);
810 	}
811 
812 	free_object_attributes(obj_dk.dk_attributes, ulAttributeCount);
813 	if (rv != CKR_OK) {
814 		goto failed_exit;
815 	}
816 
817 	/* Get the CKA_PRIVATE value for the derived key. */
818 	rv = get_cka_private_value(session_p, obj_dk.dk_object_handle,
819 	    &is_pri_obj);
820 	if (rv != CKR_OK) {
821 		goto failed_exit;
822 	}
823 
824 	/*
825 	 * Store the kernel object handle into the new derived key object
826 	 * and finish the object initialization.
827 	 */
828 	new_objp->is_lib_obj = B_FALSE;
829 	new_objp->k_handle = obj_dk.dk_object_handle;
830 	new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
831 	new_objp->extra_attrlistp = NULL;
832 
833 	if (is_pri_obj)
834 		new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
835 	else
836 		new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
837 
838 	if (is_token_obj)
839 		new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
840 	else
841 		new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
842 
843 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
844 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
845 
846 	/*
847 	 * Add the new derived object to the slot's token list if it is a
848 	 * token object. Otherwise, add it to the session's object list.
849 	 */
850 	if (is_token_obj) {
851 		pslot = slot_table[session_p->ses_slotid];
852 		kernel_add_token_object_to_slot(new_objp, pslot);
853 	} else {
854 		kernel_add_object_to_session(new_objp, session_p);
855 	}
856 
857 	*phKey = (CK_OBJECT_HANDLE)new_objp;
858 	REFRELE(session_p, ses_lock_held);
859 	return (rv);
860 
861 failed_exit:
862 	if (new_objp != NULL) {
863 		(void) free(new_objp);
864 	}
865 
866 	REFRELE(session_p, ses_lock_held);
867 	return (rv);
868 }
869