xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelObjectUtil.c (revision b8767451d156f585534afac0bf22721810d0dc63)
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  */
44 void
45 kernel_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  */
73 void
74 kernel_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  */
104 CK_RV
105 kernel_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  */
192 void
193 kernel_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  */
207 CK_RV
208 kernel_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 
319 fail_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  */
341 CK_RV
342 kernel_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 
394 static void
395 kernel_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  */
464 CK_RV
465 kernel_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  */
550 void
551 kernel_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 
576 static CK_RV
577 add_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 
597 static CK_RV
598 search_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 
653 cleanup:
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  */
662 CK_RV
663 kernel_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 
696 void
697 kernel_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 
711 void
712 kernel_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  */
748 void
749 kernel_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  */
775 void
776 kernel_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  */
815 CK_RV
816 kernel_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  */
881 void
882 kernel_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  */
941 CK_RV
942 kernel_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  */
1055 void
1056 kernel_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