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