xref: /titanic_52/usr/src/lib/pkcs11/libpkcs11/common/metaObjectManager.c (revision 0eb822a1c0c2bea495647510b75f77f0e57633eb)
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 <stdlib.h>
30 #include <string.h>
31 #include <strings.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include "metaGlobal.h"
37 
38 /* Size of the template for creating key used for wrap/unwrap */
39 #define	WRAP_KEY_TEMPLATE_SIZE	7
40 
41 /*
42  * Information necessary to create keys for C_WrapKey/C_UnwrapKey
43  */
44 typedef struct _wrap_info {
45 	CK_OBJECT_CLASS		class; /* class of the key for wrap/unwrap */
46 	CK_KEY_TYPE		key_type; /* key type of key for wrap/unwrap */
47 	CK_ULONG		key_length; /* length of key */
48 	CK_MECHANISM_TYPE	mech_type; /* mech used for wrap/unwrap */
49 	CK_ULONG		iv_length; /* length of iv for mech */
50 
51 	boolean_t		src_supports;
52 	boolean_t		dst_supports;
53 } wrap_info_t;
54 
55 extern pthread_rwlock_t meta_sessionlist_lock;
56 extern meta_session_t *meta_sessionlist_head;
57 
58 static wrap_info_t common_wrap_info[] = {
59 	{CKO_SECRET_KEY, CKK_AES, 16, CKM_AES_CBC_PAD, 16, B_FALSE, B_FALSE},
60 	{CKO_SECRET_KEY, CKK_DES3, 24, CKM_DES3_CBC_PAD, 8, B_FALSE, B_FALSE},
61 	{CKO_SECRET_KEY, CKK_DES, 8, CKM_DES_CBC_PAD, 8, B_FALSE, B_FALSE},
62 };
63 
64 static unsigned int num_common_wrap_info =
65     sizeof (common_wrap_info) / sizeof (wrap_info_t);
66 
67 static wrap_info_t special_wrap_info[] = {
68 	{CKO_SECRET_KEY, CKK_SKIPJACK, 12,  CKM_SKIPJACK_WRAP, 0,
69 	    B_FALSE, B_FALSE},
70 	{CKO_SECRET_KEY, CKK_BATON, 40, CKM_BATON_WRAP, 0,
71 	    B_FALSE, B_FALSE},
72 	{CKO_SECRET_KEY, CKK_JUNIPER, 40, CKM_JUNIPER_WRAP, 0,
73 	    B_FALSE, B_FALSE},
74 };
75 static unsigned int num_special_wrap_info =
76     sizeof (special_wrap_info) / sizeof (wrap_info_t);
77 
78 static wrap_info_t rsa_wrap_info[] = {
79 	{CKO_PUBLIC_KEY, CKK_RSA, 0,  CKM_RSA_PKCS, 0,
80 	    B_FALSE, B_FALSE},
81 	{CKO_PUBLIC_KEY, CKK_RSA, 0, CKM_RSA_X_509, 0,
82 	    B_FALSE, B_FALSE},
83 };
84 static unsigned int num_rsa_wrap_info =
85     sizeof (rsa_wrap_info) / sizeof (wrap_info_t);
86 
87 
88 static pthread_rwlock_t meta_objectclose_lock;
89 static pthread_rwlock_t tokenobject_list_lock;
90 static meta_object_t *tokenobject_list_head;
91 
92 static CK_BBOOL falsevalue = FALSE;
93 static CK_BBOOL truevalue = TRUE;
94 
95 /*
96  * Public and private exponent, and Module value for
97  * creating the RSA public/private key.
98  *
99  */
100 static CK_BYTE PubExpo[3] = {0x01, 0x00, 0x01};
101 CK_BYTE PriExpo[128] = {
102 	0x8e, 0xc9, 0x70, 0x57, 0x6b, 0xcd, 0xfb, 0xa9,
103 	0x19, 0xad, 0xcd, 0x91, 0x69, 0xd5, 0x52, 0xec,
104 	0x72, 0x1e, 0x45, 0x15, 0x06, 0xdc, 0x65, 0x2d,
105 	0x98, 0xc4, 0xce, 0x33, 0x54, 0x15, 0x70, 0x8d,
106 	0xfa, 0x65, 0xea, 0x53, 0x44, 0xf3, 0x3e, 0x3f,
107 	0xb4, 0x4c, 0x60, 0xd5, 0x01, 0x2d, 0xa4, 0x12,
108 	0x99, 0xbf, 0x3f, 0x0b, 0xcd, 0xbb, 0x24, 0x10,
109 	0x60, 0x30, 0x5e, 0x58, 0xf8, 0x59, 0xaa, 0xd1,
110 	0x63, 0x3b, 0xbc, 0xcb, 0x94, 0x58, 0x38, 0x24,
111 	0xfc, 0x65, 0x25, 0xc5, 0xa6, 0x51, 0xa2, 0x2e,
112 	0xf1, 0x5e, 0xf5, 0xc1, 0xf5, 0x46, 0xf7, 0xbd,
113 	0xc7, 0x62, 0xa8, 0xe2, 0x27, 0xd6, 0x94, 0x5b,
114 	0xd3, 0xa2, 0xb5, 0x76, 0x42, 0x67, 0x6b, 0x86,
115 	0x91, 0x97, 0x4d, 0x07, 0x92, 0x00, 0x4a, 0xdf,
116 	0x0b, 0x65, 0x64, 0x05, 0x03, 0x48, 0x27, 0xeb,
117 	0xce, 0x9a, 0x49, 0x7f, 0x3e, 0x10, 0xe0, 0x01};
118 
119 static CK_BYTE Modulus[128] = {
120 	0x94, 0x32, 0xb9, 0x12, 0x1d, 0x68, 0x2c, 0xda,
121 	0x2b, 0xe0, 0xe4, 0x97, 0x1b, 0x4d, 0xdc, 0x43,
122 	0xdf, 0x38, 0x6e, 0x7b, 0x9f, 0x07, 0x58, 0xae,
123 	0x9d, 0x82, 0x1e, 0xc7, 0xbc, 0x92, 0xbf, 0xd3,
124 	0xce, 0x00, 0xbb, 0x91, 0xc9, 0x79, 0x06, 0x03,
125 	0x1f, 0xbc, 0x9f, 0x94, 0x75, 0x29, 0x5f, 0xd7,
126 	0xc5, 0xf3, 0x73, 0x8a, 0xa4, 0x35, 0x43, 0x7a,
127 	0x00, 0x32, 0x97, 0x3e, 0x86, 0xef, 0x70, 0x6f,
128 	0x18, 0x56, 0x15, 0xaa, 0x6a, 0x87, 0xe7, 0x8d,
129 	0x7d, 0xdd, 0x1f, 0xa4, 0xe4, 0x31, 0xd4, 0x7a,
130 	0x8c, 0x0e, 0x20, 0xd2, 0x23, 0xf5, 0x57, 0x3c,
131 	0x1b, 0xa8, 0x44, 0xa4, 0x57, 0x8f, 0x33, 0x52,
132 	0xad, 0x83, 0xae, 0x4a, 0x97, 0xa6, 0x1e, 0xa6,
133 	0x2b, 0xfa, 0xea, 0xeb, 0x6e, 0x71, 0xb8, 0xb6,
134 	0x0a, 0x36, 0xed, 0x83, 0xce, 0xb0, 0xdf, 0xc1,
135 	0xd4, 0x3a, 0xe9, 0x99, 0x6f, 0xf3, 0x96, 0xb7};
136 
137 static CK_RV
138 meta_clone_template_setup(meta_object_t *object,
139     const generic_attr_t *attributes, size_t num_attributes);
140 
141 /*
142  * meta_objectManager_initialize
143  *
144  * Called from meta_Initialize.  Initializes all the variables used
145  * by the object manager.
146  */
147 CK_RV
148 meta_objectManager_initialize()
149 {
150 	if (pthread_rwlock_init(&meta_objectclose_lock, NULL) != 0) {
151 		return (CKR_FUNCTION_FAILED);
152 	}
153 
154 	if (pthread_rwlock_init(&tokenobject_list_lock, NULL) != 0) {
155 		(void) pthread_rwlock_destroy(&meta_objectclose_lock);
156 		return (CKR_FUNCTION_FAILED);
157 	}
158 
159 	tokenobject_list_head = NULL;
160 
161 	return (CKR_OK);
162 }
163 
164 void
165 meta_objectManager_finalize()
166 {
167 	/*
168 	 * If there are still any token object in the list, need to
169 	 * deactivate all of them.
170 	 */
171 	(void) meta_token_object_deactivate(ALL_TOKEN);
172 
173 	(void) pthread_rwlock_destroy(&meta_objectclose_lock);
174 	(void) pthread_rwlock_destroy(&tokenobject_list_lock);
175 }
176 
177 
178 
179 /*
180  * meta_handle2object
181  *
182  * Convert a CK_OBJECT_HANDLE to the corresponding metaobject. If
183  * successful, a reader-lock on the object will be held to indicate
184  * that it's in use. Call OBJRELEASE() when finished.
185  *
186  */
187 CK_RV
188 meta_handle2object(CK_OBJECT_HANDLE hObject, meta_object_t **object)
189 {
190 	meta_object_t *tmp_object = (meta_object_t *)(hObject);
191 
192 	/* Check for bad args (eg CK_INVALID_HANDLE, which is 0/NULL). */
193 	if (tmp_object == NULL) {
194 		*object = NULL;
195 		return (CKR_OBJECT_HANDLE_INVALID);
196 	}
197 
198 
199 	/* Lock to ensure the magic-check + read-lock is atomic. */
200 	(void) pthread_rwlock_rdlock(&meta_objectclose_lock);
201 
202 	if (tmp_object->magic_marker != METASLOT_OBJECT_MAGIC) {
203 		(void) pthread_rwlock_unlock(&meta_objectclose_lock);
204 		*object = NULL;
205 		return (CKR_OBJECT_HANDLE_INVALID);
206 	}
207 	(void) pthread_rwlock_rdlock(&tmp_object->object_lock);
208 	(void) pthread_rwlock_unlock(&meta_objectclose_lock);
209 
210 	*object = tmp_object;
211 	return (CKR_OK);
212 }
213 
214 
215 /*
216  * meta_object_alloc
217  *
218  * Creates a new metaobject, but does not yet add it to the object list.
219  * Once the caller has finished initializing the object (by setting
220  * object attributes), meta_object_add should be called. This two-step
221  * process prevents others from seeing the object until fully intitialized.
222  *
223  */
224 CK_RV
225 meta_object_alloc(meta_session_t *session, meta_object_t **object)
226 {
227 	meta_object_t *new_object;
228 	CK_ULONG num_slots;
229 
230 	/* Allocate memory for the object. */
231 	new_object = calloc(1, sizeof (meta_object_t));
232 	if (new_object == NULL)
233 		return (CKR_HOST_MEMORY);
234 
235 	num_slots = meta_slotManager_get_slotcount();
236 
237 	new_object->clones = calloc(num_slots, sizeof (slot_object_t *));
238 	if (new_object->clones == NULL) {
239 		free(new_object);
240 		return (CKR_HOST_MEMORY);
241 	}
242 
243 	new_object->tried_create_clone = calloc(num_slots, sizeof (boolean_t));
244 	if (new_object->tried_create_clone == NULL) {
245 		free(new_object->clones);
246 		free(new_object);
247 		return (CKR_HOST_MEMORY);
248 	}
249 
250 	/* Initialize the object fields. */
251 	new_object->magic_marker = METASLOT_OBJECT_MAGIC;
252 	(void) pthread_rwlock_init(&new_object->object_lock, NULL);
253 	(void) pthread_rwlock_init(&new_object->attribute_lock, NULL);
254 	(void) pthread_mutex_init(&new_object->clone_create_lock, NULL);
255 	(void) pthread_mutex_init(&new_object->isClosingObject_lock, NULL);
256 	new_object->creator_session = session;
257 
258 	*object = new_object;
259 
260 	return (CKR_OK);
261 }
262 
263 
264 /*
265  * meta_object_get_attr
266  *
267  * Get attribute values to fill in attribute values
268  * being kept in the metaslot object.  The following 4 attributes
269  * in the meta_object_t structure will be filled in:
270  * isToken, isPrivate, isSensitive, isExtractable
271  *
272  * It's basically an easy way to do a C_GetAttributeValue.
273  * So, the hSession argument is assumed
274  * to be valid, and the pointer to meta_object_t is also assumed
275  * to be valid.
276  */
277 CK_RV
278 meta_object_get_attr(slot_session_t *slot_session, CK_OBJECT_HANDLE hObject,
279     meta_object_t *object)
280 {
281 	CK_BBOOL is_sensitive, is_extractable, is_token, is_private;
282 	CK_OBJECT_CLASS class;
283 	CK_ATTRIBUTE attrs[3];
284 	CK_RV rv;
285 	CK_SESSION_HANDLE hSession = slot_session->hSession;
286 	CK_SLOT_ID fw_st_id = slot_session->fw_st_id;
287 
288 	attrs[0].type = CKA_CLASS;
289 	attrs[0].pValue = &class;
290 	attrs[0].ulValueLen = sizeof (class);
291 
292 	attrs[1].type = CKA_TOKEN;
293 	attrs[1].pValue = &is_token;
294 	attrs[1].ulValueLen = sizeof (is_token);
295 
296 	attrs[2].type = CKA_PRIVATE;
297 	attrs[2].pValue = &is_private;
298 	attrs[2].ulValueLen = sizeof (is_private);
299 
300 	rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession, hObject,
301 	    attrs, 3);
302 	if (rv != CKR_OK) {
303 		return (rv);
304 	}
305 
306 
307 	if ((class == CKO_PRIVATE_KEY) || (class == CKO_SECRET_KEY)) {
308 		/*
309 		 * CKA_SENSITIVE and CKA_EXTRACTABLE only applies to private
310 		 * and secret keys.
311 		 */
312 		attrs[0].type = CKA_SENSITIVE;
313 		attrs[0].pValue = &is_sensitive;
314 		attrs[0].ulValueLen = sizeof (is_sensitive);
315 
316 		attrs[1].type = CKA_EXTRACTABLE;
317 		attrs[1].pValue = &is_extractable;
318 		attrs[1].ulValueLen = sizeof (is_extractable);
319 
320 		rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession,
321 		    hObject, attrs, 2);
322 		if (rv != CKR_OK) {
323 			return (rv);
324 		}
325 	} else {
326 		is_sensitive = CK_FALSE;
327 		is_extractable = CK_TRUE;
328 	}
329 
330 	object->isToken = is_token;
331 	object->isPrivate = is_private;
332 	object->isSensitive = is_sensitive;
333 	object->isExtractable = is_extractable;
334 
335 	return (CKR_OK);
336 }
337 
338 
339 /*
340  * meta_object_activate
341  *
342  * Add a new metaobject to the list of objects. See also meta_object_create,
343  * which would be called to create an object before it is added.
344  */
345 void
346 meta_object_activate(meta_object_t *new_object)
347 {
348 	pthread_rwlock_t *list_lock;
349 	meta_object_t **list_head;
350 
351 	/*
352 	 * For session objects, we keep the list in the session that created
353 	 * this object, because this object will be destroyed when that session
354 	 * is closed.
355 	 *
356 	 * For token objects, the list is global (ie, not associated with any
357 	 * particular session).
358 	 */
359 	if (new_object->isToken) {
360 		list_lock = &tokenobject_list_lock;
361 		list_head = &tokenobject_list_head;
362 	} else {
363 		list_lock = &new_object->creator_session->object_list_lock;
364 		list_head = &new_object->creator_session->object_list_head;
365 	}
366 
367 	/* Add object to the list of objects. */
368 	(void) pthread_rwlock_wrlock(list_lock);
369 	INSERT_INTO_LIST(*list_head, new_object);
370 	(void) pthread_rwlock_unlock(list_lock);
371 }
372 
373 
374 /*
375  * meta_object_deactivate
376  *
377  * Removes the object from the list of valid meta objects.  Note
378  * that this function does not clean up any allocated
379  * resources (memory, object clones, etc).   Cleaning up of
380  * allocated resources is done by calling the meta_object_deallocate()
381  *
382  */
383 CK_RV
384 meta_object_deactivate(meta_object_t *object, boolean_t have_list_lock,
385     boolean_t have_object_lock)
386 {
387 	pthread_rwlock_t *list_lock;
388 	meta_object_t **list_head;
389 
390 	if (!have_object_lock) {
391 		(void) pthread_rwlock_rdlock(&object->object_lock);
392 	}
393 
394 	(void) pthread_mutex_lock(&object->isClosingObject_lock);
395 	if (object->isClosingObject) {
396 		/* Lost a delete race. */
397 		(void) pthread_mutex_unlock(&object->isClosingObject_lock);
398 		OBJRELEASE(object);
399 		return (CKR_OBJECT_HANDLE_INVALID);
400 	}
401 	object->isClosingObject = B_TRUE;
402 	(void) pthread_mutex_unlock(&object->isClosingObject_lock);
403 
404 	if (object->isToken) {
405 		list_lock = &tokenobject_list_lock;
406 		list_head = &tokenobject_list_head;
407 	} else {
408 		list_lock = &object->creator_session->object_list_lock;
409 		list_head = &object->creator_session->object_list_head;
410 	}
411 
412 	/*
413 	 * Remove object from the object list. Once removed, it will not
414 	 * be possible for another thread to begin using the object.
415 	 */
416 	(void) pthread_rwlock_wrlock(&meta_objectclose_lock);
417 	if (!have_list_lock) {
418 		(void) pthread_rwlock_wrlock(list_lock);
419 	}
420 
421 
422 	object->magic_marker = METASLOT_OBJECT_BADMAGIC;
423 	/*
424 	 * Can't use the regular REMOVE_FROM_LIST() function because
425 	 * that will miss the "error cleanup" situation where object is not yet
426 	 * in the list (object->next == NULL && object->prev == NULL)
427 	 */
428 	if (*list_head == object) {
429 		/* Object is the first one in the list */
430 		if (object->next) {
431 			*list_head = object->next;
432 			object->next->prev = NULL;
433 		} else {
434 			/* Object is the only one in the list */
435 			*list_head = NULL;
436 		}
437 	} else if (object->next != NULL || object->prev != NULL) {
438 		if (object->next) {
439 			object->prev->next = object->next;
440 			object->next->prev = object->prev;
441 		} else {
442 			/* Object is the last one in the list */
443 			object->prev->next = NULL;
444 		}
445 	}
446 
447 	if (!have_list_lock) {
448 		(void) pthread_rwlock_unlock(list_lock);
449 	}
450 	(void) pthread_rwlock_unlock(&meta_objectclose_lock);
451 
452 	/*
453 	 * Wait for anyone already using object to finish, by obtaining
454 	 * a writer-lock (need to release our reader-lock first). Once we
455 	 * get the write lock, we can just release it and finish cleaning
456 	 * up the object.
457 	 */
458 	(void) pthread_rwlock_unlock(&object->object_lock); /* rdlock */
459 	(void) pthread_rwlock_wrlock(&object->object_lock);
460 	(void) pthread_rwlock_unlock(&object->object_lock); /* wrlock */
461 
462 
463 	return (CKR_OK);
464 }
465 
466 
467 /*
468  * meta_object_dealloc
469  *
470  * Performs final object cleanup, releasing any allocated memory and
471  * destroying any clones on other slots. Caller is assumed to have
472  * called meta_object_deactivate() before this function.
473  *
474  * Caller is assumed to have only reference to object, but should have
475  * released any lock.
476  *
477  * If "nukeSourceObj" argument is true, we will actually delete the
478  * object from the underlying slot.
479  */
480 CK_RV
481 meta_object_dealloc(meta_object_t *object, boolean_t nukeSourceObj)
482 {
483 	CK_RV rv, save_rv = CKR_OK;
484 	CK_ULONG slotnum, num_slots;
485 	CK_ULONG i;
486 
487 	/* First, delete all the clones of this object on other slots. */
488 	num_slots = meta_slotManager_get_slotcount();
489 	for (slotnum = 0; slotnum < num_slots; slotnum++) {
490 		slot_session_t *obj_session;
491 		slot_object_t *clone;
492 
493 		clone = object->clones[slotnum];
494 		if (clone == NULL)
495 			continue;
496 
497 		if (nukeSourceObj || !object->isToken) {
498 
499 			rv = meta_get_slot_session(slotnum, &obj_session,
500 			    object->creator_session->session_flags);
501 
502 			if (rv == CKR_OK) {
503 				rv = FUNCLIST(obj_session->fw_st_id)->\
504 				    C_DestroyObject(obj_session->hSession,
505 				    clone->hObject);
506 
507 				meta_release_slot_session(obj_session);
508 				if ((rv != CKR_OK) && (save_rv == CKR_OK)) {
509 					save_rv = rv;
510 				}
511 			}
512 
513 		}
514 
515 		meta_slot_object_deactivate(clone);
516 		meta_slot_object_dealloc(clone);
517 
518 		object->clones[slotnum] = NULL;
519 	}
520 
521 	/* Now erase and delete any attributes in the metaobject. */
522 	dealloc_attributes(object->attributes, object->num_attributes);
523 
524 	free(object->clones);
525 	free(object->tried_create_clone);
526 
527 	if (object->clone_template) {
528 		for (i = 0; i < object->clone_template_size; i++) {
529 			free(((object->clone_template)[i]).pValue);
530 		}
531 		free(object->clone_template);
532 	}
533 
534 	/* Cleanup remaining object fields. */
535 	(void) pthread_rwlock_destroy(&object->object_lock);
536 	(void) pthread_rwlock_destroy(&object->attribute_lock);
537 	(void) pthread_mutex_destroy(&object->isClosingObject_lock);
538 	(void) pthread_mutex_destroy(&object->clone_create_lock);
539 
540 	meta_object_delay_free(object);
541 
542 	return (save_rv);
543 }
544 
545 
546 /*
547  * meta_slot_object_alloc
548  */
549 CK_RV
550 meta_slot_object_alloc(slot_object_t **object) {
551 	slot_object_t *new_object;
552 
553 	new_object = calloc(1, sizeof (slot_object_t));
554 	if (new_object == NULL)
555 		return (CKR_HOST_MEMORY);
556 
557 	*object = new_object;
558 	return (CKR_OK);
559 }
560 
561 
562 /*
563  * meta_slot_object_activate
564  */
565 void
566 meta_slot_object_activate(slot_object_t *object,
567 	slot_session_t *creator_session, boolean_t isToken)
568 {
569 	object->creator_session = creator_session;
570 
571 	if (isToken) {
572 		extern slot_data_t *slots;
573 		slot_data_t *slot;
574 
575 		slot = &(slots[object->creator_session->slotnum]);
576 
577 		(void) pthread_rwlock_wrlock(&slot->tokenobject_list_lock);
578 		INSERT_INTO_LIST(slot->tokenobject_list_head, object);
579 		(void) pthread_rwlock_unlock(&slot->tokenobject_list_lock);
580 	} else {
581 		slot_session_t *session = object->creator_session;
582 
583 		/* Add to session's list of session objects. */
584 		(void) pthread_rwlock_wrlock(&session->object_list_lock);
585 		INSERT_INTO_LIST(session->object_list_head, object);
586 		(void) pthread_rwlock_unlock(&session->object_list_lock);
587 	}
588 	object->isToken = isToken;
589 }
590 
591 
592 /*
593  * meta_slot_object_deactivate
594  *
595  * Remove the specified slot object from the appropriate object list.
596  */
597 void
598 meta_slot_object_deactivate(slot_object_t *object)
599 {
600 	slot_object_t **list_head;
601 	pthread_rwlock_t *list_lock;
602 
603 	if (object->isToken) {
604 		extern slot_data_t *slots;
605 		slot_data_t *slot;
606 
607 		slot = &(slots[object->creator_session->slotnum]);
608 
609 		list_head = &slot->tokenobject_list_head;
610 		list_lock = &slot->tokenobject_list_lock;
611 	} else {
612 		list_head = &object->creator_session->object_list_head;
613 		list_lock = &object->creator_session->object_list_lock;
614 	}
615 
616 	(void) pthread_rwlock_wrlock(list_lock);
617 	REMOVE_FROM_LIST(*list_head, object);
618 	(void) pthread_rwlock_unlock(list_lock);
619 }
620 
621 
622 /*
623  * meta_slot_object_dealloc
624  */
625 void
626 meta_slot_object_dealloc(slot_object_t *object)
627 {
628 	/* Not much cleanup for slot objects, unlike meta objects... */
629 	free(object);
630 }
631 
632 
633 /*
634  * meta_object_copyin
635  *
636  * When a key is generated/derived/unwrapped, the attribute values
637  * created by the token are not immediately read into our copy of the
638  * attributes. We defer this work until we actually need to know.
639  */
640 CK_RV
641 meta_object_copyin(meta_object_t *object)
642 {
643 	CK_RV rv = CKR_OK;
644 	slot_session_t *session = NULL;
645 	CK_ATTRIBUTE *attrs = NULL, *attrs_with_val = NULL;
646 	slot_object_t *slot_object = NULL;
647 	CK_ULONG num_attrs = 0, i, num_attrs_with_val;
648 	CK_SESSION_HANDLE hSession;
649 	CK_SLOT_ID fw_st_id;
650 
651 	/* Make sure no one else is looking at attributes. */
652 	(void) pthread_rwlock_wrlock(&object->attribute_lock);
653 
654 	/* Did we just lose a copyin race with another thread */
655 	if (object->attributes != NULL) {
656 		goto finish;
657 	}
658 
659 	slot_object = object->clones[object->master_clone_slotnum];
660 
661 	rv = meta_get_slot_session(object->master_clone_slotnum, &session,
662 	    object->creator_session->session_flags);
663 	if (rv != CKR_OK) {
664 		goto finish;
665 	}
666 
667 	/*
668 	 * first, get the master template of all the attributes
669 	 * for this object
670 	 */
671 	rv = get_master_attributes_by_object(session, slot_object,
672 	    &(object->attributes), &(object->num_attributes));
673 	if (rv != CKR_OK) {
674 		goto finish;
675 	}
676 
677 	/*
678 	 * Get value for each attribute items.
679 	 *
680 	 * Some attributes are required by the given object type.
681 	 * Some are optional.  Get all the values first, and then
682 	 * make sure we have value for all required values,
683 	 */
684 	attrs = calloc(object->num_attributes, sizeof (CK_ATTRIBUTE));
685 	if (attrs == NULL) {
686 		rv = CKR_HOST_MEMORY;
687 		goto finish;
688 	}
689 
690 
691 	for (i = 0; i < object->num_attributes; i++) {
692 		attrs[i].type =
693 		    ((object->attributes[i]).attribute).type;
694 	}
695 	num_attrs = object->num_attributes;
696 
697 	hSession = session->hSession;
698 	fw_st_id = session->fw_st_id;
699 
700 	/* first, call C_GetAttributeValue() to get size for each attribute */
701 	rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession,
702 	    slot_object->hObject, attrs, num_attrs);
703 	/*
704 	 * If the return value is not CKR_OK, allow it to be
705 	 * CKR_ATTRIBUTE_TYPE_INVALID for now.
706 	 * Some attributes defined in PKCS#11 version 2.11
707 	 * might not be defined in earlier versions.  We will
708 	 * TRY to work with those providers if the attribute
709 	 * is optional.
710 	 */
711 	if ((rv != CKR_OK) && (rv != CKR_ATTRIBUTE_TYPE_INVALID)) {
712 		rv = CKR_FUNCTION_FAILED; /* make sure rv is appropriate */
713 		goto finish;
714 	}
715 
716 	/*
717 	 * allocate space.
718 	 * Since we don't know how many attributes have
719 	 * values at this time, just assume all of them
720 	 * have values so we save one loop to count the number
721 	 * of attributes that have value.
722 	 */
723 	attrs_with_val = calloc(num_attrs, sizeof (CK_ATTRIBUTE));
724 	if (attrs_with_val == NULL) {
725 		rv = CKR_HOST_MEMORY;
726 		goto finish;
727 	}
728 
729 
730 	num_attrs_with_val = 0;
731 	for (i = 0; i < num_attrs; i++) {
732 		if (!(((CK_LONG)(attrs[i].ulValueLen)) > 0)) {
733 			/* if it isn't an optional attr, len should be > 0 */
734 			if (!object->attributes[i].canBeEmptyValue) {
735 				rv = CKR_FUNCTION_FAILED;
736 				goto finish;
737 			}
738 		} else {
739 			attrs_with_val[num_attrs_with_val].type = attrs[i].type;
740 			attrs_with_val[num_attrs_with_val].ulValueLen =
741 			    attrs[i].ulValueLen;
742 			attrs_with_val[num_attrs_with_val].pValue =
743 			    malloc(attrs[i].ulValueLen);
744 			if (attrs_with_val[num_attrs_with_val].pValue == NULL) {
745 				rv = CKR_HOST_MEMORY;
746 				goto finish;
747 			}
748 			num_attrs_with_val++;
749 		}
750 	}
751 
752 	rv = FUNCLIST(fw_st_id)->C_GetAttributeValue(hSession,
753 	    slot_object->hObject, attrs_with_val, num_attrs_with_val);
754 	if (rv != CKR_OK) {
755 		goto finish;
756 	}
757 
758 	/* store these values into the meta object */
759 	for (i = 0; i < num_attrs_with_val; i++) {
760 		rv = attribute_set_value(&(attrs_with_val[i]),
761 		    object->attributes, object->num_attributes);
762 		if (rv != CKR_OK) {
763 			goto finish;
764 		}
765 	}
766 
767 finish:
768 	(void) pthread_rwlock_unlock(&object->attribute_lock);
769 
770 	if (session)
771 		meta_release_slot_session(session);
772 
773 	if (attrs) {
774 		for (i = 0; i < num_attrs; i++) {
775 			if (attrs[i].pValue != NULL) {
776 				free(attrs[i].pValue);
777 			}
778 		}
779 		free(attrs);
780 	}
781 
782 	if (attrs_with_val) {
783 		for (i = 0; i < num_attrs; i++) {
784 			if (attrs_with_val[i].pValue != NULL) {
785 				free(attrs_with_val[i].pValue);
786 			}
787 		}
788 		free(attrs_with_val);
789 	}
790 	return (rv);
791 }
792 
793 /*
794  * Create an object to be used for wrapping and unwrapping.
795  * The same template will be used for all wrapping/unwrapping keys all
796  * the time
797  */
798 
799 static CK_RV
800 create_wrap_unwrap_key(slot_session_t *slot_session, CK_OBJECT_HANDLE *hObject,
801     wrap_info_t *wrap_info, char *key_data, CK_ULONG key_len)
802 {
803 
804 	CK_OBJECT_CLASS objclass;
805 	CK_KEY_TYPE keytype;
806 	CK_RV rv = CKR_OK;
807 	int i;
808 	CK_ATTRIBUTE template[WRAP_KEY_TEMPLATE_SIZE];
809 
810 	i = 0;
811 	objclass = wrap_info->class;
812 	template[i].type = CKA_CLASS;
813 	template[i].pValue = &objclass;
814 	template[i].ulValueLen = sizeof (objclass);
815 
816 	i++;
817 	keytype = wrap_info->key_type;
818 	template[i].type = CKA_KEY_TYPE;
819 	template[i].pValue = &keytype;
820 	template[i].ulValueLen = sizeof (keytype);
821 
822 	i++;
823 	template[i].type = CKA_TOKEN;
824 	template[i].pValue = &falsevalue;
825 	template[i].ulValueLen = sizeof (falsevalue);
826 
827 
828 	if (objclass == CKO_SECRET_KEY) {
829 		i++;
830 		template[i].type = CKA_VALUE;
831 		template[i].pValue = key_data;
832 		template[i].ulValueLen = key_len;
833 
834 		i++;
835 		template[i].type = CKA_WRAP;
836 		template[i].pValue = &truevalue;
837 		template[i].ulValueLen = sizeof (truevalue);
838 
839 		i++;
840 		template[i].type = CKA_UNWRAP;
841 		template[i].pValue = &truevalue;
842 		template[i].ulValueLen = sizeof (truevalue);
843 	} else {
844 		/* Modulus is the same for rsa public and private key */
845 		i++;
846 		template[i].type = CKA_MODULUS;
847 		template[i].pValue = Modulus;
848 		template[i].ulValueLen = sizeof (Modulus);
849 
850 		if (objclass == CKO_PUBLIC_KEY) {
851 			/* RSA public key */
852 			i++;
853 			template[i].type = CKA_PUBLIC_EXPONENT;
854 			template[i].pValue = PubExpo;
855 			template[i].ulValueLen = sizeof (PubExpo);
856 
857 			i++;
858 			template[i].type = CKA_WRAP;
859 			template[i].pValue = &truevalue;
860 			template[i].ulValueLen = sizeof (truevalue);
861 		} else {
862 			/* RSA private key */
863 			i++;
864 			template[i].type = CKA_PRIVATE_EXPONENT;
865 			template[i].pValue = PriExpo;
866 			template[i].ulValueLen = sizeof (PriExpo);
867 
868 			i++;
869 			template[i].type = CKA_UNWRAP;
870 			template[i].pValue = &truevalue;
871 			template[i].ulValueLen = sizeof (truevalue);
872 		}
873 	}
874 
875 	rv = FUNCLIST(slot_session->fw_st_id)->C_CreateObject(
876 	    slot_session->hSession, template, i + 1, hObject);
877 
878 	return (rv);
879 }
880 
881 
882 /*
883  * Create a clone of a non-sensitive and extractable object.
884  * If the template required for creating the clone doesn't exist,
885  * it will be retrieved from the master clone.
886  */
887 static CK_RV
888 clone_by_create(meta_object_t *object, slot_object_t *new_clone,
889     slot_session_t *dst_slot_session)
890 {
891 
892 	CK_RV rv;
893 
894 	if (object->attributes == NULL) {
895 		rv = meta_object_copyin(object);
896 		if (rv != CKR_OK) {
897 			return (rv);
898 		}
899 	}
900 
901 	if (object->clone_template == NULL) {
902 		rv = meta_clone_template_setup(object, object->attributes,
903 		    object->num_attributes);
904 		if (rv != CKR_OK) {
905 			return (rv);
906 		}
907 	}
908 
909 	/* Create the clone... */
910 	rv = FUNCLIST(dst_slot_session->fw_st_id)->C_CreateObject(
911 	    dst_slot_session->hSession, object->clone_template,
912 	    object->clone_template_size, &(new_clone->hObject));
913 	if (rv != CKR_OK) {
914 		return (rv);
915 	}
916 
917 	return (CKR_OK);
918 }
919 
920 /*
921  * Goes through the list of wraping mechanisms, and returns the first
922  * one that is supported by both the source and the destination slot.
923  * If none of the mechanisms are supported by both slot, return the
924  * first mechanism that's supported by the source slot
925  */
926 static CK_RV
927 find_best_match_wrap_mech(wrap_info_t *wrap_info, int num_info,
928 	CK_ULONG src_slotnum, CK_ULONG dst_slotnum, int *first_both_mech,
929 	int *first_src_mech)
930 {
931 
932 	int i;
933 	boolean_t src_supports, dst_supports;
934 	CK_RV rv;
935 
936 	for (i = 0; i < num_info; i++) {
937 		src_supports = B_FALSE;
938 		dst_supports = B_FALSE;
939 
940 		rv = meta_mechManager_slot_supports_mech(
941 		    (wrap_info[i]).mech_type, src_slotnum,
942 		    &src_supports, NULL, B_FALSE);
943 		if (rv != CKR_OK) {
944 			return (rv);
945 		}
946 
947 		rv = meta_mechManager_slot_supports_mech(
948 		    (wrap_info[i]).mech_type, dst_slotnum,
949 		    &dst_supports, NULL, B_FALSE);
950 		if (rv != CKR_OK) {
951 			return (rv);
952 		}
953 
954 		/* both source and destination supports the mech */
955 		if ((src_supports) && (dst_supports)) {
956 			*first_both_mech = i;
957 			return (CKR_OK);
958 		}
959 
960 		if ((src_supports) && (*first_src_mech == -1)) {
961 			*first_src_mech = i;
962 		}
963 	}
964 	return (CKR_OK);
965 }
966 
967 /*
968  * Determine the wrapping/unwrapping mechanism to be used
969  *
970  * If possible, select a mechanism that's supported by both source
971  * and destination slot.  If none of the mechanisms are supported
972  * by both slot, then, select the first one supported by
973  * the source slot.
974  */
975 
976 static CK_RV
977 get_wrap_mechanism(CK_OBJECT_CLASS obj_class, CK_KEY_TYPE key_type,
978     CK_ULONG src_slotnum, CK_ULONG dst_slotnum, wrap_info_t *wrap_info)
979 {
980 	wrap_info_t *wrap_info_to_search = NULL;
981 	unsigned int num_wrap_info;
982 	CK_RV rv;
983 	int i;
984 	boolean_t src_supports = B_FALSE, dst_supports = B_FALSE;
985 	int first_src_mech, rsa_first_src_mech, first_both_mech;
986 
987 	if ((obj_class == CKO_PRIVATE_KEY) && (key_type == CKK_KEA)) {
988 		/*
989 		 * only SKIPJACK keys can be used for wrapping
990 		 * KEA private keys
991 		 */
992 
993 		for (i = 0; i < num_special_wrap_info; i++) {
994 			if ((special_wrap_info[i]).mech_type
995 			    != CKM_SKIPJACK_WRAP) {
996 				continue;
997 			}
998 
999 			src_supports = B_FALSE;
1000 			dst_supports = B_FALSE;
1001 
1002 			rv = meta_mechManager_slot_supports_mech(
1003 			    (special_wrap_info[i]).mech_type, src_slotnum,
1004 			    &src_supports, NULL, B_FALSE);
1005 			if (rv != CKR_OK) {
1006 				goto finish;
1007 			}
1008 
1009 			rv = meta_mechManager_slot_supports_mech(
1010 			    (special_wrap_info[i]).mech_type, dst_slotnum,
1011 			    &dst_supports, NULL, B_FALSE);
1012 			if (rv != CKR_OK) {
1013 				goto finish;
1014 			}
1015 
1016 			if (src_supports) {
1017 				/*
1018 				 * both src and dst supports the mech or
1019 				 * only the src supports the mech
1020 				 */
1021 				(void) memcpy(wrap_info,
1022 				    &(special_wrap_info[i]),
1023 				    sizeof (wrap_info_t));
1024 
1025 				wrap_info->src_supports = src_supports;
1026 				wrap_info->dst_supports = dst_supports;
1027 				rv = CKR_OK;
1028 				goto finish;
1029 			}
1030 
1031 		}
1032 
1033 		/*
1034 		 * if we are here, that means neither the source slot
1035 		 * nor the destination slots suppports CKM_SKIPJACK_WRAP
1036 		 */
1037 		rv = CKR_FUNCTION_FAILED;
1038 		goto finish;
1039 	}
1040 
1041 	if ((key_type == CKK_SKIPJACK) || (key_type == CKK_BATON) ||
1042 	    (key_type == CKK_JUNIPER)) {
1043 		/* special key types */
1044 		wrap_info_to_search = special_wrap_info;
1045 		num_wrap_info = num_special_wrap_info;
1046 	} else {
1047 		/* use the regular wrapping mechanisms */
1048 		wrap_info_to_search = common_wrap_info;
1049 		num_wrap_info = num_common_wrap_info;
1050 	}
1051 
1052 	first_both_mech = -1;
1053 	first_src_mech = -1;
1054 
1055 	rv = find_best_match_wrap_mech(wrap_info_to_search, num_wrap_info,
1056 	    src_slotnum, dst_slotnum, &first_both_mech, &first_src_mech);
1057 	if (rv != CKR_OK) {
1058 		goto finish;
1059 	}
1060 
1061 	if (first_both_mech != -1) {
1062 		(void) memcpy(wrap_info,
1063 		    &(wrap_info_to_search[first_both_mech]),
1064 		    sizeof (wrap_info_t));
1065 
1066 		wrap_info->src_supports = B_TRUE;
1067 		wrap_info->dst_supports = B_TRUE;
1068 		rv = CKR_OK;
1069 		goto finish;
1070 	}
1071 
1072 	/*
1073 	 * If we are here, we did not find a mechanism that's supported
1074 	 * by both source and destination slot.
1075 	 *
1076 	 * If it is a secret key, can also try to wrap it with
1077 	 * a RSA public key
1078 	 */
1079 	if (obj_class == CKO_SECRET_KEY) {
1080 		first_both_mech = -1;
1081 		rsa_first_src_mech = -1;
1082 
1083 		rv = find_best_match_wrap_mech(rsa_wrap_info,
1084 		    num_rsa_wrap_info, src_slotnum, dst_slotnum,
1085 		    &first_both_mech, &rsa_first_src_mech);
1086 
1087 		if (rv != CKR_OK) {
1088 			goto finish;
1089 		}
1090 
1091 		if (first_both_mech > -1) {
1092 			(void) memcpy(wrap_info,
1093 			    &(rsa_wrap_info[first_both_mech]),
1094 			    sizeof (wrap_info_t));
1095 
1096 			wrap_info->src_supports = B_TRUE;
1097 			wrap_info->dst_supports = B_TRUE;
1098 			rv = CKR_OK;
1099 			goto finish;
1100 		}
1101 	}
1102 
1103 	/*
1104 	 * if we are here, that means none of the mechanisms are supported
1105 	 * by both the source and the destination
1106 	 */
1107 	if (first_src_mech > -1) {
1108 		/* source slot support one of the secret key mechs */
1109 		(void) memcpy(wrap_info,
1110 		    &(wrap_info_to_search[first_src_mech]),
1111 		    sizeof (wrap_info_t));
1112 		wrap_info->src_supports = B_TRUE;
1113 		wrap_info->dst_supports = B_FALSE;
1114 		rv = CKR_OK;
1115 	} else if (rsa_first_src_mech > -1) {
1116 		/* source slot support one of the RSA mechs */
1117 		(void) memcpy(wrap_info, &(rsa_wrap_info[rsa_first_src_mech]),
1118 		    sizeof (wrap_info_t));
1119 
1120 		wrap_info->src_supports = B_TRUE;
1121 		wrap_info->dst_supports = B_FALSE;
1122 		rv = CKR_OK;
1123 	} else {
1124 		/* neither source nor destination support any wrap mechs */
1125 		rv = CKR_FUNCTION_FAILED;
1126 	}
1127 
1128 finish:
1129 	return (rv);
1130 }
1131 
1132 
1133 /*
1134  * This is called if the object to be cloned is a sensitive object
1135  */
1136 static CK_RV
1137 clone_by_wrap(meta_object_t *object, slot_object_t *new_clone,
1138     slot_session_t *dst_slot_session)
1139 {
1140 	slot_session_t *src_slot_session = NULL;
1141 	CK_OBJECT_HANDLE wrappingKey = NULL, unwrappingKey = NULL;
1142 	CK_MECHANISM wrappingMech;
1143 	CK_BYTE *wrappedKey = NULL;
1144 	CK_ULONG wrappedKeyLen = 0;
1145 	slot_object_t *slot_object = NULL;
1146 	CK_RV rv = CKR_OK;
1147 	CK_OBJECT_HANDLE unwrapped_obj;
1148 	meta_object_t *tmp_meta_obj = NULL;
1149 	slot_object_t *tmp_slot_obj = NULL;
1150 	CK_OBJECT_CLASS obj_class;
1151 	CK_KEY_TYPE key_type;
1152 	meta_session_t *tmp_meta_session = NULL;
1153 	CK_ATTRIBUTE unwrap_template[4];
1154 	char key_data[1024]; /* should be big enough for any key size */
1155 	char ivbuf[1024]; /* should be big enough for any mech */
1156 	wrap_info_t wrap_info;
1157 	CK_ULONG key_len, unwrap_template_size;
1158 
1159 	slot_object = object->clones[object->master_clone_slotnum];
1160 
1161 	rv = meta_get_slot_session(object->master_clone_slotnum,
1162 	    &src_slot_session, object->creator_session->session_flags);
1163 	if (rv != CKR_OK) {
1164 		return (rv);
1165 	}
1166 
1167 	/*
1168 	 * get the object class and key type for unwrap template
1169 	 * This information will also be used for determining
1170 	 * which wrap mechanism and which key to use for
1171 	 * doing the wrapping
1172 	 */
1173 	unwrap_template[0].type = CKA_CLASS;
1174 	unwrap_template[0].pValue = &obj_class;
1175 	unwrap_template[0].ulValueLen = sizeof (obj_class);
1176 
1177 	unwrap_template[1].type = CKA_KEY_TYPE;
1178 	unwrap_template[1].pValue = &key_type;
1179 	unwrap_template[1].ulValueLen = sizeof (key_type);
1180 
1181 	rv = FUNCLIST(src_slot_session->fw_st_id)->C_GetAttributeValue(
1182 	    src_slot_session->hSession, slot_object->hObject,
1183 	    unwrap_template, 2);
1184 	if (rv != CKR_OK) {
1185 		goto finish;
1186 	}
1187 
1188 	rv = get_wrap_mechanism(obj_class, key_type, src_slot_session->slotnum,
1189 	    dst_slot_session->slotnum, &wrap_info);
1190 	if (rv != CKR_OK) {
1191 		goto finish;
1192 	}
1193 
1194 	/*
1195 	 * open the random device and read number of bytes required for
1196 	 * creating a secret key for wrapping and unwrapping
1197 	 */
1198 	if (wrap_info.class == CKO_SECRET_KEY) {
1199 
1200 		/*
1201 		 * /dev/urandom will be used for generating the key used
1202 		 * for doing the wrap/unwrap.  It's should be ok to
1203 		 * use /dev/urandom because this key is used for this
1204 		 * one time operation only.  It doesn't need to be stored.
1205 		 */
1206 		int fd;
1207 
1208 		while ((fd = open(RANDOM_DEVICE, O_RDONLY)) < 0) {
1209 			if (errno != EINTR)
1210 				break;
1211 		}
1212 		if (fd == -1) {
1213 			rv = CKR_FUNCTION_FAILED;
1214 			goto finish;
1215 		}
1216 		key_len = wrap_info.key_length;
1217 
1218 		if (looping_read(fd, key_data, key_len) != key_len) {
1219 			rv = CKR_FUNCTION_FAILED;
1220 			goto finish;
1221 		}
1222 
1223 		if (wrap_info.iv_length > 0) {
1224 			if (looping_read(fd, ivbuf, wrap_info.iv_length)
1225 			    != wrap_info.iv_length) {
1226 				rv = CKR_FUNCTION_FAILED;
1227 				goto finish;
1228 			}
1229 		}
1230 
1231 		(void) close(fd);
1232 	}
1233 
1234 	/* create the wrapping key */
1235 	rv = create_wrap_unwrap_key(src_slot_session, &wrappingKey,
1236 	    &wrap_info, key_data, key_len);
1237 	if (rv != CKR_OK) {
1238 		goto finish;
1239 	}
1240 
1241 	wrappingMech.mechanism = wrap_info.mech_type;
1242 	wrappingMech.pParameter = ((wrap_info.iv_length > 0) ? ivbuf : NULL);
1243 	wrappingMech.ulParameterLen = wrap_info.iv_length;
1244 
1245 	/* get the size of the wrapped key */
1246 	rv = FUNCLIST(src_slot_session->fw_st_id)->C_WrapKey(
1247 	    src_slot_session->hSession, &wrappingMech,
1248 	    wrappingKey, slot_object->hObject, NULL, &wrappedKeyLen);
1249 
1250 	if (rv != CKR_OK) {
1251 		goto finish;
1252 	}
1253 
1254 	wrappedKey = malloc(wrappedKeyLen * sizeof (CK_BYTE));
1255 	if (wrappedKey == NULL) {
1256 		rv = CKR_HOST_MEMORY;
1257 		goto finish;
1258 	}
1259 
1260 	/* do the actual key wrapping */
1261 	rv = FUNCLIST(src_slot_session->fw_st_id)->C_WrapKey(
1262 	    src_slot_session->hSession, &wrappingMech,
1263 	    wrappingKey, slot_object->hObject, wrappedKey, &wrappedKeyLen);
1264 
1265 	if (rv != CKR_OK) {
1266 		goto finish;
1267 	}
1268 
1269 	/* explicitly force the unwrapped object to be not sensitive */
1270 	unwrap_template[2].type = CKA_SENSITIVE;
1271 	unwrap_template[2].pValue = &falsevalue;
1272 	unwrap_template[2].ulValueLen = sizeof (falsevalue);
1273 
1274 	unwrap_template[3].type = CKA_TOKEN;
1275 	unwrap_template[3].pValue = &falsevalue;
1276 	unwrap_template[3].ulValueLen = sizeof (falsevalue);
1277 
1278 	unwrap_template_size =
1279 	    sizeof (unwrap_template) / sizeof (CK_ATTRIBUTE);
1280 
1281 	if (!wrap_info.dst_supports) {
1282 		/*
1283 		 * if we know for sure that the destination slot doesn't
1284 		 * support the wrapping mechanism, no point in trying.
1285 		 * go directly to unwrap in source slot, and create key
1286 		 * in destination
1287 		 */
1288 		goto unwrap_in_source;
1289 	}
1290 
1291 	/* create the unwrapping key in destination slot */
1292 	if (wrap_info.key_type == CKK_RSA) {
1293 		/* for RSA key, the unwrapping key need to be private key */
1294 		wrap_info.class = CKO_PRIVATE_KEY;
1295 	}
1296 	rv = create_wrap_unwrap_key(dst_slot_session,
1297 	    &unwrappingKey, &wrap_info, key_data, key_len);
1298 	if (rv != CKR_OK) {
1299 		goto finish;
1300 	}
1301 
1302 	rv = FUNCLIST(dst_slot_session->fw_st_id)->C_UnwrapKey(
1303 	    dst_slot_session->hSession, &wrappingMech,
1304 	    unwrappingKey, wrappedKey, wrappedKeyLen, unwrap_template,
1305 	    unwrap_template_size, &(new_clone->hObject));
1306 
1307 	if (rv != CKR_OK) {
1308 unwrap_in_source:
1309 
1310 		/*
1311 		 * There seemed to be a problem with unwrapping in the
1312 		 * destination slot.
1313 		 * Try to do the unwrap in the src slot so it becomes
1314 		 * a non-sensitive object, then, get all the attributes
1315 		 * and create the object in the destination slot
1316 		 */
1317 
1318 
1319 		if (wrap_info.class == CKO_SECRET_KEY) {
1320 			/* unwrap with same key used for wrapping */
1321 			rv = FUNCLIST(src_slot_session->fw_st_id)->C_UnwrapKey(
1322 			    src_slot_session->hSession,
1323 			    &wrappingMech, wrappingKey, wrappedKey,
1324 			    wrappedKeyLen, unwrap_template,
1325 			    unwrap_template_size, &(unwrapped_obj));
1326 		} else {
1327 			/*
1328 			 * If the object is wrapping with RSA public key, need
1329 			 * need to create RSA private key for unwrapping
1330 			 */
1331 			wrap_info.class = CKO_PRIVATE_KEY;
1332 			rv = create_wrap_unwrap_key(src_slot_session,
1333 			    &unwrappingKey, &wrap_info, key_data, key_len);
1334 			if (rv != CKR_OK) {
1335 				goto finish;
1336 			}
1337 			rv = FUNCLIST(src_slot_session->fw_st_id)->C_UnwrapKey(
1338 			    src_slot_session->hSession,
1339 			    &wrappingMech, unwrappingKey, wrappedKey,
1340 			    wrappedKeyLen, unwrap_template,
1341 			    unwrap_template_size, &(unwrapped_obj));
1342 		}
1343 
1344 
1345 		if (rv != CKR_OK) {
1346 			goto finish;
1347 		}
1348 
1349 		rv = meta_session_alloc(&tmp_meta_session);
1350 		if (rv != CKR_OK) {
1351 			goto finish;
1352 		}
1353 
1354 		tmp_meta_session->session_flags = CKF_SERIAL_SESSION;
1355 
1356 		rv = meta_object_alloc(tmp_meta_session, &tmp_meta_obj);
1357 		if (rv != CKR_OK) {
1358 			goto finish;
1359 		}
1360 
1361 		rv = meta_slot_object_alloc(&tmp_slot_obj);
1362 		if (rv != CKR_OK) {
1363 			goto finish;
1364 		}
1365 
1366 		tmp_meta_obj->master_clone_slotnum = src_slot_session->slotnum;
1367 		tmp_slot_obj->hObject = unwrapped_obj;
1368 		tmp_meta_obj->clones[tmp_meta_obj->master_clone_slotnum]
1369 		    = tmp_slot_obj;
1370 		meta_slot_object_activate(tmp_slot_obj, src_slot_session,
1371 		    B_FALSE);
1372 		tmp_slot_obj = NULL;
1373 
1374 		rv = clone_by_create(tmp_meta_obj, new_clone,
1375 		    dst_slot_session);
1376 		if (rv != CKR_OK) {
1377 			goto finish;
1378 		}
1379 	}
1380 
1381 finish:
1382 	if (unwrappingKey) {
1383 		(void) FUNCLIST(dst_slot_session->fw_st_id)->C_DestroyObject(
1384 		    dst_slot_session->hSession, unwrappingKey);
1385 	}
1386 
1387 	if (wrappingKey) {
1388 		(void) FUNCLIST(src_slot_session->fw_st_id)->C_DestroyObject(
1389 		    src_slot_session->hSession, wrappingKey);
1390 	}
1391 
1392 	if (tmp_slot_obj) {
1393 		(void) meta_slot_object_dealloc(tmp_slot_obj);
1394 	}
1395 
1396 	if (tmp_meta_obj) {
1397 		(void) meta_object_dealloc(tmp_meta_obj, B_TRUE);
1398 	}
1399 
1400 	if (tmp_meta_session) {
1401 		(void) meta_session_dealloc(tmp_meta_session);
1402 	}
1403 
1404 	if (wrappedKey) {
1405 		free(wrappedKey);
1406 	}
1407 
1408 	if (src_slot_session) {
1409 		meta_release_slot_session(src_slot_session);
1410 	}
1411 
1412 	return (rv);
1413 
1414 }
1415 
1416 
1417 /*
1418  * meta_object_get_clone
1419  *
1420  * Creates a "clone" of a metaobject on the specified slot. A clone is a
1421  * copy of the object.
1422  *
1423  * Clones are cached, so that they can be reused with subsquent operations.
1424  */
1425 CK_RV
1426 meta_object_get_clone(meta_object_t *object,
1427 	CK_ULONG slot_num, slot_session_t *slot_session,
1428 	slot_object_t **clone)
1429 {
1430 	CK_RV rv = CKR_OK;
1431 	slot_object_t *newclone = NULL;
1432 
1433 	/* Does a clone already exist? */
1434 	if (object->clones[slot_num] != NULL) {
1435 		*clone = object->clones[slot_num];
1436 		return (CKR_OK);
1437 	}
1438 
1439 	if ((object->isSensitive) && (object->isToken) &&
1440 	    (!metaslot_auto_key_migrate)) {
1441 		/*
1442 		 * if the object is a sensitive token object, and auto
1443 		 * key migrate is not allowed, will not create the clone
1444 		 * in another slot
1445 		 */
1446 		return (CKR_FUNCTION_FAILED);
1447 	}
1448 
1449 	/* object attributes can't be extracted and attributes are not known */
1450 	if ((!object->isExtractable) && (object->attributes == NULL)) {
1451 		return (CKR_FUNCTION_FAILED);
1452 	}
1453 
1454 	/*
1455 	 * has an attempt already been made to create this object in
1456 	 * slot?  If yes, and there's no clone, as indicated above,
1457 	 * that means this object can't be created in this slot.
1458 	 */
1459 	if (object->tried_create_clone[slot_num]) {
1460 		return (CKR_FUNCTION_FAILED);
1461 	}
1462 	(void) pthread_mutex_lock(&object->clone_create_lock);
1463 
1464 	/* Maybe someone just created one? */
1465 	if (object->clones[slot_num] != NULL) {
1466 		*clone = object->clones[slot_num];
1467 		goto finish;
1468 	}
1469 
1470 
1471 	rv = meta_slot_object_alloc(&newclone);
1472 	if (rv != CKR_OK)
1473 		goto finish;
1474 
1475 	object->tried_create_clone[slot_num] = B_TRUE;
1476 
1477 	if (object->isSensitive) {
1478 		rv = clone_by_wrap(object, newclone, slot_session);
1479 	} else {
1480 		rv = clone_by_create(object, newclone, slot_session);
1481 	}
1482 
1483 	if (rv != CKR_OK) {
1484 		goto finish;
1485 	}
1486 
1487 	object->clones[slot_num] = newclone;
1488 	meta_slot_object_activate(newclone, slot_session, object->isToken);
1489 
1490 	*clone = newclone;
1491 	newclone = NULL;
1492 finish:
1493 	(void) pthread_mutex_unlock(&object->clone_create_lock);
1494 
1495 	if (newclone)
1496 		meta_slot_object_dealloc(newclone);
1497 
1498 	return (rv);
1499 }
1500 
1501 
1502 /*
1503  * meta_setup_clone_template
1504  *
1505  * Create a clone template for the specified object.
1506  */
1507 static CK_RV
1508 meta_clone_template_setup(meta_object_t *object,
1509     const generic_attr_t *attributes, size_t num_attributes)
1510 {
1511 	CK_RV rv = CKR_OK;
1512 	CK_ATTRIBUTE *clone_template;
1513 	size_t i, c = 0;
1514 
1515 	clone_template = malloc(num_attributes * sizeof (CK_ATTRIBUTE));
1516 	if (clone_template == NULL) {
1517 		rv = CKR_HOST_MEMORY;
1518 		goto finish;
1519 	}
1520 
1521 	/* Don't allow attributes to change while we look at them. */
1522 	(void) pthread_rwlock_rdlock(&object->attribute_lock);
1523 
1524 	for (i = 0; i < num_attributes; i++) {
1525 		if (!attributes[i].isCloneAttr) {
1526 			continue;
1527 		}
1528 		if ((!(attributes[i].hasValueForClone)) &&
1529 		    (attributes[i].canBeEmptyValue)) {
1530 			continue;
1531 		}
1532 
1533 		clone_template[c].type = attributes[i].attribute.type;
1534 		clone_template[c].ulValueLen =
1535 				attributes[i].attribute.ulValueLen;
1536 		/* Allocate space to store the attribute value. */
1537 		clone_template[c].pValue = malloc(clone_template[c].ulValueLen);
1538 		if (clone_template[c].pValue == NULL) {
1539 			rv = CKR_HOST_MEMORY;
1540 			(void) pthread_rwlock_unlock(&object->attribute_lock);
1541 			goto finish;
1542 		}
1543 
1544 		(void) memcpy(clone_template[c].pValue,
1545 		    object->attributes[i].attribute.pValue,
1546 		    clone_template[c].ulValueLen);
1547 		c++;
1548 	}
1549 
1550 	(void) pthread_rwlock_unlock(&object->attribute_lock);
1551 
1552 	object->clone_template = clone_template;
1553 	object->clone_template_size = c;
1554 
1555 finish:
1556 	return (rv);
1557 }
1558 
1559 
1560 /*
1561  * meta_object_find_by_handle
1562  *
1563  * Search for an existing metaobject, using the object handle of a clone
1564  * on a particular slot.
1565  *
1566  * Returns a matching metaobject, or NULL if no match was found.
1567  */
1568 meta_object_t *
1569 meta_object_find_by_handle(CK_OBJECT_HANDLE hObject, CK_ULONG slotnum,
1570     boolean_t token_only)
1571 {
1572 	meta_object_t *object = NULL, *tmp_obj;
1573 	meta_session_t *session;
1574 
1575 	if (!token_only) {
1576 		(void) pthread_rwlock_rdlock(&meta_sessionlist_lock);
1577 		session = meta_sessionlist_head;
1578 		while (session != NULL) {
1579 			/* lock the objects list while we look at it */
1580 			(void) pthread_rwlock_rdlock(
1581 			    &(session->object_list_lock));
1582 			tmp_obj = session->object_list_head;
1583 			while (tmp_obj != NULL) {
1584 				slot_object_t *slot_object;
1585 
1586 				(void) pthread_rwlock_rdlock(
1587 				    &(tmp_obj->object_lock));
1588 				slot_object = tmp_obj->clones[slotnum];
1589 				if (slot_object != NULL) {
1590 					if (slot_object->hObject == hObject) {
1591 						object = tmp_obj;
1592 					}
1593 				}
1594 				(void) pthread_rwlock_unlock(
1595 				    &(tmp_obj->object_lock));
1596 				if (object != NULL) {
1597 					break;
1598 				}
1599 				tmp_obj = tmp_obj->next;
1600 			}
1601 			(void) pthread_rwlock_unlock(
1602 			    &(session->object_list_lock));
1603 			if (object != NULL) {
1604 				break;
1605 			}
1606 			session = session->next;
1607 		}
1608 		(void) pthread_rwlock_unlock(&meta_sessionlist_lock);
1609 	}
1610 
1611 	if (object != NULL) {
1612 		/* found the object, no need to look further */
1613 		return (object);
1614 	}
1615 
1616 	/*
1617 	 * Look at list of token objects
1618 	 */
1619 	(void) pthread_rwlock_rdlock(&tokenobject_list_lock);
1620 	tmp_obj = tokenobject_list_head;
1621 
1622 	while (tmp_obj != NULL) {
1623 		slot_object_t *slot_object;
1624 
1625 		(void) pthread_rwlock_rdlock(&(tmp_obj->object_lock));
1626 		slot_object = tmp_obj->clones[slotnum];
1627 		if (slot_object != NULL) {
1628 			if (slot_object->hObject == hObject)
1629 				object = tmp_obj;
1630 		}
1631 		(void) pthread_rwlock_unlock(&(tmp_obj->object_lock));
1632 		if (object != NULL) {
1633 			break;
1634 		}
1635 		tmp_obj = tmp_obj->next;
1636 	}
1637 	(void) pthread_rwlock_unlock(&tokenobject_list_lock);
1638 
1639 	return (object);
1640 }
1641 
1642 CK_RV
1643 meta_token_object_deactivate(token_obj_type_t token_type)
1644 {
1645 	meta_object_t *object, *tmp_object;
1646 	CK_RV save_rv = CKR_OK, rv;
1647 
1648 	/* get a write lock on the token object list */
1649 	(void) pthread_rwlock_wrlock(&tokenobject_list_lock);
1650 
1651 	object = tokenobject_list_head;
1652 
1653 	/* go through each object and delete the one with matching type */
1654 	while (object != NULL) {
1655 		tmp_object = object->next;
1656 
1657 		if ((token_type == ALL_TOKEN) ||
1658 		    ((object->isPrivate) && (token_type == PRIVATE_TOKEN)) ||
1659 		    ((!object->isPrivate) && (token_type == PUBLIC_TOKEN))) {
1660 			rv = meta_object_deactivate(object, B_TRUE, B_FALSE);
1661 			if ((rv != CKR_OK) && (save_rv == CKR_OK)) {
1662 				save_rv = rv;
1663 				goto finish;
1664 			}
1665 			rv = meta_object_dealloc(object, B_FALSE);
1666 			if ((rv != CKR_OK) && (save_rv == CKR_OK)) {
1667 				save_rv = rv;
1668 				goto finish;
1669 			}
1670 		}
1671 		object = tmp_object;
1672 	}
1673 finish:
1674 	(void) pthread_rwlock_unlock(&tokenobject_list_lock);
1675 	return (save_rv);
1676 }
1677 
1678 /*
1679  * This function adds the to-be-freed meta object to a linked list.
1680  * When the number of objects queued in the linked list reaches the
1681  * maximum threshold MAX_OBJ_TO_BE_FREED, it will free the first
1682  * object (FIFO) in the list.
1683  */
1684 void
1685 meta_object_delay_free(meta_object_t *objp)
1686 {
1687 	meta_object_t *tmp;
1688 
1689 	(void) pthread_mutex_lock(&obj_delay_freed.obj_to_be_free_mutex);
1690 
1691 	/* Add the newly deleted object at the end of the list */
1692 	objp->next = NULL;
1693 	if (obj_delay_freed.first == NULL) {
1694 		obj_delay_freed.last = objp;
1695 		obj_delay_freed.first = objp;
1696 	} else {
1697 		obj_delay_freed.last->next = objp;
1698 		obj_delay_freed.last = objp;
1699 	}
1700 
1701 	if (++obj_delay_freed.count >= MAX_OBJ_TO_BE_FREED) {
1702 		/*
1703 		 * Free the first object in the list only if
1704 		 * the total count reaches maximum threshold.
1705 		 */
1706 		obj_delay_freed.count--;
1707 		tmp = obj_delay_freed.first->next;
1708 		free(obj_delay_freed.first);
1709 		obj_delay_freed.first = tmp;
1710 	}
1711 	(void) pthread_mutex_unlock(&obj_delay_freed.obj_to_be_free_mutex);
1712 }
1713