xref: /titanic_41/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelObjectUtil.c (revision 602ca9ea8f9ce0933f0944601cc5d230e91a950d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <strings.h>
31 #include <errno.h>
32 #include <security/cryptoki.h>
33 #include <cryptoutil.h>
34 #include "kernelGlobal.h"
35 #include "kernelObject.h"
36 #include "kernelSession.h"
37 #include "kernelSlot.h"
38 
39 /*
40  * Add an object to the session's object list.
41  *
42  * This function will acquire the lock on the session, and release
43  * that lock after adding the object to the session's object list.
44  */
45 void
46 kernel_add_object_to_session(kernel_object_t *objp, kernel_session_t *sp)
47 {
48 	/* Acquire the session lock. */
49 	(void) pthread_mutex_lock(&sp->session_mutex);
50 
51 	/* Insert the new object in front of session's object list. */
52 	if (sp->object_list == NULL) {
53 		sp->object_list = objp;
54 		objp->next = NULL;
55 		objp->prev = NULL;
56 	} else {
57 		sp->object_list->prev = objp;
58 		objp->next = sp->object_list;
59 		objp->prev = NULL;
60 		sp->object_list = objp;
61 	}
62 
63 	/* Release the session lock. */
64 	(void) pthread_mutex_unlock(&sp->session_mutex);
65 }
66 
67 /*
68  * Clean up and release the storage allocated to the object.
69  *
70  * The function is called either with the object lock being held
71  * (by caller kernel_delete_object()), or there is no object lock
72  * yet (by kernel_build_XXX_object() during creating an object).
73  */
74 void
75 kernel_cleanup_object(kernel_object_t *objp)
76 {
77 	/*
78 	 * Free the storage allocated to a secret key object.
79 	 */
80 	if (objp->class == CKO_SECRET_KEY) {
81 		if (OBJ_SEC(objp) != NULL && OBJ_SEC_VALUE(objp) != NULL) {
82 			bzero(OBJ_SEC_VALUE(objp), OBJ_SEC_VALUE_LEN(objp));
83 			free(OBJ_SEC_VALUE(objp));
84 			OBJ_SEC_VALUE(objp) = NULL;
85 			OBJ_SEC_VALUE_LEN(objp) = 0;
86 		}
87 		free(OBJ_SEC(objp));
88 		OBJ_SEC(objp) = NULL;
89 	} else {
90 		kernel_cleanup_object_bigint_attrs(objp);
91 	}
92 
93 	/*
94 	 * Free the storage allocated to the extra attribute list.
95 	 */
96 	kernel_cleanup_extra_attr(objp);
97 }
98 
99 /*
100  * Create a new object. Copy the attributes that can be modified
101  * (in the boolean attribute mask field and extra attribute list)
102  * from the old object to the new object.
103  *
104  * The caller of this function holds the lock on the old object.
105  */
106 CK_RV
107 kernel_copy_object(kernel_object_t *old_object, kernel_object_t **new_object,
108     boolean_t copy_everything, kernel_session_t *sp)
109 {
110 	CK_RV rv = CKR_OK;
111 	kernel_object_t *new_objp = NULL;
112 	CK_ATTRIBUTE_INFO_PTR attrp;
113 
114 	/* Allocate new object. */
115 	new_objp = calloc(1, sizeof (kernel_object_t));
116 	if (new_objp == NULL)
117 		return (CKR_HOST_MEMORY);
118 
119 	new_objp->class = old_object->class;
120 	new_objp->bool_attr_mask = old_object->bool_attr_mask;
121 
122 	attrp = old_object->extra_attrlistp;
123 	while (attrp) {
124 		/*
125 		 * Copy the attribute_info struct from the old
126 		 * object to a new attribute_info struct, and add
127 		 * that new struct to the extra attribute list
128 		 * of the new object.
129 		 */
130 		rv = kernel_copy_extra_attr(attrp, new_objp);
131 		if (rv != CKR_OK) {
132 			kernel_cleanup_extra_attr(new_objp);
133 			free(new_objp);
134 			return (rv);
135 		}
136 		attrp = attrp->next;
137 	}
138 
139 	*new_object = new_objp;
140 
141 	if (!copy_everything) {
142 		/* done with copying all information that can be modified */
143 		return (CKR_OK);
144 	}
145 
146 	/*
147 	 * Copy the rest of the object.
148 	 * Certain fields that are not appropriate for coping will be
149 	 * initialized.
150 	 */
151 	new_objp->key_type = old_object->key_type;
152 	new_objp->magic_marker = old_object->magic_marker;
153 	new_objp->mechanism = old_object->mechanism;
154 	new_objp->session_handle = (CK_SESSION_HANDLE)sp;
155 	(void) pthread_mutex_init(&(new_objp->object_mutex), NULL);
156 	/* copy key related information */
157 	switch (new_objp->class) {
158 		case CKO_PUBLIC_KEY:
159 			rv = kernel_copy_public_key_attr(OBJ_PUB(old_object),
160 			    &(OBJ_PUB(new_objp)), new_objp->key_type);
161 			break;
162 		case CKO_PRIVATE_KEY:
163 			rv = kernel_copy_private_key_attr(OBJ_PRI(old_object),
164 			    &(OBJ_PRI(new_objp)), new_objp->key_type);
165 			break;
166 		case CKO_SECRET_KEY:
167 			rv = kernel_copy_secret_key_attr(OBJ_SEC(old_object),
168 			    &(OBJ_SEC(new_objp)));
169 			break;
170 		default:
171 			/* should never be this case */
172 			break;
173 	}
174 	if (rv != CKR_OK) {
175 		/*
176 		 * don't need to cleanup the memory from failure of copying
177 		 * any key related stuff.  Each individual function for
178 		 * copying key attr will free the memory if it fails
179 		 */
180 		kernel_cleanup_extra_attr(new_objp);
181 		free(new_objp);
182 	}
183 	return (rv);
184 }
185 
186 /*
187  * Copy the attributes (in the boolean attribute mask field and
188  * extra attribute list) from the new object back to the original
189  * object. Also, clean up and release all the storage in the extra
190  * attribute list of the original object.
191  *
192  * The caller of this function holds the lock on the old object.
193  */
194 void
195 kernel_merge_object(kernel_object_t *old_object, kernel_object_t *new_object)
196 {
197 
198 	old_object->bool_attr_mask = new_object->bool_attr_mask;
199 	kernel_cleanup_extra_attr(old_object);
200 	old_object->extra_attrlistp = new_object->extra_attrlistp;
201 
202 }
203 
204 /*
205  * Create a new object struct.  If it is a session object, add the object to
206  * the session's object list.  If it is a token object, add it to the slot's
207  * token object list.  The caller does not hold the slot lock.
208  */
209 CK_RV
210 kernel_add_object(CK_ATTRIBUTE_PTR pTemplate,  CK_ULONG ulCount,
211 	CK_ULONG *objecthandle_p, kernel_session_t *sp)
212 {
213 	CK_RV rv = CKR_OK;
214 	kernel_object_t *new_objp = NULL;
215 	kernel_slot_t	*pslot;
216 	crypto_object_create_t	objc;
217 	CK_BBOOL is_pri_obj;
218 	CK_BBOOL is_token_obj = B_FALSE;
219 	int r;
220 
221 	new_objp = calloc(1, sizeof (kernel_object_t));
222 	if (new_objp == NULL) {
223 		rv = CKR_HOST_MEMORY;
224 		goto fail_cleanup;
225 	}
226 
227 	new_objp->extra_attrlistp = NULL;
228 	new_objp->is_lib_obj = B_TRUE;
229 
230 	/*
231 	 * If the HW provider supports object creation, create the object
232 	 * in the HW provider by calling the CRYPTO_OBJECT_CREATE ioctl.
233 	 * Otherwise, create the object in the library.
234 	 */
235 	pslot = slot_table[sp->ses_slotid];
236 	if (pslot->sl_func_list.fl_object_create) {
237 		new_objp->is_lib_obj = B_FALSE;
238 		objc.oc_session = sp->k_session;
239 		objc.oc_count = ulCount;
240 		rv = process_object_attributes(pTemplate, ulCount,
241 		    &objc.oc_attributes, &is_token_obj);
242 		if (rv != CKR_OK) {
243 			goto fail_cleanup;
244 		}
245 
246 		/* Cannot create a token object with a READ-ONLY session */
247 		if (is_token_obj && sp->ses_RO) {
248 			free_object_attributes(objc.oc_attributes, ulCount);
249 			rv = CKR_SESSION_READ_ONLY;
250 			goto fail_cleanup;
251 		}
252 
253 		while ((r = ioctl(kernel_fd, CRYPTO_OBJECT_CREATE,
254 		    &objc)) < 0) {
255 			if (errno != EINTR)
256 				break;
257 		}
258 		if (r < 0) {
259 			rv = CKR_FUNCTION_FAILED;
260 		} else {
261 			rv = crypto2pkcs11_error_number(objc.oc_return_value);
262 		}
263 
264 		free_object_attributes(objc.oc_attributes, ulCount);
265 
266 		if (rv != CKR_OK) {
267 			goto fail_cleanup;
268 		}
269 
270 		/* Get the CKA_PRIVATE value of this object. */
271 		new_objp->k_handle = objc.oc_handle;
272 		rv = get_cka_private_value(sp, new_objp->k_handle,
273 		    &is_pri_obj);
274 		if (rv != CKR_OK) {
275 			goto fail_cleanup;
276 		}
277 
278 		/* Set the PRIVATE_BOOL_ON and TOKEN_BOOL_ON attributes */
279 		if (is_pri_obj)
280 			new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
281 		else
282 			new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
283 
284 		if (is_token_obj)
285 			new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
286 		else
287 			new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
288 
289 	} else {
290 		/*
291 		 * Create the object in the library.
292 		 * Validate attribute template and fill in the attributes
293 		 * in the kernel_object_t.
294 		 */
295 		rv = kernel_build_object(pTemplate, ulCount, new_objp, sp,
296 		    KERNEL_CREATE_OBJ);
297 		if (rv != CKR_OK) {
298 			goto fail_cleanup;
299 		}
300 	}
301 
302 	/* Initialize the rest of stuffs in kernel_object_t. */
303 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
304 	new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
305 	new_objp->session_handle = (CK_SESSION_HANDLE)sp;
306 
307 	if (is_token_obj) {
308 		/* Add the new object to the slot's token object list. */
309 		pslot = slot_table[sp->ses_slotid];
310 		kernel_add_token_object_to_slot(new_objp, pslot);
311 	} else {
312 		/* Add the new object to the session's object list. */
313 		kernel_add_object_to_session(new_objp, sp);
314 	}
315 
316 	/* Type casting the address of an object struct to an object handle. */
317 	*objecthandle_p = (CK_ULONG)new_objp;
318 
319 	return (CKR_OK);
320 
321 fail_cleanup:
322 	if (new_objp) {
323 		/*
324 		 * If the object is created in the HW provider, the storage
325 		 * allocated for the ioctl call is always cleaned up after
326 		 * the call.  If the object is created in the library,
327 		 * the storage allocated inside of this object should
328 		 * have been cleaned up in the kernel_build_object()
329 		 * after an error occurred. Therefore, we can safely
330 		 * free the object.
331 		 */
332 		free(new_objp);
333 	}
334 
335 	return (rv);
336 }
337 
338 /*
339  * Remove an object from the session's object list.
340  *
341  * The caller of this function holds the session lock.
342  */
343 CK_RV
344 kernel_remove_object_from_session(kernel_object_t *objp, kernel_session_t *sp)
345 {
346 	kernel_object_t *tmp_objp;
347 	boolean_t found = B_FALSE;
348 
349 	/*
350 	 * Remove the object from the session's object list.
351 	 */
352 	if ((sp == NULL) ||
353 	    (sp->magic_marker != KERNELTOKEN_SESSION_MAGIC)) {
354 		return (CKR_SESSION_HANDLE_INVALID);
355 	}
356 
357 	if ((sp->object_list == NULL) || (objp == NULL) ||
358 	    (objp->magic_marker != KERNELTOKEN_OBJECT_MAGIC)) {
359 		return (CKR_OBJECT_HANDLE_INVALID);
360 	}
361 
362 	tmp_objp = sp->object_list;
363 	while (tmp_objp) {
364 		if (tmp_objp == objp) {
365 			found = B_TRUE;
366 			break;
367 		}
368 		tmp_objp = tmp_objp->next;
369 	}
370 	if (!found)
371 		return (CKR_OBJECT_HANDLE_INVALID);
372 
373 	if (sp->object_list == objp) {
374 		/* Object is the first one in the list. */
375 		if (objp->next) {
376 			sp->object_list = objp->next;
377 			objp->next->prev = NULL;
378 		} else {
379 			/* Object is the only one in the list. */
380 			sp->object_list = NULL;
381 		}
382 	} else {
383 		/* Object is not the first one in the list. */
384 		if (objp->next) {
385 			/* Object is in the middle of the list. */
386 			objp->prev->next = objp->next;
387 			objp->next->prev = objp->prev;
388 		} else {
389 			/* Object is the last one in the list. */
390 			objp->prev->next = NULL;
391 		}
392 	}
393 	return (CKR_OK);
394 }
395 
396 static void
397 kernel_delete_object_cleanup(kernel_object_t *objp)
398 {
399 	/* Acquire the lock on the object. */
400 	(void) pthread_mutex_lock(&objp->object_mutex);
401 
402 	/*
403 	 * Make sure another thread hasn't freed the object.
404 	 */
405 	if (objp->magic_marker != KERNELTOKEN_OBJECT_MAGIC) {
406 		(void) pthread_mutex_unlock(&objp->object_mutex);
407 		return;
408 	}
409 
410 	/*
411 	 * The deletion of an object must be blocked when the object
412 	 * reference count is not zero. This means if any object related
413 	 * operation starts prior to the delete object operation gets in,
414 	 * the object deleting thread must wait for the non-deleting
415 	 * operation to be completed before it can proceed the delete
416 	 * operation.
417 	 */
418 	while (objp->obj_refcnt != 0) {
419 		/*
420 		 * We set the OBJECT_REFCNT_WAITING flag before we put
421 		 * this deleting thread in a wait state, so other non-deleting
422 		 * operation thread will signal to wake it up only when
423 		 * the object reference count becomes zero and this flag
424 		 * is set.
425 		 */
426 		objp->obj_delete_sync |= OBJECT_REFCNT_WAITING;
427 		(void) pthread_cond_wait(&objp->obj_free_cond,
428 			&objp->object_mutex);
429 	}
430 
431 	objp->obj_delete_sync &= ~OBJECT_REFCNT_WAITING;
432 
433 	/* Mark object as no longer valid. */
434 	objp->magic_marker = 0;
435 
436 	(void) pthread_cond_destroy(&objp->obj_free_cond);
437 }
438 
439 /*
440  * Delete a session object:
441  * - Remove the object from the session's object list.
442  * - Release the storage allocated to the object.
443  *
444  * The boolean argument ses_lock_held is used to indicate that whether
445  * the caller holds the session lock or not.
446  * - When called by kernel_delete_all_objects_in_session() or
447  *   kernel_delete_pri_objects_in_slot() -- ses_lock_held = TRUE.
448  *
449  * The boolean argument wrapper_only is used to indicate that whether
450  * the caller only wants to clean up the object wrapper from the library and
451  * needs not to make an ioctl call.
452  * - This argument only applies to the object created in the provider level.
453  * - When called by kernel_cleanup_pri_objects_in_slot(), wrapper_only is TRUE.
454  * - When called by C_DestroyObject(), wrapper_only is FALSE.
455  * - When called by kernel_delete_all_objects_in_session(), the value of
456  *   wrapper_only depends on its caller.
457  */
458 CK_RV
459 kernel_delete_session_object(kernel_session_t *sp, kernel_object_t *objp,
460     boolean_t ses_lock_held, boolean_t wrapper_only)
461 {
462 	CK_RV rv = CKR_OK;
463 	crypto_object_destroy_t	obj_destroy;
464 
465 	/*
466 	 * Check to see if the caller holds the lock on the session.
467 	 * If not, we need to acquire that lock in order to proceed.
468 	 */
469 	if (!ses_lock_held) {
470 		/* Acquire the session lock. */
471 		(void) pthread_mutex_lock(&sp->session_mutex);
472 	}
473 
474 	/* Remove the object from the session's object list first. */
475 	rv = kernel_remove_object_from_session(objp, sp);
476 	if (!ses_lock_held) {
477 		/*
478 		 * If the session lock is obtained by this function,
479 		 * then release that lock after removing the object
480 		 * from session's object list.
481 		 * We want the releasing of the object storage to
482 		 * be done without holding the session lock.
483 		 */
484 		(void) pthread_mutex_unlock(&sp->session_mutex);
485 	}
486 
487 	if (rv != CKR_OK)
488 		return (rv);
489 
490 	kernel_delete_object_cleanup(objp);
491 
492 	/* Destroy the object. */
493 	if (objp->is_lib_obj) {
494 		/*
495 		 * If this object is created in the library, cleanup the
496 		 * contents of this object such as free all the storage
497 		 * allocated for this object.
498 		 */
499 		kernel_cleanup_object(objp);
500 	} else {
501 		/*
502 		 * This object is created in the HW provider. If wrapper_only
503 		 * is FALSE, make an ioctl call to destroy it in kernel.
504 		 */
505 		if (!wrapper_only) {
506 			obj_destroy.od_session = sp->k_session;
507 			obj_destroy.od_handle = objp->k_handle;
508 
509 			while (ioctl(kernel_fd, CRYPTO_OBJECT_DESTROY,
510 			    &obj_destroy) < 0) {
511 				if (errno != EINTR)
512 					break;
513 			}
514 
515 			/*
516 			 * Ignore ioctl return codes for a session object.
517 			 * If the kernel can not delete a session object, it
518 			 * is likely caused by the HW provider. There's not
519 			 * much that can be done.  The library will still
520 			 * cleanup the object wrapper in the library. The HW
521 			 * provider will destroy all session objects when
522 			 * the application exits.
523 			 */
524 		}
525 	}
526 
527 	/* Reset OBJECT_IS_DELETING flag. */
528 	objp->obj_delete_sync &= ~OBJECT_IS_DELETING;
529 
530 	(void) pthread_mutex_unlock(&objp->object_mutex);
531 	/* Destroy the object lock */
532 	(void) pthread_mutex_destroy(&objp->object_mutex);
533 	/* Free the object itself */
534 	kernel_object_delay_free(objp);
535 
536 	return (CKR_OK);
537 }
538 
539 /*
540  * Delete all the objects in a session. The caller holds the lock
541  * on the session.   If the wrapper_only argument is TRUE, the caller only
542  * want to clean up object wrappers in the library.
543  */
544 void
545 kernel_delete_all_objects_in_session(kernel_session_t *sp,
546     boolean_t wrapper_only)
547 {
548 	kernel_object_t *objp = sp->object_list;
549 	kernel_object_t *objp1;
550 
551 	/* Delete all the objects in the session. */
552 	while (objp) {
553 		objp1 = objp->next;
554 
555 		/*
556 		 * Delete an session object by calling
557 		 * kernel_delete_session_object():
558 		 * - The 3rd TRUE boolean argument indicates that the caller
559 		 *   holds the session lock.
560 		 * - The 4th boolean argument indicates whether we only want
561 		 *   clean up object wrappers in the library.
562 		 */
563 		(void) kernel_delete_session_object(sp, objp, B_TRUE,
564 		    wrapper_only);
565 
566 		objp = objp1;
567 	}
568 }
569 
570 static CK_RV
571 add_to_search_result(kernel_object_t *obj, find_context_t *fcontext,
572     CK_ULONG *num_result_alloc)
573 {
574 	/*
575 	 * allocate space for storing results if the currently
576 	 * allocated space is not enough
577 	 */
578 	if (*num_result_alloc <= fcontext->num_results) {
579 		fcontext->objs_found = realloc(fcontext->objs_found,
580 		    sizeof (kernel_object_t *) * (*num_result_alloc + BUFSIZ));
581 		if (fcontext->objs_found == NULL) {
582 			return (CKR_HOST_MEMORY);
583 		}
584 		*num_result_alloc += BUFSIZ;
585 	}
586 
587 	(fcontext->objs_found)[(fcontext->num_results)++] = obj;
588 	return (CKR_OK);
589 }
590 
591 static CK_RV
592 search_for_objects(kernel_session_t *sp, CK_ATTRIBUTE_PTR pTemplate,
593     CK_ULONG ulCount, find_context_t *fcontext)
594 {
595 	kernel_session_t *session_p;
596 	kernel_object_t *obj;
597 	CK_OBJECT_CLASS pclasses[6]; /* classes attrs possiblely exist */
598 	CK_ULONG num_pclasses;	/* number of possible classes */
599 	CK_ULONG num_result_alloc = 0; /* spaces allocated for results */
600 	CK_RV rv = CKR_OK;
601 	kernel_slot_t	*pslot;
602 
603 	if (ulCount > 0) {
604 		/* there are some search requirement */
605 		kernel_process_find_attr(pclasses, &num_pclasses,
606 		    pTemplate, ulCount);
607 	}
608 
609 	/* Acquire the slot lock */
610 	pslot = slot_table[sp->ses_slotid];
611 	(void) pthread_mutex_lock(&pslot->sl_mutex);
612 
613 	/*
614 	 * Go through all objects in each session.
615 	 * Acquire individual session lock for the session
616 	 * we are searching.
617 	 */
618 	session_p = pslot->sl_sess_list;
619 	while (session_p) {
620 		(void) pthread_mutex_lock(&session_p->session_mutex);
621 		obj = session_p->object_list;
622 		while (obj) {
623 			(void) pthread_mutex_lock(&obj->object_mutex);
624 			if (ulCount > 0) {
625 				if (kernel_find_match_attrs(obj, pclasses,
626 				    num_pclasses, pTemplate, ulCount)) {
627 					rv = add_to_search_result(
628 					    obj, fcontext, &num_result_alloc);
629 				}
630 			} else {
631 				/* no search criteria, just record the object */
632 				rv = add_to_search_result(obj, fcontext,
633 				    &num_result_alloc);
634 			}
635 			(void) pthread_mutex_unlock(&obj->object_mutex);
636 			if (rv != CKR_OK) {
637 				(void) pthread_mutex_unlock(
638 				    &session_p->session_mutex);
639 				goto cleanup;
640 			}
641 			obj = obj->next;
642 		}
643 		(void) pthread_mutex_unlock(&session_p->session_mutex);
644 		session_p = session_p->next;
645 	}
646 
647 cleanup:
648 	/* Release the slot lock */
649 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
650 	return (rv);
651 }
652 
653 /*
654  * Initialize the context for C_FindObjects() calls
655  */
656 CK_RV
657 kernel_find_objects_init(kernel_session_t *sp, CK_ATTRIBUTE_PTR pTemplate,
658     CK_ULONG ulCount)
659 {
660 	CK_RV rv = CKR_OK;
661 	CK_OBJECT_CLASS class; /* for kernel_validate_attr(). Value unused */
662 	find_context_t *fcontext;
663 
664 	if (ulCount) {
665 		rv = kernel_validate_attr(pTemplate, ulCount, &class);
666 		/* Make sure all attributes in template are valid */
667 		if (rv != CKR_OK) {
668 			return (rv);
669 		}
670 	}
671 
672 	/* prepare the find context */
673 	fcontext = calloc(1, sizeof (find_context_t));
674 	if (fcontext == NULL) {
675 		return (CKR_HOST_MEMORY);
676 	}
677 
678 	rv = search_for_objects(sp, pTemplate, ulCount, fcontext);
679 	if (rv != CKR_OK) {
680 		free(fcontext);
681 		return (rv);
682 	}
683 
684 	/* store the find_context in the session */
685 	sp->find_objects.context = (CK_VOID_PTR)fcontext;
686 
687 	return (rv);
688 }
689 
690 void
691 kernel_find_objects_final(kernel_session_t *sp)
692 {
693 	find_context_t *fcontext;
694 
695 	fcontext = sp->find_objects.context;
696 	sp->find_objects.context = NULL;
697 	sp->find_objects.flags = 0;
698 	if (fcontext->objs_found != NULL) {
699 		free(fcontext->objs_found);
700 	}
701 
702 	free(fcontext);
703 }
704 
705 void
706 kernel_find_objects(kernel_session_t *sp, CK_OBJECT_HANDLE *obj_found,
707     CK_ULONG max_obj_requested, CK_ULONG *found_obj_count)
708 {
709 	find_context_t *fcontext;
710 	CK_ULONG num_obj_found = 0;
711 	CK_ULONG i;
712 	kernel_object_t *obj;
713 
714 	fcontext = sp->find_objects.context;
715 
716 	for (i = fcontext->next_result_index;
717 	    ((num_obj_found < max_obj_requested) &&
718 	    (i < fcontext->num_results));
719 	    i++) {
720 		obj = fcontext->objs_found[i];
721 		if (obj != NULL) {
722 			(void) pthread_mutex_lock(&obj->object_mutex);
723 			/* a sanity check to make sure the obj is still valid */
724 			if (obj->magic_marker == KERNELTOKEN_OBJECT_MAGIC) {
725 				obj_found[num_obj_found] =
726 				    (CK_OBJECT_HANDLE)obj;
727 				num_obj_found++;
728 			}
729 			(void) pthread_mutex_unlock(&obj->object_mutex);
730 		}
731 	}
732 	fcontext->next_result_index = i;
733 	*found_obj_count = num_obj_found;
734 }
735 
736 /*
737  * Add an token object to the token object list in slot.
738  *
739  * This function will acquire the lock on the slot, and release
740  * that lock after adding the object to the slot's token object list.
741  */
742 void
743 kernel_add_token_object_to_slot(kernel_object_t *objp, kernel_slot_t *pslot)
744 {
745 	/* Acquire the slot lock. */
746 	(void) pthread_mutex_lock(&pslot->sl_mutex);
747 
748 	/* Insert the new object in front of slot's token object list. */
749 	if (pslot->sl_tobj_list == NULL) {
750 		pslot->sl_tobj_list = objp;
751 		objp->next = NULL;
752 		objp->prev = NULL;
753 	} else {
754 		pslot->sl_tobj_list->prev = objp;
755 		objp->next = pslot->sl_tobj_list;
756 		objp->prev = NULL;
757 		pslot->sl_tobj_list = objp;
758 	}
759 
760 	/* Release the slot lock. */
761 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
762 }
763 
764 /*
765  * Remove an token object from the slot's token object list.
766  * This routine is called by kernel_delete_token_object().
767  * The caller of this function hold the slot lock.
768  */
769 void
770 kernel_remove_token_object_from_slot(kernel_slot_t *pslot,
771     kernel_object_t *objp)
772 {
773 
774 	if (pslot->sl_tobj_list == objp) {
775 		/* Object is the first one in the list */
776 		if (objp->next) {
777 			pslot->sl_tobj_list = objp->next;
778 			objp->next->prev = NULL;
779 		} else {
780 			/* Object is the only one in the list. */
781 			pslot->sl_tobj_list = NULL;
782 		}
783 	} else {
784 		/* Object is not the first one in the list. */
785 		if (objp->next) {
786 			/* Object is in the middle of the list. */
787 			objp->prev->next = objp->next;
788 			objp->next->prev = objp->prev;
789 		} else {
790 			/* Object is the last one in the list. */
791 			objp->prev->next = NULL;
792 		}
793 	}
794 }
795 
796 /*
797  * Delete a token object:
798  * - Remove the object from the slot's token object list.
799  * - Release the storage allocated to the object.
800  *
801  * The boolean argument slot_lock_held is used to indicate that whether
802  * the caller holds the slot lock or not. When the caller does not hold
803  * the slot lock, this function will acquire that lock in order to proceed,
804  * and also release that lock before returning to caller.
805  *
806  * The boolean argument wrapper_only is used to indicate that whether
807  * the caller only wants to the object wrapper from library.
808  */
809 CK_RV
810 kernel_delete_token_object(kernel_slot_t *pslot, kernel_session_t *sp,
811     kernel_object_t *objp, boolean_t slot_lock_held, boolean_t wrapper_only)
812 {
813 	CK_RV rv;
814 	crypto_object_destroy_t	obj_destroy;
815 	int r;
816 
817 	/*
818 	 * Check to see if the caller holds the lock on the slot.
819 	 * If not, we need to acquire that lock in order to proceed.
820 	 */
821 	if (!slot_lock_held) {
822 		(void) pthread_mutex_lock(&pslot->sl_mutex);
823 	}
824 
825 	/* Remove the object from the slot's token object list first. */
826 	kernel_remove_token_object_from_slot(pslot, objp);
827 
828 	/* Release the slot lock if the call doesn't hold the lock. */
829 	if (!slot_lock_held) {
830 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
831 	}
832 
833 	kernel_delete_object_cleanup(objp);
834 
835 	if (!wrapper_only) {
836 		obj_destroy.od_session = sp->k_session;
837 		obj_destroy.od_handle = objp->k_handle;
838 
839 		while ((r = ioctl(kernel_fd, CRYPTO_OBJECT_DESTROY,
840 		    &obj_destroy)) < 0) {
841 			if (errno != EINTR)
842 				break;
843 		}
844 		if (r < 0) {
845 			rv = CKR_FUNCTION_FAILED;
846 		} else {
847 			rv = crypto2pkcs11_error_number(
848 			    obj_destroy.od_return_value);
849 		}
850 
851 		/*
852 		 * Could not destroy an object from kernel. Write a warning
853 		 * in syslog, but we still clean up the object wrapper in
854 		 * the library.
855 		 */
856 		if (rv != CKR_OK) {
857 			cryptoerror(LOG_ERR, "pkcs11_kernel: Could not "
858 			    "destroy an object in kernel.");
859 		}
860 	}
861 
862 	(void) pthread_mutex_unlock(&objp->object_mutex);
863 	/* Destroy the object lock */
864 	(void) pthread_mutex_destroy(&objp->object_mutex);
865 	/* Free the object itself */
866 	kernel_object_delay_free(objp);
867 
868 	return (CKR_OK);
869 }
870 
871 /*
872  * Clean up private object wrappers in this slot. The caller holds the slot
873  * lock.
874  */
875 void
876 kernel_cleanup_pri_objects_in_slot(kernel_slot_t *pslot,
877     kernel_session_t *cur_sp)
878 {
879 	kernel_session_t *session_p;
880 	kernel_object_t *objp;
881 	kernel_object_t *objp1;
882 
883 	/*
884 	 * Delete every private token object from the slot' token object list
885 	 */
886 	objp = pslot->sl_tobj_list;
887 	while (objp) {
888 		objp1 = objp->next;
889 		/*
890 		 * The first TRUE boolean argument indicates that the caller
891 		 * hold the slot lock.  The second TRUE boolean argument
892 		 * indicates that the caller just wants to clean up the object
893 		 * wrapper from the library only.
894 		 */
895 		if (objp->bool_attr_mask & PRIVATE_BOOL_ON) {
896 			(void) kernel_delete_token_object(pslot, cur_sp, objp,
897 			    B_TRUE, B_TRUE);
898 		}
899 		objp = objp1;
900 	}
901 
902 	/*
903 	 * Walk through all the sessions in this slot and delete every
904 	 * private object.
905 	 */
906 	session_p = pslot->sl_sess_list;
907 	while (session_p) {
908 
909 		/* Delete all the objects in the session. */
910 		objp = session_p->object_list;
911 		while (objp) {
912 			objp1 = objp->next;
913 			/*
914 			 * The FALSE boolean argument indicates that the
915 			 * caller does not hold the session lock.  The TRUE
916 			 * boolean argument indicates that the caller just
917 			 * want to clean upt the object wrapper from the
918 			 * library only.
919 			 */
920 			if (objp->bool_attr_mask & PRIVATE_BOOL_ON) {
921 				(void) kernel_delete_session_object(session_p,
922 				    objp, B_FALSE, B_TRUE);
923 			}
924 
925 			objp = objp1;
926 		}
927 
928 		session_p = session_p->next;
929 	}
930 }
931 
932 /*
933  * Get the object size in bytes for the objects created in the library.
934  */
935 CK_RV
936 kernel_get_object_size(kernel_object_t *obj, CK_ULONG_PTR pulSize)
937 {
938 	CK_RV rv = CKR_OK;
939 	CK_ULONG obj_size;
940 	biginteger_t *big;
941 
942 	obj_size = sizeof (kernel_object_t);
943 
944 	switch (obj->class) {
945 	case CKO_PUBLIC_KEY:
946 		if (obj->key_type == CKK_RSA) {
947 			big = OBJ_PUB_RSA_PUBEXPO(obj);
948 			obj_size += big->big_value_len;
949 			big = OBJ_PUB_RSA_MOD(obj);
950 			obj_size += big->big_value_len;
951 
952 		} else if (obj->key_type == CKK_DSA) {
953 			big = OBJ_PUB_DSA_PRIME(obj);
954 			obj_size += big->big_value_len;
955 			big = OBJ_PUB_DSA_SUBPRIME(obj);
956 			obj_size += big->big_value_len;
957 			big = OBJ_PUB_DSA_BASE(obj);
958 			obj_size += big->big_value_len;
959 			big = OBJ_PUB_DSA_VALUE(obj);
960 			obj_size += big->big_value_len;
961 
962 		} else if (obj->key_type == CKK_EC) {
963 			big = OBJ_PUB_EC_POINT(obj);
964 			obj_size += big->big_value_len;
965 
966 		} else {
967 			rv = CKR_OBJECT_HANDLE_INVALID;
968 		}
969 		break;
970 
971 	case CKO_PRIVATE_KEY:
972 		if (obj->key_type == CKK_RSA) {
973 			big = OBJ_PRI_RSA_MOD(obj);
974 			obj_size += big->big_value_len;
975 
976 			big = OBJ_PRI_RSA_PUBEXPO(obj); /* optional */
977 			if (big != NULL) {
978 				obj_size += big->big_value_len;
979 			}
980 
981 			big = OBJ_PRI_RSA_PRIEXPO(obj);
982 			obj_size += big->big_value_len;
983 
984 			big = OBJ_PRI_RSA_PRIME1(obj); /* optional */
985 			if (big != NULL) {
986 				obj_size += big->big_value_len;
987 			}
988 
989 			big = OBJ_PRI_RSA_PRIME2(obj); /* optional */
990 			if (big != NULL) {
991 				obj_size += big->big_value_len;
992 			}
993 
994 			big = OBJ_PRI_RSA_EXPO1(obj); /* optional */
995 			if (big != NULL) {
996 				obj_size += big->big_value_len;
997 			}
998 
999 			big = OBJ_PRI_RSA_EXPO2(obj); /* optional */
1000 			if (big != NULL) {
1001 				obj_size += big->big_value_len;
1002 			}
1003 
1004 			big = OBJ_PRI_RSA_COEF(obj); /* optional */
1005 			if (big != NULL) {
1006 				obj_size += big->big_value_len;
1007 			}
1008 
1009 		} else if (obj->key_type == CKK_DSA) {
1010 			big = OBJ_PRI_DSA_PRIME(obj);
1011 			obj_size += big->big_value_len;
1012 			big = OBJ_PRI_DSA_SUBPRIME(obj);
1013 			obj_size += big->big_value_len;
1014 			big = OBJ_PRI_DSA_BASE(obj);
1015 			obj_size += big->big_value_len;
1016 			big = OBJ_PRI_DSA_VALUE(obj);
1017 			obj_size += big->big_value_len;
1018 
1019 		} else if (obj->key_type == CKK_EC) {
1020 			big = OBJ_PRI_EC_VALUE(obj);
1021 			obj_size += big->big_value_len;
1022 
1023 		} else {
1024 			rv = CKR_OBJECT_HANDLE_INVALID;
1025 		}
1026 		break;
1027 
1028 	case CKO_SECRET_KEY:
1029 		obj_size += OBJ_SEC_VALUE_LEN(obj);
1030 		break;
1031 
1032 	default:
1033 		rv = CKR_OBJECT_HANDLE_INVALID;
1034 	}
1035 
1036 	if (rv == CKR_OK) {
1037 		*pulSize = obj_size;
1038 	}
1039 
1040 	return (rv);
1041 }
1042 
1043 /*
1044  * This function adds the to-be-freed session object to a linked list.
1045  * When the number of objects queued in the linked list reaches the
1046  * maximum threshold MAX_OBJ_TO_BE_FREED, it will free the first
1047  * object (FIFO) in the list.
1048  */
1049 void
1050 kernel_object_delay_free(kernel_object_t *objp)
1051 {
1052 	kernel_object_t *tmp;
1053 
1054 	(void) pthread_mutex_lock(&obj_delay_freed.obj_to_be_free_mutex);
1055 
1056 	/* Add the newly deleted object at the end of the list */
1057 	objp->next = NULL;
1058 	if (obj_delay_freed.first == NULL) {
1059 		obj_delay_freed.last = objp;
1060 		obj_delay_freed.first = objp;
1061 	} else {
1062 		obj_delay_freed.last->next = objp;
1063 		obj_delay_freed.last = objp;
1064 	}
1065 
1066 	if (++obj_delay_freed.count >= MAX_OBJ_TO_BE_FREED) {
1067 		/*
1068 		 * Free the first object in the list only if
1069 		 * the total count reaches maximum threshold.
1070 		 */
1071 		obj_delay_freed.count--;
1072 		tmp = obj_delay_freed.first->next;
1073 		free(obj_delay_freed.first);
1074 		obj_delay_freed.first = tmp;
1075 	}
1076 	(void) pthread_mutex_unlock(&obj_delay_freed.obj_to_be_free_mutex);
1077 }
1078