xref: /onnv-gate/usr/src/lib/pkcs11/pkcs11_kms/common/kmsObjectUtil.c (revision 12720:3db6e0082404)
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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <strings.h>
28 #include <errno.h>
29 #include <security/cryptoki.h>
30 #include <cryptoutil.h>
31 
32 #include "kmsGlobal.h"
33 #include "kmsObject.h"
34 #include "kmsSession.h"
35 #include "kmsSlot.h"
36 #include "kmsKeystoreUtil.h"
37 
38 kms_object_t *
kms_new_object()39 kms_new_object()
40 {
41 	kms_object_t *obj;
42 
43 	obj = calloc(1, sizeof (kms_object_t));
44 	if (obj == NULL)
45 		return (NULL);
46 
47 	(void) pthread_cond_init(&obj->obj_free_cond, NULL);
48 	(void) pthread_mutex_init(&obj->object_mutex, NULL);
49 	obj->magic_marker = KMSTOKEN_OBJECT_MAGIC;
50 
51 	return (obj);
52 }
53 
54 /*
55  * Add an object to the session's object list.
56  *
57  * This function will acquire the lock on the session, and release
58  * that lock after adding the object to the session's object list.
59  */
60 void
kms_add_object_to_session(kms_object_t * objp,kms_session_t * sp)61 kms_add_object_to_session(kms_object_t *objp, kms_session_t *sp)
62 {
63 	/* Acquire the session lock. */
64 	(void) pthread_mutex_lock(&sp->session_mutex);
65 
66 	/* Insert the new object in front of session's object list. */
67 	if (sp->object_list == NULL) {
68 		sp->object_list = objp;
69 		objp->next = NULL;
70 		objp->prev = NULL;
71 	} else {
72 		sp->object_list->prev = objp;
73 		objp->next = sp->object_list;
74 		objp->prev = NULL;
75 		sp->object_list = objp;
76 	}
77 
78 	/* Release the session lock. */
79 	(void) pthread_mutex_unlock(&sp->session_mutex);
80 }
81 
82 /*
83  * Clean up and release the storage allocated to the object.
84  *
85  * The function is called either with the object lock being held
86  * (by caller kms_delete_object()), or there is no object lock
87  * yet (by kms_build_XXX_object() during creating an object).
88  */
89 void
kms_cleanup_object(kms_object_t * objp)90 kms_cleanup_object(kms_object_t *objp)
91 {
92 	/*
93 	 * Free the storage allocated to a secret key object.
94 	 */
95 	if (objp->class == CKO_SECRET_KEY) {
96 		if (OBJ_SEC(objp) != NULL && OBJ_SEC_VALUE(objp) != NULL) {
97 			bzero(OBJ_SEC_VALUE(objp), OBJ_SEC_VALUE_LEN(objp));
98 			free(OBJ_SEC_VALUE(objp));
99 			OBJ_SEC_VALUE(objp) = NULL;
100 			OBJ_SEC_VALUE_LEN(objp) = 0;
101 		}
102 		if (OBJ_SEC(objp) != NULL)
103 			free(OBJ_SEC(objp));
104 
105 		OBJ_SEC(objp) = NULL;
106 	}
107 
108 	/*
109 	 * Free the storage allocated to the extra attribute list.
110 	 */
111 	kms_cleanup_extra_attr(objp);
112 }
113 
114 void
kms_free_object(kms_object_t * obj)115 kms_free_object(kms_object_t *obj)
116 {
117 	(void) pthread_cond_destroy(&obj->obj_free_cond);
118 	(void) pthread_mutex_destroy(&obj->object_mutex);
119 
120 	kms_cleanup_object(obj);
121 
122 	free(obj);
123 }
124 
125 /*
126  * Create a new object. Copy the attributes that can be modified
127  * (in the boolean attribute mask field and extra attribute list)
128  * from the old object to the new object.
129  *
130  * The caller of this function holds the lock on the old object.
131  */
132 CK_RV
kms_copy_object(kms_object_t * old_object,kms_object_t ** new_object,boolean_t copy_everything,kms_session_t * sp)133 kms_copy_object(kms_object_t *old_object, kms_object_t **new_object,
134     boolean_t copy_everything, kms_session_t *sp)
135 {
136 	CK_RV rv = CKR_OK;
137 	kms_object_t *new_objp = NULL;
138 	CK_ATTRIBUTE_INFO_PTR attrp;
139 
140 	/* Allocate new object. */
141 	new_objp = kms_new_object();
142 	if (new_objp == NULL)
143 		return (CKR_HOST_MEMORY);
144 
145 	new_objp->class = old_object->class;
146 	new_objp->bool_attr_mask = old_object->bool_attr_mask;
147 
148 	attrp = old_object->extra_attrlistp;
149 	while (attrp) {
150 		/*
151 		 * Copy the attribute_info struct from the old
152 		 * object to a new attribute_info struct, and add
153 		 * that new struct to the extra attribute list
154 		 * of the new object.
155 		 */
156 		rv = kms_copy_extra_attr(attrp, new_objp);
157 		if (rv != CKR_OK) {
158 			kms_free_object(new_objp);
159 			return (rv);
160 		}
161 		attrp = attrp->next;
162 	}
163 
164 	*new_object = new_objp;
165 
166 	if (!copy_everything) {
167 		/* done with copying all information that can be modified */
168 		return (CKR_OK);
169 	}
170 
171 	/*
172 	 * Copy the rest of the object.
173 	 * Certain fields that are not appropriate for coping will be
174 	 * initialized.
175 	 */
176 	new_objp->key_type = old_object->key_type;
177 	new_objp->magic_marker = old_object->magic_marker;
178 	new_objp->mechanism = old_object->mechanism;
179 	new_objp->session_handle = (CK_SESSION_HANDLE)sp;
180 
181 	/* copy key related information */
182 	switch (new_objp->class) {
183 		case CKO_SECRET_KEY:
184 			rv = kms_copy_secret_key_attr(OBJ_SEC(old_object),
185 			    &(OBJ_SEC(new_objp)));
186 			break;
187 		default:
188 			/* should never be this case */
189 			break;
190 	}
191 	if (rv != CKR_OK) {
192 		kms_free_object(new_objp);
193 		*new_object = NULL;
194 	}
195 	return (rv);
196 }
197 
198 /*
199  * Copy the attributes (in the boolean attribute mask field and
200  * extra attribute list) from the new object back to the original
201  * object. Also, clean up and release all the storage in the extra
202  * attribute list of the original object.
203  *
204  * The caller of this function holds the lock on the old object.
205  */
206 void
kms_merge_object(kms_object_t * old_object,kms_object_t * new_object)207 kms_merge_object(kms_object_t *old_object, kms_object_t *new_object)
208 {
209 	old_object->bool_attr_mask = new_object->bool_attr_mask;
210 	kms_cleanup_extra_attr(old_object);
211 	old_object->extra_attrlistp = new_object->extra_attrlistp;
212 }
213 
214 /*
215  * Create a new object struct.  If it is a session object, add the object to
216  * the session's object list.  If it is a token object, add it to the slot's
217  * token object list.  The caller does not hold the slot lock.
218  */
219 CK_RV
kms_add_object(CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_ULONG * objecthandle_p,kms_session_t * sp)220 kms_add_object(CK_ATTRIBUTE_PTR pTemplate,  CK_ULONG ulCount,
221 	CK_ULONG *objecthandle_p, kms_session_t *sp)
222 {
223 	CK_RV rv = CKR_OK;
224 	kms_object_t *new_objp = NULL;
225 	kms_slot_t	*pslot;
226 	CK_ATTRIBUTE	pritmpl;
227 	CK_BBOOL	is_pri_obj, is_token_obj;
228 
229 	new_objp = kms_new_object();
230 	if (new_objp == NULL)
231 		return (CKR_HOST_MEMORY);
232 
233 	rv = kms_build_object(pTemplate, ulCount, new_objp);
234 	if (rv != CKR_OK)
235 		goto fail_cleanup;
236 
237 	/* Cannot create a token object with a READ-ONLY session */
238 	pritmpl.type = CKA_TOKEN;
239 	pritmpl.pValue = &is_token_obj;
240 	pritmpl.ulValueLen = sizeof (is_token_obj);
241 	rv = kms_get_attribute(new_objp, &pritmpl);
242 	if (rv != CKR_OK)
243 		goto fail_cleanup;
244 
245 	if (is_token_obj && sp->ses_RO) {
246 		rv = CKR_SESSION_READ_ONLY;
247 		goto fail_cleanup;
248 	}
249 
250 	/*
251 	 * If the KMS supports object creation, create the object
252 	 * in the KMS.  Otherwise, create the object in the library.
253 	 */
254 
255 	/* Get the CKA_PRIVATE value of this object. */
256 	pritmpl.type = CKA_PRIVATE;
257 	pritmpl.pValue = &is_pri_obj;
258 	pritmpl.ulValueLen = sizeof (is_pri_obj);
259 
260 	rv = kms_get_attribute(new_objp, &pritmpl);
261 	if (rv != CKR_OK) {
262 		goto fail_cleanup;
263 	}
264 
265 	/* Set the PRIVATE_BOOL_ON and TOKEN_BOOL_ON attributes */
266 	if (is_pri_obj)
267 		new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
268 	else
269 		new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
270 
271 	if (is_token_obj)
272 		new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
273 	else
274 		new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
275 
276 	new_objp->session_handle = (CK_SESSION_HANDLE)sp;
277 
278 	if (is_token_obj) {
279 		/* Add the new object to the slot's token object list. */
280 		pslot = get_slotinfo();
281 		kms_add_token_object_to_slot(new_objp, pslot);
282 	} else {
283 		/* Add the new object to the session's object list. */
284 		kms_add_object_to_session(new_objp, sp);
285 	}
286 
287 	/* Type casting the address of an object struct to an object handle. */
288 	if (rv == CKR_OK)
289 		*objecthandle_p = (CK_ULONG)new_objp;
290 
291 fail_cleanup:
292 	if (rv != CKR_OK) {
293 		kms_free_object(new_objp);
294 	}
295 	return (rv);
296 }
297 
298 /*
299  * Remove an object from the session's object list.
300  *
301  * The caller of this function holds the session lock.
302  */
303 CK_RV
kms_remove_object_from_session(kms_object_t * objp,kms_session_t * sp)304 kms_remove_object_from_session(kms_object_t *objp, kms_session_t *sp)
305 {
306 	kms_object_t *tmp_objp;
307 	boolean_t found = B_FALSE;
308 
309 	/*
310 	 * Remove the object from the session's object list.
311 	 */
312 	if ((sp == NULL) ||
313 	    (sp->magic_marker != KMSTOKEN_SESSION_MAGIC)) {
314 		return (CKR_SESSION_HANDLE_INVALID);
315 	}
316 
317 	if ((sp->object_list == NULL) || (objp == NULL) ||
318 	    (objp->magic_marker != KMSTOKEN_OBJECT_MAGIC)) {
319 		return (CKR_OBJECT_HANDLE_INVALID);
320 	}
321 
322 	tmp_objp = sp->object_list;
323 	while (tmp_objp) {
324 		if (tmp_objp == objp) {
325 			found = B_TRUE;
326 			break;
327 		}
328 		tmp_objp = tmp_objp->next;
329 	}
330 	if (!found)
331 		return (CKR_OBJECT_HANDLE_INVALID);
332 
333 	if (sp->object_list == objp) {
334 		/* Object is the first one in the list. */
335 		if (objp->next) {
336 			sp->object_list = objp->next;
337 			objp->next->prev = NULL;
338 		} else {
339 			/* Object is the only one in the list. */
340 			sp->object_list = NULL;
341 		}
342 	} else {
343 		/* Object is not the first one in the list. */
344 		if (objp->next) {
345 			/* Object is in the middle of the list. */
346 			objp->prev->next = objp->next;
347 			objp->next->prev = objp->prev;
348 		} else {
349 			/* Object is the last one in the list. */
350 			objp->prev->next = NULL;
351 		}
352 	}
353 	return (CKR_OK);
354 }
355 
356 /*
357  * This function adds the to-be-freed session object to a linked list.
358  * When the number of objects queued in the linked list reaches the
359  * maximum threshold MAX_OBJ_TO_BE_FREED, it will free the first
360  * object (FIFO) in the list.
361  */
362 void
kms_object_delay_free(kms_object_t * objp)363 kms_object_delay_free(kms_object_t *objp)
364 {
365 	kms_object_t *tmp;
366 
367 	(void) pthread_mutex_lock(&obj_delay_freed.obj_to_be_free_mutex);
368 
369 	/* Add the newly deleted object at the end of the list */
370 	objp->next = NULL;
371 	if (obj_delay_freed.first == NULL) {
372 		obj_delay_freed.last = objp;
373 		obj_delay_freed.first = objp;
374 	} else {
375 		obj_delay_freed.last->next = objp;
376 		obj_delay_freed.last = objp;
377 	}
378 
379 	if (++obj_delay_freed.count >= MAX_OBJ_TO_BE_FREED) {
380 		/*
381 		 * Free the first object in the list only if
382 		 * the total count reaches maximum threshold.
383 		 */
384 		obj_delay_freed.count--;
385 		tmp = obj_delay_freed.first->next;
386 		kms_free_object(obj_delay_freed.first);
387 		obj_delay_freed.first = tmp;
388 	}
389 	(void) pthread_mutex_unlock(&obj_delay_freed.obj_to_be_free_mutex);
390 }
391 
392 static void
kms_delete_object_cleanup(kms_object_t * objp,boolean_t force)393 kms_delete_object_cleanup(kms_object_t *objp, boolean_t force)
394 {
395 	/* Acquire the lock on the object. */
396 	(void) pthread_mutex_lock(&objp->object_mutex);
397 
398 	/*
399 	 * Make sure another thread hasn't freed the object.
400 	 */
401 	if (objp->magic_marker != KMSTOKEN_OBJECT_MAGIC) {
402 		(void) pthread_mutex_unlock(&objp->object_mutex);
403 		return;
404 	}
405 
406 	/*
407 	 * The deletion of an object must be blocked when the object
408 	 * reference count is not zero. This means if any object related
409 	 * operation starts prior to the delete object operation gets in,
410 	 * the object deleting thread must wait for the non-deleting
411 	 * operation to be completed before it can proceed the delete
412 	 * operation.
413 	 *
414 	 * Unless we are being forced to shut everything down, this only
415 	 * happens if the library's _fini() is running not if someone
416 	 * explicitly called C_Finalize().
417 	 */
418 	if (force) {
419 		objp->obj_refcnt = 0;
420 	}
421 
422 	while (objp->obj_refcnt != 0) {
423 		/*
424 		 * We set the OBJECT_REFCNT_WAITING flag before we put
425 		 * this deleting thread in a wait state, so other non-deleting
426 		 * operation thread will signal to wake it up only when
427 		 * the object reference count becomes zero and this flag
428 		 * is set.
429 		 */
430 		objp->obj_delete_sync |= OBJECT_REFCNT_WAITING;
431 		(void) pthread_cond_wait(&objp->obj_free_cond,
432 		    &objp->object_mutex);
433 	}
434 
435 	objp->obj_delete_sync &= ~OBJECT_REFCNT_WAITING;
436 
437 	/* Mark object as no longer valid. */
438 	objp->magic_marker = 0;
439 	kms_cleanup_object(objp);
440 
441 	objp->obj_delete_sync &= ~OBJECT_IS_DELETING;
442 	(void) pthread_mutex_unlock(&objp->object_mutex);
443 
444 	if (objp->bool_attr_mask & TOKEN_BOOL_ON)
445 		free(objp);
446 	else
447 		kms_object_delay_free(objp);
448 }
449 
450 /*
451  * Delete a session object:
452  * - Remove the object from the session's object list.
453  * - Release the storage allocated to the object.
454  *
455  * The boolean argument ses_lock_held is used to indicate that whether
456  * the caller holds the session lock or not.
457  * - When called by kms_delete_all_objects_in_session() or
458  *   kms_delete_pri_objects_in_slot() -- ses_lock_held = TRUE.
459  *
460  * The boolean argument wrapper_only is used to indicate that whether
461  * the caller only wants to clean up the object wrapper from the library and
462  * needs not to make an call to KMS.
463  * - This argument only applies to the object created in the provider level.
464  * - When called by kms_cleanup_pri_objects_in_slot(), wrapper_only is TRUE.
465  * - When called by C_DestroyObject(), wrapper_only is FALSE.
466  * - When called by kms_delete_all_objects_in_session(), the value of
467  *   wrapper_only depends on its caller.
468  */
469 CK_RV
kms_delete_object(kms_session_t * sp,kms_object_t * objp,boolean_t ses_lock_held,boolean_t wrapper_only)470 kms_delete_object(kms_session_t *sp, kms_object_t *objp,
471     boolean_t ses_lock_held, boolean_t wrapper_only)
472 {
473 	CK_RV rv = CKR_OK;
474 
475 	/*
476 	 * Check to see if the caller holds the lock on the session.
477 	 * If not, we need to acquire that lock in order to proceed.
478 	 */
479 	if (!ses_lock_held) {
480 		/* Acquire the session lock. */
481 		(void) pthread_mutex_lock(&sp->session_mutex);
482 	}
483 
484 	/* Remove the object from the session's object list first. */
485 	if ((rv = kms_remove_object_from_session(objp, sp))) {
486 		if (!ses_lock_held)
487 			(void) pthread_mutex_unlock(&sp->session_mutex);
488 		return (rv);
489 	}
490 
491 	if (!wrapper_only)
492 		(void) pthread_mutex_unlock(&sp->session_mutex);
493 
494 	kms_delete_object_cleanup(objp, wrapper_only);
495 
496 	return (rv);
497 }
498 
499 /*
500  * Delete all the objects in a session. The caller holds the lock
501  * on the session.   If the wrapper_only argument is TRUE, the caller only
502  * want to clean up object wrappers in the library.
503  */
504 void
kms_delete_all_objects_in_session(kms_session_t * sp,boolean_t wrapper_only)505 kms_delete_all_objects_in_session(kms_session_t *sp,
506     boolean_t wrapper_only)
507 {
508 	kms_object_t *objp = sp->object_list;
509 	kms_object_t *objp1;
510 
511 	/* Delete all the objects in the session. */
512 	while (objp) {
513 		objp1 = objp->next;
514 		(void) kms_delete_object(sp, objp, B_TRUE,
515 		    wrapper_only);
516 
517 		objp = objp1;
518 	}
519 }
520 
521 static CK_RV
add_to_search_result(kms_object_t * obj,find_context_t * fcontext,CK_ULONG * num_result_alloc)522 add_to_search_result(kms_object_t *obj, find_context_t *fcontext,
523     CK_ULONG *num_result_alloc)
524 {
525 	/*
526 	 * allocate space for storing results if the currently
527 	 * allocated space is not enough
528 	 */
529 	if (*num_result_alloc <= fcontext->num_results) {
530 		fcontext->objs_found = realloc(fcontext->objs_found,
531 		    sizeof (kms_object_t *) * (*num_result_alloc + BUFSIZ));
532 		if (fcontext->objs_found == NULL) {
533 			return (CKR_HOST_MEMORY);
534 		}
535 		*num_result_alloc += BUFSIZ;
536 	}
537 
538 	(fcontext->objs_found)[(fcontext->num_results)++] = obj;
539 	return (CKR_OK);
540 }
541 
542 static CK_RV
search_for_objects(kms_session_t * sp,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,find_context_t * fcontext)543 search_for_objects(kms_session_t *sp, CK_ATTRIBUTE_PTR pTemplate,
544     CK_ULONG ulCount, find_context_t *fcontext)
545 {
546 	kms_session_t *session_p;
547 	kms_object_t *obj;
548 	CK_OBJECT_CLASS pclasses[6]; /* classes attrs possibly exist */
549 	CK_ULONG num_pclasses;	/* number of possible classes */
550 	CK_ULONG num_result_alloc = 0; /* spaces allocated for results */
551 	CK_RV rv = CKR_OK;
552 	kms_slot_t	*pslot = NULL;
553 	boolean_t token_specified = B_FALSE;
554 	boolean_t token_flag_val = B_FALSE;
555 	int i;
556 
557 	if (ulCount > 0) {
558 		/* there are some search requirement */
559 		kms_process_find_attr(pclasses, &num_pclasses,
560 		    pTemplate, ulCount);
561 	}
562 
563 	/*
564 	 * look through template and see if it explicitly specifies
565 	 * whether we need to look for token objects or not
566 	 */
567 	for (i = 0; i < ulCount; i++) {
568 		if (pTemplate[i].type == CKA_TOKEN) {
569 			token_specified = B_TRUE;
570 			token_flag_val = *((CK_BBOOL *)pTemplate[i].pValue);
571 			break;
572 		}
573 	}
574 
575 	pslot = get_slotinfo();
576 
577 	/* Acquire the slot lock */
578 	if (token_flag_val || !token_specified) {
579 		(void) pthread_mutex_lock(&pslot->sl_mutex);
580 		/*
581 		 * Make sure the object list is current.
582 		 */
583 		rv = KMS_RefreshObjectList(sp, pslot);
584 		if (rv != CKR_OK) {
585 			(void) pthread_mutex_unlock(&pslot->sl_mutex);
586 			return (rv);
587 		}
588 
589 		obj = pslot->sl_tobj_list;
590 		while (obj) {
591 			(void) pthread_mutex_lock(&obj->object_mutex);
592 			if (((token_specified) && (ulCount > 1)) ||
593 			    ((!token_specified) && (ulCount > 0))) {
594 				if (kms_find_match_attrs(obj, pclasses,
595 				    num_pclasses, pTemplate, ulCount)) {
596 					rv = add_to_search_result(
597 					    obj, fcontext, &num_result_alloc);
598 				}
599 			} else {
600 				/* no search criteria, just record the object */
601 				rv = add_to_search_result(obj, fcontext,
602 				    &num_result_alloc);
603 			}
604 			(void) pthread_mutex_unlock(&obj->object_mutex);
605 			if (rv != CKR_OK) {
606 				goto cleanup;
607 			}
608 			obj = obj->next;
609 		}
610 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
611 	}
612 
613 	if (token_flag_val) {
614 		return (rv);
615 	}
616 
617 	/*
618 	 * Go through all objects in each session.
619 	 * Acquire individual session lock for the session
620 	 * we are searching.
621 	 */
622 	session_p = pslot->sl_sess_list;
623 	while (session_p) {
624 		(void) pthread_mutex_lock(&session_p->session_mutex);
625 		obj = session_p->object_list;
626 		while (obj) {
627 			(void) pthread_mutex_lock(&obj->object_mutex);
628 			if (ulCount > 0) {
629 				if (kms_find_match_attrs(obj, pclasses,
630 				    num_pclasses, pTemplate, ulCount)) {
631 					rv = add_to_search_result(
632 					    obj, fcontext, &num_result_alloc);
633 				}
634 			} else {
635 				/* no search criteria, just record the object */
636 				rv = add_to_search_result(obj, fcontext,
637 				    &num_result_alloc);
638 			}
639 			(void) pthread_mutex_unlock(&obj->object_mutex);
640 			if (rv != CKR_OK) {
641 				(void) pthread_mutex_unlock(
642 				    &session_p->session_mutex);
643 				goto cleanup;
644 			}
645 			obj = obj->next;
646 		}
647 		(void) pthread_mutex_unlock(&session_p->session_mutex);
648 		session_p = session_p->next;
649 	}
650 
651 cleanup:
652 	/* Release the slot lock */
653 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
654 	return (rv);
655 }
656 
657 /*
658  * Initialize the context for C_FindObjects() calls
659  */
660 CK_RV
kms_find_objects_init(kms_session_t * sp,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)661 kms_find_objects_init(kms_session_t *sp, CK_ATTRIBUTE_PTR pTemplate,
662     CK_ULONG ulCount)
663 {
664 	CK_RV rv = CKR_OK;
665 	CK_OBJECT_CLASS class; /* for kms_validate_attr(). Value unused */
666 	find_context_t *fcontext;
667 
668 	if (ulCount) {
669 		rv = kms_validate_attr(pTemplate, ulCount, &class);
670 		/* Make sure all attributes in template are valid */
671 		if (rv != CKR_OK) {
672 			return (rv);
673 		}
674 	}
675 
676 	/* prepare the find context */
677 	fcontext = calloc(1, sizeof (find_context_t));
678 	if (fcontext == NULL) {
679 		return (CKR_HOST_MEMORY);
680 	}
681 
682 	rv = search_for_objects(sp, pTemplate, ulCount, fcontext);
683 	if (rv != CKR_OK) {
684 		free(fcontext);
685 		return (rv);
686 	}
687 
688 	/* store the find_context in the session */
689 	sp->find_objects.context = (CK_VOID_PTR)fcontext;
690 
691 	return (rv);
692 }
693 
694 void
kms_find_objects_final(kms_session_t * sp)695 kms_find_objects_final(kms_session_t *sp)
696 {
697 	find_context_t *fcontext;
698 
699 	fcontext = sp->find_objects.context;
700 	sp->find_objects.context = NULL;
701 	sp->find_objects.flags = 0;
702 	if (fcontext->objs_found != NULL) {
703 		free(fcontext->objs_found);
704 	}
705 
706 	free(fcontext);
707 }
708 
709 CK_RV
kms_find_objects(kms_session_t * sp,CK_OBJECT_HANDLE * obj_found,CK_ULONG max_obj_requested,CK_ULONG * found_obj_count)710 kms_find_objects(kms_session_t *sp, CK_OBJECT_HANDLE *obj_found,
711     CK_ULONG max_obj_requested, CK_ULONG *found_obj_count)
712 {
713 	find_context_t *fcontext;
714 	CK_ULONG num_obj_found = 0;
715 	CK_ULONG i;
716 	kms_object_t *obj;
717 
718 	fcontext = sp->find_objects.context;
719 
720 	for (i = fcontext->next_result_index;
721 	    ((num_obj_found < max_obj_requested) &&
722 	    (i < fcontext->num_results));
723 	    i++) {
724 		obj = fcontext->objs_found[i];
725 		if (obj != NULL) {
726 			(void) pthread_mutex_lock(&obj->object_mutex);
727 			/* a sanity check to make sure the obj is still valid */
728 			if (obj->magic_marker == KMSTOKEN_OBJECT_MAGIC) {
729 				obj_found[num_obj_found] =
730 				    (CK_OBJECT_HANDLE)obj;
731 				num_obj_found++;
732 			}
733 			(void) pthread_mutex_unlock(&obj->object_mutex);
734 		}
735 	}
736 	fcontext->next_result_index = i;
737 	*found_obj_count = num_obj_found;
738 	return (CKR_OK);
739 }
740 
741 /*
742  * Add an token object to the token object list in slot.
743  *
744  * This function will acquire the lock on the slot, and release
745  * that lock after adding the object to the slot's token object list.
746  */
747 void
kms_add_token_object_to_slot(kms_object_t * objp,kms_slot_t * pslot)748 kms_add_token_object_to_slot(kms_object_t *objp, kms_slot_t *pslot)
749 {
750 	/* Acquire the slot lock. */
751 	(void) pthread_mutex_lock(&pslot->sl_mutex);
752 
753 	/* Insert the new object in front of slot's token object list. */
754 	if (pslot->sl_tobj_list == NULL) {
755 		pslot->sl_tobj_list = objp;
756 		objp->next = NULL;
757 		objp->prev = NULL;
758 	} else {
759 		pslot->sl_tobj_list->prev = objp;
760 		objp->next = pslot->sl_tobj_list;
761 		objp->prev = NULL;
762 		pslot->sl_tobj_list = objp;
763 	}
764 
765 	/* Release the slot lock. */
766 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
767 }
768 
769 /*
770  * Remove an token object from the slot's token object list.
771  * This routine is called by kms_delete_token_object().
772  * The caller of this function hold the slot lock.
773  */
774 void
kms_remove_token_object_from_slot(kms_slot_t * pslot,kms_object_t * objp)775 kms_remove_token_object_from_slot(kms_slot_t *pslot,
776     kms_object_t *objp)
777 {
778 
779 	if (pslot->sl_tobj_list == objp) {
780 		/* Object is the first one in the list */
781 		if (objp->next) {
782 			pslot->sl_tobj_list = objp->next;
783 			objp->next->prev = NULL;
784 		} else {
785 			/* Object is the only one in the list. */
786 			pslot->sl_tobj_list = NULL;
787 		}
788 	} else {
789 		/* Object is not the first one in the list. */
790 		if (objp->next) {
791 			/* Object is in the middle of the list. */
792 			if (objp->prev)
793 				objp->prev->next = objp->next;
794 			objp->next->prev = objp->prev;
795 		} else if (objp->prev) {
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
kms_delete_token_object(kms_slot_t * pslot,kms_session_t * sp,kms_object_t * objp,boolean_t slot_lock_held,boolean_t wrapper_only)816 kms_delete_token_object(kms_slot_t *pslot, kms_session_t *sp,
817     kms_object_t *objp, boolean_t slot_lock_held, boolean_t wrapper_only)
818 {
819 	CK_RV rv = CKR_OK;
820 
821 	if (!slot_lock_held) {
822 		(void) pthread_mutex_lock(&pslot->sl_mutex);
823 	}
824 	if (!wrapper_only && objp->class == CKO_SECRET_KEY) {
825 		/* Delete from KMS */
826 		rv = KMS_DestroyKey(sp, objp);
827 	}
828 
829 	/* Remove the object from the slot's token object list first. */
830 	kms_remove_token_object_from_slot(pslot, objp);
831 
832 	/* Release the slot lock if the call doesn't hold the lock. */
833 	if (!slot_lock_held) {
834 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
835 	}
836 
837 	kms_delete_object_cleanup(objp, wrapper_only);
838 
839 	return (rv);
840 }
841 
842 /*
843  * Clean up private object wrappers in this slot. The caller holds the slot
844  * lock.
845  */
846 void
kms_cleanup_pri_objects_in_slot(kms_slot_t * pslot,kms_session_t * cur_sp)847 kms_cleanup_pri_objects_in_slot(kms_slot_t *pslot,
848     kms_session_t *cur_sp)
849 {
850 	kms_session_t *session_p;
851 	kms_object_t *objp;
852 	kms_object_t *objp1;
853 
854 	/*
855 	 * Delete every private token object from
856 	 * the slot token object list.
857 	 */
858 	(void) pthread_mutex_lock(&pslot->sl_mutex);
859 	objp = pslot->sl_tobj_list;
860 	while (objp) {
861 		objp1 = objp->next;
862 		/*
863 		 * The first TRUE boolean argument indicates that the caller
864 		 * hold the slot lock.  The second TRUE boolean argument
865 		 * indicates that the caller just wants to clean up the object
866 		 * wrapper from the library only.
867 		 */
868 		if (objp->bool_attr_mask & PRIVATE_BOOL_ON) {
869 			(void) kms_delete_token_object(pslot, cur_sp, objp,
870 			    B_TRUE, B_TRUE);
871 		}
872 		objp = objp1;
873 	}
874 
875 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
876 	/*
877 	 * Walk through all the sessions in this slot and delete every
878 	 * private object.
879 	 */
880 	session_p = pslot->sl_sess_list;
881 	while (session_p) {
882 
883 		/* Delete all the objects in the session. */
884 		objp = session_p->object_list;
885 		while (objp) {
886 			objp1 = objp->next;
887 			/*
888 			 * The FALSE boolean argument indicates that the
889 			 * caller does not hold the session lock.  The TRUE
890 			 * boolean argument indicates that the caller just
891 			 * want to clean upt the object wrapper from the
892 			 * library only.
893 			 */
894 			if (objp->bool_attr_mask & PRIVATE_BOOL_ON) {
895 				(void) kms_delete_object(session_p,
896 				    objp, B_FALSE, B_TRUE);
897 			}
898 			objp = objp1;
899 		}
900 
901 		session_p = session_p->next;
902 	}
903 }
904 
905 /*
906  * Get the object size in bytes for the objects created in the library.
907  */
908 CK_RV
kms_get_object_size(kms_object_t * obj,CK_ULONG_PTR pulSize)909 kms_get_object_size(kms_object_t *obj, CK_ULONG_PTR pulSize)
910 {
911 	CK_RV rv = CKR_OK;
912 	CK_ULONG obj_size;
913 
914 	obj_size = sizeof (kms_object_t);
915 
916 	switch (obj->class) {
917 	case CKO_SECRET_KEY:
918 		obj_size += OBJ_SEC_VALUE_LEN(obj);
919 		break;
920 
921 	default:
922 		rv = CKR_OBJECT_HANDLE_INVALID;
923 	}
924 
925 	if (rv == CKR_OK) {
926 		*pulSize = obj_size;
927 	}
928 
929 	return (rv);
930 }
931