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