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 */
25
26 /*
27 * Object Management Functions
28 * (as defined in PKCS#11 spec section 11.7)
29 */
30
31 #include <strings.h>
32 #include "metaGlobal.h"
33 #include <stdio.h>
34
35 #define FIND_OBJ_BUF_SIZE 512 /* size of buf used for C_FindObjects */
36
37 /*
38 * Argument related return codes. Will return to the caller immediately,
39 * and not try the operation on another slot.
40 */
41 static CK_RV stop_rv[] = {
42 CKR_ARGUMENTS_BAD,
43 CKR_ATTRIBUTE_TYPE_INVALID,
44 CKR_DOMAIN_PARAMS_INVALID,
45 CKR_TEMPLATE_INCOMPLETE
46 };
47 static int num_stop_rv = sizeof (stop_rv) / sizeof (CK_RV);
48
49 /*
50 * Return codes that are related to a specific slot.
51 * Will try to perform the operation in the next available slot.
52 * If all attempts failed, will return the error code from the first slot.
53 *
54 * This list is here for reference only, it is commented out because
55 * it doesn't need to be used by the code at this point.
56 *
57 * static CK_RV try_again_rv[] = {
58 * CKR_DEVICE_ERROR,
59 * CKR_DEVICE_MEMORY,
60 * CKR_DEVICE_REMOVED,
61 * CKR_FUNCTION_FAILED,
62 * CKR_GENERAL_ERROR,
63 * CKR_HOST_MEMORY,
64 * CKR_TEMPLATE_INCONSISTENT,
65 * CKR_ATTRIBUTE_READ_ONLY,
66 * CKR_ATTRIBUTE_VALUE_INVALID
67 * };
68 * static int num_try_again_rv = sizeof (try_again_rv) / sizeof (CK_RV);
69 */
70
71 /*
72 * We should never get these return codes because
73 * MetaSlot is the one that actually created the
74 * sessions. When we get these errors in C_CreateObject,
75 * will try to create the object in the next available slot.
76 * If all attempts failed, will return CKR_FUNCTION_FAILED
77 * to the caller.
78 */
79 static CK_RV other_rv[] = {
80 CKR_CRYPTOKI_NOT_INITIALIZED,
81 CKR_SESSION_CLOSED,
82 CKR_SESSION_HANDLE_INVALID,
83 CKR_SESSION_READ_ONLY
84 };
85 static int num_other_rv = sizeof (other_rv) / sizeof (CK_RV);
86
87 /*
88 * This function is only used by the C_CreateObject and C_CopyObject.
89 *
90 * It is used to determine if the operation should be tried on another slot
91 * based on the return code
92 */
93 static boolean_t
try_again(CK_RV rv)94 try_again(CK_RV rv)
95 {
96 int i;
97
98 for (i = 0; i < num_stop_rv; i++) {
99 if (rv == stop_rv[i]) {
100 return (B_FALSE);
101 }
102 }
103 return (B_TRUE);
104 }
105
106
107 /*
108 * meta_CreateObject
109 *
110 */
111 CK_RV
meta_CreateObject(CK_SESSION_HANDLE hSession,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_OBJECT_HANDLE_PTR phObject)112 meta_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
113 CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject)
114 {
115 CK_RV rv;
116 meta_session_t *session;
117 slot_session_t *slot_session = NULL;
118 meta_object_t *object = NULL;
119 slot_object_t *slot_object = NULL;
120 CK_OBJECT_HANDLE hNewObject;
121 CK_ULONG slot_num, keystore_slotnum;
122 CK_RV first_rv;
123
124 if (pTemplate == NULL || ulCount < 1 || phObject == NULL)
125 return (CKR_ARGUMENTS_BAD);
126
127 rv = meta_handle2session(hSession, &session);
128 if (rv != CKR_OK)
129 return (rv);
130
131 rv = meta_object_alloc(session, &object);
132 if (rv != CKR_OK)
133 goto cleanup;
134
135 /*
136 * Create a clone of the object
137 */
138 rv = meta_slot_object_alloc(&slot_object);
139 if (rv != CKR_OK)
140 goto cleanup;
141
142 /*
143 * Set to true (token object) if template has CKA_TOKEN=true;
144 * otherwise, it is false (session object).
145 */
146 (void) get_template_boolean(CKA_TOKEN, pTemplate, ulCount,
147 &(object->isToken));
148
149 /* Can't create token objects in a read-only session. */
150 if ((IS_READ_ONLY_SESSION(session->session_flags)) && object->isToken) {
151 rv = CKR_SESSION_READ_ONLY;
152 goto cleanup;
153 }
154
155 /*
156 * Set to true (private object) if template has CKA_PRIVATE=true;
157 * otherwise, it is false (public object).
158 */
159 (void) get_template_boolean(CKA_PRIVATE, pTemplate, ulCount,
160 &(object->isPrivate));
161
162 /* Assume object is extractable unless template has otherwise */
163 object->isExtractable = B_TRUE;
164 (void) get_template_boolean(CKA_EXTRACTABLE, pTemplate, ulCount,
165 &(object->isExtractable));
166
167 /*
168 * Set to true (sensitive object) if template has CKA_SENSITIVE=true;
169 * otherwise, it is false.
170 */
171 (void) get_template_boolean(CKA_SENSITIVE, pTemplate, ulCount,
172 &(object->isSensitive));
173
174 /*
175 * Check if this can be a FreeObject.
176 *
177 * For creating objects, this check is mostly for preventing
178 * non-keystore hardware from creating CKA_PRIVATE objects without
179 * logging in.
180 */
181
182 if (meta_freeobject_check(session, object, NULL, pTemplate, ulCount,
183 0)) {
184 /*
185 * Make sure we are logged into the keystore if this is a
186 * private freetoken object.
187 */
188 if (object->isPrivate && !metaslot_logged_in())
189 return (CKR_USER_NOT_LOGGED_IN);
190
191 if (!meta_freeobject_set(object, pTemplate, ulCount, B_TRUE))
192 goto cleanup;
193 }
194
195
196 keystore_slotnum = get_keystore_slotnum();
197
198 if (object->isToken || object->isFreeToken == FREE_ENABLED) {
199
200 /*
201 * If this is a token object or a FreeToken then create it
202 * on the keystore slot.
203 */
204
205 slot_num = keystore_slotnum;
206 rv = meta_get_slot_session(slot_num, &slot_session,
207 session->session_flags);
208 if (rv != CKR_OK)
209 goto cleanup;
210
211 object->tried_create_clone[slot_num] = B_TRUE;
212 rv = FUNCLIST(slot_session->fw_st_id)->C_CreateObject(
213 slot_session->hSession, pTemplate, ulCount, &hNewObject);
214
215 if (rv != CKR_OK)
216 goto cleanup;
217
218 } else {
219
220 /*
221 * Create a clone of the object in the first available slot.
222 *
223 * If creating a clone in a specific slot failed, it will
224 * either stop and return the error to the user, or try
225 * again in the next available slot until it succeeds. The
226 * decision to stop or continue is made based on the return
227 * code.
228 */
229 CK_ULONG num_slots = meta_slotManager_get_slotcount();
230
231 for (slot_num = 0; slot_num < num_slots; slot_num++) {
232 /*
233 * If this is a free token and we are on the keystore
234 * slot, bypass this because it was already created
235 */
236
237 rv = meta_get_slot_session(slot_num, &slot_session,
238 session->session_flags);
239 if (rv != CKR_OK)
240 goto cleanup;
241
242 object->tried_create_clone[slot_num] = B_TRUE;
243 rv = FUNCLIST(slot_session->fw_st_id)->C_CreateObject(
244 slot_session->hSession, pTemplate, ulCount,
245 &hNewObject);
246 if (rv == CKR_OK)
247 break;
248
249 if (!try_again(rv))
250 goto cleanup;
251
252 /* save first rv for other errors */
253 if (slot_num == 0)
254 first_rv = rv;
255
256 meta_release_slot_session(slot_session);
257 slot_session = NULL;
258
259 }
260 }
261
262 if (rv == CKR_OK) {
263 slot_object->hObject = hNewObject;
264 object->clones[slot_num] = slot_object;
265 object->master_clone_slotnum = slot_num;
266
267 /* Allow FreeToken to activate onto token obj list */
268 if (object->isFreeToken == FREE_ENABLED)
269 object->isToken = B_TRUE;
270
271 meta_slot_object_activate(slot_object, slot_session,
272 object->isToken);
273
274 slot_object = NULL;
275 meta_release_slot_session(slot_session);
276 slot_session = NULL;
277
278 } else {
279 /*
280 * return either first error code or
281 * CKR_FUNCTION_FAILED depending on the failure
282 */
283 int i;
284 for (i = 0; i < num_other_rv; i++) {
285 if (rv == other_rv[i]) {
286 rv = CKR_FUNCTION_FAILED;
287 goto cleanup;
288 }
289 }
290 /* need to return first rv */
291 rv = first_rv;
292 goto cleanup;
293 }
294
295
296 /*
297 * always keep a copy of the template for C_CreateObject,
298 * so clones can be created on other slots if necessary.
299 * This is done even when the CKA_EXTRACTABLE=FALSE flag
300 * is set for the object. The supplied template is
301 * "owned" by metaslot. The application should not be
302 * penalized just because metaslot choose to try creating
303 * the object in a slot that's not capable of performing
304 * any future operation.
305 */
306 rv = get_master_attributes_by_template(pTemplate, ulCount,
307 &object->attributes, &object->num_attributes);
308 if (rv == CKR_OK) {
309 CK_ULONG i;
310 for (i = 0; i < ulCount; i++) {
311 rv = attribute_set_value(&(pTemplate[i]),
312 object->attributes, object->num_attributes);
313 }
314 }
315
316 meta_object_activate(object);
317 *phObject = (CK_OBJECT_HANDLE) object;
318
319 REFRELEASE(session);
320
321 return (CKR_OK);
322
323 cleanup:
324 if (slot_object)
325 meta_slot_object_dealloc(slot_object);
326 if (slot_session)
327 meta_release_slot_session(slot_session);
328 if (object)
329 (void) meta_object_dealloc(session, object, B_TRUE);
330
331 REFRELEASE(session);
332
333 return (rv);
334 }
335
336
337 /*
338 * meta_CopyObject
339 *
340 */
341 CK_RV
meta_CopyObject(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_OBJECT_HANDLE_PTR phNewObject)342 meta_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
343 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
344 CK_OBJECT_HANDLE_PTR phNewObject)
345 {
346 CK_RV rv, first_rv;
347 meta_session_t *session;
348 meta_object_t *src_object, *dst_object = NULL;
349 slot_session_t *slot_session = NULL;
350 slot_object_t *dst_slot_object = NULL;
351 CK_ULONG i;
352 slot_object_t *src_slot_object;
353 CK_ULONG slotnum, num_slots;
354 boolean_t found;
355
356 if (pTemplate == NULL && ulCount != 0)
357 return (CKR_ARGUMENTS_BAD);
358 if (phNewObject == NULL)
359 return (CKR_ARGUMENTS_BAD);
360
361 rv = meta_handle2session(hSession, &session);
362 if (rv != CKR_OK)
363 return (rv);
364
365 rv = meta_handle2object(hObject, &src_object);
366 if (rv != CKR_OK) {
367 REFRELEASE(session);
368 return (rv);
369 }
370
371 rv = meta_object_alloc(session, &dst_object);
372 if (rv != CKR_OK)
373 goto finish;
374
375 found = get_template_boolean(CKA_TOKEN,
376 pTemplate, ulCount, &(dst_object->isToken));
377 if (!found) {
378 dst_object->isToken = src_object->isToken;
379 if (src_object->isFreeToken == FREE_ENABLED)
380 dst_object->isToken = TRUE;
381 else
382 dst_object->isToken = src_object->isToken;
383 }
384
385 /* Can't create token objects in a read-only session. */
386 if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
387 (dst_object->isToken)) {
388 rv = CKR_SESSION_READ_ONLY;
389 goto finish;
390 }
391
392 if (dst_object->isToken) {
393
394 /*
395 * if the dst object is a token object, and the source
396 * object is not, the source object needs to be extractable.
397 * Otherwise, the source object needs to reside in the
398 * token object slot
399 */
400 if ((!src_object->isExtractable) &&
401 (src_object->master_clone_slotnum
402 != get_keystore_slotnum())) {
403 rv = CKR_FUNCTION_FAILED;
404 goto finish;
405 }
406
407 /* determine if dst is going to be private object or not */
408 found = get_template_boolean(CKA_PRIVATE,
409 pTemplate, ulCount, &(dst_object->isPrivate));
410 if (!found) {
411 /* will be the same as the source object */
412 dst_object->isPrivate = src_object->isPrivate;
413 }
414
415 slotnum = get_keystore_slotnum();
416 } else {
417
418 /* try create the obj in the same slot as the source obj */
419 slotnum = src_object->master_clone_slotnum;
420 }
421
422 rv = meta_slot_object_alloc(&dst_slot_object);
423 if (rv != CKR_OK)
424 goto finish;
425
426 rv = meta_get_slot_session(slotnum, &slot_session,
427 session->session_flags);
428 if (rv != CKR_OK)
429 goto finish;
430
431 rv = meta_object_get_clone(src_object, slotnum,
432 slot_session, &src_slot_object);
433 if (rv != CKR_OK)
434 goto finish;
435
436 dst_object->tried_create_clone[slotnum] = B_TRUE;
437 rv = FUNCLIST(slot_session->fw_st_id)->C_CopyObject(
438 slot_session->hSession, src_slot_object->hObject, pTemplate,
439 ulCount, &(dst_slot_object->hObject));
440
441 if (rv != CKR_OK) {
442 if (dst_object->isToken) {
443 /*
444 * token obj can only be created in the
445 * token slot. No need to try anywhere else
446 */
447 goto finish;
448 }
449 if ((!src_object->isExtractable) ||
450 ((src_object->isSensitive) && (src_object->isToken) &&
451 (!metaslot_auto_key_migrate))) {
452 /* source object isn't clonable in another slot */
453 goto finish;
454 }
455
456 if (!try_again(rv)) {
457 goto finish;
458 }
459
460 first_rv = rv;
461
462 meta_release_slot_session(slot_session);
463 slot_session = NULL;
464
465 num_slots = meta_slotManager_get_slotcount();
466
467 /* Try operation on other slots if the object is clonable */
468 for (slotnum = 0; slotnum < num_slots; slotnum++) {
469
470 if (slotnum == src_object->master_clone_slotnum) {
471 /* already tried, don't need to try again */
472 continue;
473 }
474
475 rv = meta_get_slot_session(slotnum, &slot_session,
476 session->session_flags);
477 if (rv != CKR_OK) {
478 goto finish;
479 }
480
481 rv = meta_object_get_clone(src_object, slotnum,
482 slot_session, &src_slot_object);
483 if (rv != CKR_OK)
484 goto finish;
485
486 dst_object->tried_create_clone[slotnum] = B_TRUE;
487
488 rv = FUNCLIST(slot_session->fw_st_id)->C_CopyObject(
489 slot_session->hSession, src_slot_object->hObject,
490 pTemplate, ulCount, &dst_slot_object->hObject);
491
492 if (rv == CKR_OK) {
493 break;
494 }
495
496 if (!try_again(rv)) {
497 goto finish;
498 }
499 meta_release_slot_session(slot_session);
500 slot_session = NULL;
501 }
502 }
503
504 if (rv == CKR_OK) {
505
506 rv = meta_object_get_attr(slot_session,
507 dst_slot_object->hObject, dst_object);
508 if (rv != CKR_OK) {
509 goto finish;
510 }
511
512 if (src_object->attributes != NULL) {
513
514 /* Keep a copy of the template for the future */
515
516 /*
517 * Don't allow attributes to change while
518 * we look at them.
519 */
520 (void) pthread_rwlock_rdlock(
521 &src_object->attribute_lock);
522
523 rv = get_master_attributes_by_duplication(
524 src_object->attributes,
525 src_object->num_attributes,
526 &dst_object->attributes,
527 &dst_object->num_attributes);
528
529 (void) pthread_rwlock_unlock(
530 &src_object->attribute_lock);
531
532 if (rv != CKR_OK)
533 goto finish;
534
535 for (i = 0; i < ulCount; i++) {
536 rv = attribute_set_value(pTemplate + i,
537 dst_object->attributes,
538 dst_object->num_attributes);
539
540 if (rv != CKR_OK)
541 goto finish;
542 }
543 }
544
545 /* Allow FreeToken to activate onto token obj list */
546 if (dst_object->isFreeToken == FREE_ENABLED)
547 dst_object->isToken = TRUE;
548
549 meta_slot_object_activate(dst_slot_object,
550 slot_session, dst_object->isToken);
551
552 dst_object->clones[slotnum] = dst_slot_object;
553 dst_object->master_clone_slotnum = slotnum;
554 dst_slot_object = NULL; /* for error cleanup */
555
556 meta_release_slot_session(slot_session);
557 slot_session = NULL; /* for error cleanup */
558
559 } else {
560 /*
561 * return either first error code or
562 * CKR_FUNCTION_FAILED depending on the failure
563 */
564 int j;
565 for (j = 0; j < num_other_rv; j++) {
566 if (rv == other_rv[j]) {
567 rv = CKR_FUNCTION_FAILED;
568 goto finish;
569 }
570 }
571 /* need to return first rv */
572 rv = first_rv;
573 goto finish;
574 }
575 meta_object_activate(dst_object);
576 *phNewObject = (CK_OBJECT_HANDLE) dst_object;
577
578 finish:
579 if (rv != CKR_OK) {
580 if (dst_slot_object)
581 meta_slot_object_dealloc(dst_slot_object);
582
583 if (dst_object)
584 (void) meta_object_dealloc(session, dst_object,
585 B_TRUE);
586
587 if (slot_session)
588 meta_release_slot_session(slot_session);
589 }
590
591 OBJRELEASE(src_object);
592 REFRELEASE(session);
593
594 return (rv);
595 }
596
597
598 /*
599 * meta_DestroyObject
600 *
601 * This function destroys an object by first removing it from the
602 * list of valid objects for a given session (if session object) or
603 * the global token object list. And then, calling C_DestroyObject
604 * on all the slots on which we have created a clone of this object.
605 */
606 CK_RV
meta_DestroyObject(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject)607 meta_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
608 {
609 CK_RV rv;
610 meta_session_t *session;
611 meta_object_t *object;
612
613 rv = meta_handle2session(hSession, &session);
614 if (rv != CKR_OK)
615 return (rv);
616
617 rv = meta_handle2object(hObject, &object);
618 if (rv != CKR_OK) {
619 REFRELEASE(session);
620 return (rv);
621 }
622
623 /* Can't delete token objects from a read-only session. */
624 if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
625 (object->isToken || object->isFreeToken == FREE_ENABLED)) {
626 OBJRELEASE(object);
627 REFRELEASE(session);
628 return (CKR_SESSION_READ_ONLY);
629 }
630
631 /* Remove object from list of valid meta_objects */
632 rv = meta_object_deactivate(object, B_FALSE, B_TRUE);
633
634 /*
635 * Actually call C_DestroyObject on all the slots on which we have
636 * created a clone of this object.
637 */
638 if (rv == CKR_OK)
639 rv = meta_object_dealloc(session, object, B_TRUE);
640
641 REFRELEASE(session);
642
643 return (rv);
644 }
645
646
647 /*
648 * meta_GetObjectSize
649 *
650 * NOTES:
651 * 1) Because the "size" is so poorly defined in the spec, we have deemed
652 * it useless and won't support it. This is especially true for the
653 * metaslot, because the mulitple providers it uses may each interpret
654 * the size differently.
655 */
656 /* ARGSUSED */
657 CK_RV
meta_GetObjectSize(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ULONG_PTR pulSize)658 meta_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
659 CK_ULONG_PTR pulSize)
660 {
661 return (CKR_FUNCTION_NOT_SUPPORTED);
662 }
663
664
665 /*
666 * meta_GetAttributeValue
667 *
668 */
669 CK_RV
meta_GetAttributeValue(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)670 meta_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
671 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
672 {
673 CK_RV rv;
674 meta_session_t *session;
675 meta_object_t *object;
676 CK_ULONG slotnum;
677 slot_session_t *slot_session;
678
679 if (pTemplate == NULL || ulCount < 1)
680 return (CKR_ARGUMENTS_BAD);
681
682 rv = meta_handle2session(hSession, &session);
683 if (rv != CKR_OK)
684 return (rv);
685
686 rv = meta_handle2object(hObject, &object);
687 if (rv != CKR_OK) {
688 REFRELEASE(session);
689 return (rv);
690 }
691
692 slotnum = object->master_clone_slotnum;
693
694 rv = meta_get_slot_session(slotnum, &slot_session,
695 session->session_flags);
696 if (rv == CKR_OK) {
697 rv = FUNCLIST(slot_session->fw_st_id)->C_GetAttributeValue(
698 slot_session->hSession, object->clones[slotnum]->hObject,
699 pTemplate, ulCount);
700
701 meta_release_slot_session(slot_session);
702 }
703
704 OBJRELEASE(object);
705 REFRELEASE(session);
706
707 return (rv);
708
709 }
710
711
712 /*
713 * meta_SetAttributeValue
714 *
715 * Call C_SetAttributeValue on all the clones. If the operation fails on
716 * all clones, return the failure.
717 *
718 * If the operation fails on some clones and not the others, delete all the
719 * clones that have failed the operation. If any of the deleted clone is the
720 * master clone, use one of the remaining clone as the master clone.
721 *
722 * If the operation is successful and the master template already exists,
723 * update the master template with new values.
724 */
725 CK_RV
meta_SetAttributeValue(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)726 meta_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
727 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
728 {
729 CK_RV rv = CKR_OK, save_rv = CKR_OK;
730 meta_session_t *session;
731 meta_object_t *object;
732 CK_ULONG slotnum, num_slots;
733 /* Keep track of which slot's SetAttributeValue failed */
734 boolean_t *clone_failed_op = NULL;
735 int num_clones = 0, num_clones_failed = 0;
736 slot_session_t *slot_session;
737 slot_object_t *slot_object;
738 boolean_t need_update_master_clone = B_FALSE;
739
740 if (pTemplate == NULL || ulCount < 1)
741 return (CKR_ARGUMENTS_BAD);
742
743 rv = meta_handle2session(hSession, &session);
744 if (rv != CKR_OK)
745 return (rv);
746
747 rv = meta_handle2object(hObject, &object);
748 if (rv != CKR_OK) {
749 REFRELEASE(session);
750 return (rv);
751 }
752
753 if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
754 (object->isToken || object->isFreeToken == FREE_ENABLED)) {
755 rv = CKR_SESSION_READ_ONLY;
756 goto finish;
757 }
758
759 if ((!object->isExtractable) && (object->attributes == NULL)) {
760 /*
761 * object has no clone, just need to do the operation
762 * in the master clone slot
763 */
764 slot_session_t *slot_session;
765 slotnum = object->master_clone_slotnum;
766
767 rv = meta_get_slot_session(slotnum, &slot_session,
768 session->session_flags);
769 if (rv == CKR_OK) {
770 rv = FUNCLIST(slot_session->fw_st_id)->\
771 C_SetAttributeValue(slot_session->hSession,
772 object->clones[slotnum]->hObject, pTemplate,
773 ulCount);
774
775 meta_release_slot_session(slot_session);
776 }
777 goto finish;
778 }
779
780
781 num_slots = meta_slotManager_get_slotcount();
782
783 /*
784 * object might have clones, need to do operation in all clones
785 *
786 * If the C_SetAttributeValue() call fails in a clone, the
787 * clone that failed the operation can not be deleted right
788 * away. The clone with the failed operation is recorded, and
789 * the deletion will happen in a separate loop.
790 *
791 * This is necessary because if ALL the clones failed
792 * C_SetAttributeVAlue(), then, the app's call to C_SetAttributeValue()
793 * is considered failed, and there shouldn't be any changes to the
794 * object, none of the clones should be deleted.
795 * On the other hand, if C_SetAttributeValue() fails in some clones
796 * and succeeds in other clones, the C_SetAttributeValue() operation
797 * is considered successful, and those clones that failed the
798 * operation is deleted.
799 */
800 clone_failed_op = calloc(num_slots, sizeof (boolean_t));
801 if (clone_failed_op == NULL) {
802 rv = CKR_HOST_MEMORY;
803 goto finish;
804 }
805 for (slotnum = 0; slotnum < num_slots; slotnum++) {
806 if (object->clones[slotnum] != NULL) {
807 num_clones++;
808 rv = meta_get_slot_session(slotnum, &slot_session,
809 session->session_flags);
810 if (rv != CKR_OK) {
811 goto finish;
812 }
813
814 rv = FUNCLIST(slot_session->fw_st_id)->\
815 C_SetAttributeValue(slot_session->hSession,
816 object->clones[slotnum]->hObject, pTemplate,
817 ulCount);
818
819 if (rv != CKR_OK) {
820 num_clones_failed++;
821 clone_failed_op[slotnum] = B_TRUE;
822 if (save_rv == CKR_OK) {
823 save_rv = rv;
824 }
825 }
826 meta_release_slot_session(slot_session);
827 }
828 }
829
830 if (num_clones_failed == num_clones) {
831 /* all operations failed */
832 rv = save_rv;
833 goto finish;
834 }
835
836 if (num_clones_failed > 0) {
837 /*
838 * C_SetAttributeValue in some of the clones failed.
839 * Find out which ones failed, and delete the clones
840 * in those failed slots
841 */
842 for (slotnum = 0; slotnum < num_slots; slotnum++) {
843 if (clone_failed_op[slotnum]) {
844
845 slot_object_t *clone = object->clones[slotnum];
846
847 rv = meta_get_slot_session(slotnum,
848 &slot_session, session->session_flags);
849 if (rv == CKR_OK) {
850 (void) FUNCLIST(
851 slot_session->fw_st_id)->
852 C_DestroyObject(
853 slot_session->hSession,
854 clone->hObject);
855
856 meta_release_slot_session(slot_session);
857
858 }
859
860 meta_slot_object_deactivate(clone);
861 meta_slot_object_dealloc(clone);
862 object->clones[slotnum] = NULL;
863
864 if (slotnum == object->master_clone_slotnum) {
865 need_update_master_clone = B_TRUE;
866 }
867 }
868 }
869
870 if (need_update_master_clone) {
871 /* make first available clone the master */
872 for (slotnum = 0; slotnum < num_slots; slotnum++) {
873 if (object->clones[slotnum]) {
874 object->master_clone_slotnum = slotnum;
875 need_update_master_clone = B_FALSE;
876 break;
877 }
878 }
879
880 }
881 if (need_update_master_clone) {
882 /*
883 * something is very wrong, can't continue
884 * it should never be this case.
885 */
886 rv = CKR_FUNCTION_FAILED;
887 goto finish;
888 }
889 rv = CKR_OK;
890 }
891
892 /*
893 * Update the attribute information we keep in our metaslot object
894 */
895 slot_object = object->clones[object->master_clone_slotnum];
896 rv = meta_get_slot_session(object->master_clone_slotnum,
897 &slot_session, session->session_flags);
898 if (rv == CKR_OK) {
899 (void) meta_object_get_attr(slot_session,
900 slot_object->hObject, object);
901 meta_release_slot_session(slot_session);
902 }
903
904 /* if there's a copy of the attributes, keep it up to date */
905 if (object->attributes != NULL) {
906
907 CK_ULONG i;
908
909 /* Make sure no one else is looking at attributes. */
910 (void) pthread_rwlock_wrlock(&object->attribute_lock);
911
912 for (i = 0; i < ulCount; i++) {
913 (void) attribute_set_value(pTemplate + i,
914 object->attributes, object->num_attributes);
915
916 }
917 (void) pthread_rwlock_unlock(&object->attribute_lock);
918 }
919
920 finish:
921 if (clone_failed_op) {
922 free(clone_failed_op);
923 }
924 OBJRELEASE(object);
925 REFRELEASE(session);
926
927 return (rv);
928 }
929
930 static boolean_t
meta_object_in_list(meta_object_t * obj,meta_object_t ** objs_list,int num_objs)931 meta_object_in_list(meta_object_t *obj, meta_object_t **objs_list, int num_objs)
932 {
933 int i;
934
935 for (i = 0; i < num_objs; i++) {
936 if (objs_list[i] == obj) {
937 return (B_TRUE);
938 }
939 }
940 return (B_FALSE);
941 }
942
943 static CK_RV
add_to_search_result(meta_object_t * object,find_objs_info_t * info,int * num_results_alloc)944 add_to_search_result(meta_object_t *object, find_objs_info_t *info,
945 int *num_results_alloc)
946 {
947 /*
948 * allocate space for storing results if the currently
949 * allocated space is not enough
950 */
951 if (*num_results_alloc <= info->num_matched_objs) {
952 *num_results_alloc += FIND_OBJ_BUF_SIZE;
953 info->matched_objs = realloc(info->matched_objs,
954 sizeof (meta_object_t *) * (*num_results_alloc));
955 if (info->matched_objs == NULL) {
956 return (CKR_HOST_MEMORY);
957 }
958 }
959 (info->matched_objs)[(info->num_matched_objs)++] = object;
960 return (CKR_OK);
961 }
962
963 static CK_RV
process_find_results(CK_OBJECT_HANDLE * results,CK_ULONG num_results,int * num_results_allocated,find_objs_info_t * info,CK_ULONG slotnum,boolean_t token_only,slot_session_t * slot_session,meta_session_t * session)964 process_find_results(CK_OBJECT_HANDLE *results, CK_ULONG num_results,
965 int *num_results_allocated, find_objs_info_t *info, CK_ULONG slotnum,
966 boolean_t token_only, slot_session_t *slot_session,
967 meta_session_t *session)
968 {
969 CK_ULONG i;
970 meta_object_t *object;
971 CK_RV rv;
972
973 for (i = 0; i < num_results; i++) {
974
975 object = meta_object_find_by_handle(results[i], slotnum,
976 token_only);
977
978 /*
979 * a token object is found from the keystore,
980 * need to create a meta object for it
981 */
982 if (object == NULL) {
983 slot_object_t *slot_object;
984
985 rv = meta_object_alloc(session, &object);
986 if (rv != CKR_OK) {
987 return (rv);
988 }
989
990 rv = meta_slot_object_alloc(&slot_object);
991 if (rv != CKR_OK) {
992 (void) meta_object_dealloc(session, object,
993 B_TRUE);
994 return (rv);
995 }
996
997 slot_object->hObject = results[i];
998 object->master_clone_slotnum = slotnum;
999 object->clones[slotnum] = slot_object;
1000
1001 /* get in the attributes we keep in meta_object */
1002
1003 rv = meta_object_get_attr(slot_session,
1004 slot_object->hObject, object);
1005 if (rv != CKR_OK) {
1006 (void) meta_object_dealloc(session, object,
1007 B_TRUE);
1008 return (rv);
1009 }
1010
1011 meta_slot_object_activate(slot_object, slot_session,
1012 B_TRUE);
1013 meta_object_activate(object);
1014 slot_object = NULL;
1015 }
1016
1017 if (!meta_object_in_list(object, info->matched_objs,
1018 info->num_matched_objs)) {
1019 rv = add_to_search_result(object, info,
1020 num_results_allocated);
1021 if (rv != CKR_OK) {
1022 return (rv);
1023 }
1024 }
1025 }
1026 return (CKR_OK);
1027 }
1028
1029 static CK_RV
meta_search_for_objects(meta_session_t * session,find_objs_info_t * info,slot_session_t * slot_session,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_ULONG slotnum,boolean_t token_only,int * num_results_alloc)1030 meta_search_for_objects(meta_session_t *session, find_objs_info_t *info,
1031 slot_session_t *slot_session, CK_ATTRIBUTE_PTR pTemplate,
1032 CK_ULONG ulCount, CK_ULONG slotnum, boolean_t token_only,
1033 int *num_results_alloc)
1034 {
1035 CK_ULONG tmp_num_results;
1036 CK_OBJECT_HANDLE tmp_results[FIND_OBJ_BUF_SIZE];
1037 CK_SESSION_HANDLE hSession = slot_session->hSession;
1038 CK_RV rv;
1039 CK_SLOT_ID fw_st_id = slot_session->fw_st_id;
1040
1041 rv = FUNCLIST(fw_st_id)->C_FindObjectsInit(hSession,
1042 pTemplate, ulCount);
1043
1044 if (rv != CKR_OK) {
1045 return (rv);
1046 }
1047
1048 tmp_num_results = 0;
1049 rv = FUNCLIST(fw_st_id)->C_FindObjects(hSession, tmp_results,
1050 FIND_OBJ_BUF_SIZE, &tmp_num_results);
1051 if (rv != CKR_OK) {
1052 return (rv);
1053 }
1054
1055 rv = process_find_results(tmp_results, tmp_num_results,
1056 num_results_alloc, info, slotnum, token_only,
1057 slot_session, session);
1058 if (rv != CKR_OK) {
1059 return (rv);
1060 }
1061
1062 while (tmp_num_results == FIND_OBJ_BUF_SIZE) {
1063 /* might be more results, need to call C_FindObjects again */
1064 rv = FUNCLIST(fw_st_id)->C_FindObjects(hSession, tmp_results,
1065 FIND_OBJ_BUF_SIZE, &tmp_num_results);
1066 if (rv != CKR_OK) {
1067 return (rv);
1068 }
1069
1070 rv = process_find_results(tmp_results, tmp_num_results,
1071 num_results_alloc, info, slotnum, token_only,
1072 slot_session, session);
1073 if (rv != CKR_OK) {
1074 return (rv);
1075 }
1076 }
1077
1078 rv = FUNCLIST(fw_st_id)->C_FindObjectsFinal(hSession);
1079 return (rv);
1080 }
1081
1082
1083 /*
1084 * meta_FindObjectsInit
1085 *
1086 * This function actually will do ALL the work of searching for objects
1087 * that match all requirements specified in the template.
1088 *
1089 * Objects that matched the template will be stored in the
1090 * session's data structure. When the subsequent C_FindObjects()
1091 * calls are made, results saved will be returned.
1092 *
1093 */
1094 CK_RV
meta_FindObjectsInit(CK_SESSION_HANDLE hSession,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)1095 meta_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
1096 CK_ULONG ulCount)
1097 {
1098 CK_RV rv;
1099 meta_session_t *session;
1100 CK_ULONG slot_num = 0;
1101 boolean_t have_token_attr, tokenTrue = B_FALSE;
1102 slot_session_t *slot_find_session = NULL;
1103 int num_results_allocated = 0;
1104 CK_ULONG keystore_slotnum;
1105
1106 rv = meta_handle2session(hSession, &session);
1107 if (rv != CKR_OK)
1108 return (rv);
1109
1110 if ((session->find_objs_info).op_active) {
1111 REFRELEASE(session);
1112 return (CKR_OPERATION_ACTIVE);
1113 }
1114
1115 (session->find_objs_info).op_active = B_TRUE;
1116
1117 REFRELEASE(session);
1118
1119 /* see if the template indicates token object only or not */
1120 have_token_attr = get_template_boolean(CKA_TOKEN, pTemplate, ulCount,
1121 &tokenTrue);
1122
1123 keystore_slotnum = get_keystore_slotnum();
1124
1125 if (have_token_attr && tokenTrue) {
1126
1127
1128 /*
1129 * only interested in token objects, just need to search
1130 * token object slot
1131 */
1132 rv = meta_get_slot_session(keystore_slotnum,
1133 &slot_find_session, session->session_flags);
1134 if (rv != CKR_OK) {
1135 goto finish;
1136 }
1137 rv = meta_search_for_objects(session,
1138 &(session->find_objs_info), slot_find_session, pTemplate,
1139 ulCount, keystore_slotnum, B_TRUE, &num_results_allocated);
1140 if (rv != CKR_OK) {
1141 goto finish;
1142 }
1143 } else {
1144 CK_ULONG num_slots = meta_slotManager_get_slotcount();
1145 for (slot_num = 0; slot_num < num_slots; slot_num++) {
1146 rv = meta_get_slot_session(slot_num,
1147 &slot_find_session, session->session_flags);
1148 if (rv != CKR_OK) {
1149 goto finish;
1150 }
1151
1152 /*
1153 * if the slot is NOT the token object slot, and
1154 * CKA_TOKEN is not specified, need to specified
1155 * it to be false explicitly. This will prevent
1156 * us from using token objects that doesn't
1157 * belong to the token slot in the case that
1158 * more than one slot supports token objects.
1159 */
1160
1161 if ((slot_num != keystore_slotnum) &&
1162 (!have_token_attr)) {
1163 CK_BBOOL false = FALSE;
1164 CK_ATTRIBUTE_PTR newTemplate;
1165
1166 newTemplate = malloc((ulCount + 1) *
1167 sizeof (CK_ATTRIBUTE));
1168 if (newTemplate == NULL) {
1169 rv = CKR_HOST_MEMORY;
1170 goto finish;
1171 }
1172 (void) memcpy(newTemplate + 1, pTemplate,
1173 ulCount * sizeof (CK_ATTRIBUTE));
1174 newTemplate[0].type = CKA_TOKEN;
1175 newTemplate[0].pValue = &false;
1176 newTemplate[0].ulValueLen = sizeof (false);
1177
1178 rv = meta_search_for_objects(session,
1179 &(session->find_objs_info),
1180 slot_find_session, newTemplate,
1181 ulCount+1, slot_num, B_FALSE,
1182 &num_results_allocated);
1183 free(newTemplate);
1184 } else {
1185 rv = meta_search_for_objects(session,
1186 &(session->find_objs_info),
1187 slot_find_session, pTemplate, ulCount,
1188 slot_num, B_FALSE,
1189 &num_results_allocated);
1190 }
1191
1192 if (rv != CKR_OK) {
1193 goto finish;
1194 }
1195 meta_release_slot_session(slot_find_session);
1196 slot_find_session = NULL;
1197 }
1198 }
1199
1200 finish:
1201 if (slot_find_session != NULL) {
1202 meta_release_slot_session(slot_find_session);
1203 }
1204 if (rv != CKR_OK) {
1205 (void) pthread_rwlock_wrlock(&session->session_lock);
1206 if (((session->find_objs_info).matched_objs) != NULL) {
1207 free((session->find_objs_info).matched_objs);
1208 }
1209 bzero(&(session->find_objs_info), sizeof (find_objs_info_t));
1210 (void) pthread_rwlock_unlock(&(session->session_lock));
1211 }
1212
1213 return (rv);
1214 }
1215
1216 /*
1217 * meta_FindObjects
1218 *
1219 * This function actually doesn't do any real work in search for the
1220 * matching object. All the work is done in FindObjectsInit(). This
1221 * function will only return the matching objects store in the session's
1222 * "find_objs_info" variable.
1223 *
1224 */
1225 CK_RV
meta_FindObjects(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE_PTR phObject,CK_ULONG ulMaxObjectCount,CK_ULONG_PTR pulObjectCount)1226 meta_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject,
1227 CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount)
1228 {
1229 CK_RV rv;
1230 find_objs_info_t *info;
1231 CK_ULONG num_objs_found = 0;
1232 meta_object_t *obj;
1233 meta_session_t *session;
1234 int i;
1235
1236 rv = meta_handle2session(hSession, &session);
1237 if (rv != CKR_OK)
1238 return (rv);
1239
1240 info = &(session->find_objs_info);
1241
1242 if (!(info->op_active)) {
1243 REFRELEASE(session);
1244 return (CKR_OPERATION_NOT_INITIALIZED);
1245 }
1246
1247 for (i = info->next_result_index;
1248 ((num_objs_found < ulMaxObjectCount) &&
1249 (i < info->num_matched_objs));
1250 i++) {
1251 obj = info->matched_objs[i];
1252 if (obj != NULL) {
1253 /* sanity check to see if object is still valid */
1254 (void) pthread_rwlock_rdlock(&obj->object_lock);
1255 if (obj->magic_marker == METASLOT_OBJECT_MAGIC) {
1256 phObject[num_objs_found++] =
1257 (CK_OBJECT_HANDLE)obj;
1258 }
1259 (void) pthread_rwlock_unlock(&obj->object_lock);
1260 }
1261 }
1262 info->next_result_index = i;
1263 *pulObjectCount = num_objs_found;
1264 REFRELEASE(session);
1265 return (rv);
1266 }
1267
1268
1269 /*
1270 * meta_FindObjectsFinal
1271 *
1272 */
1273 CK_RV
meta_FindObjectsFinal(CK_SESSION_HANDLE hSession)1274 meta_FindObjectsFinal(CK_SESSION_HANDLE hSession)
1275 {
1276 CK_RV rv;
1277 find_objs_info_t *info;
1278 meta_session_t *session;
1279
1280 rv = meta_handle2session(hSession, &session);
1281 if (rv != CKR_OK)
1282 return (rv);
1283
1284 info = &(session->find_objs_info);
1285
1286 if (!info->op_active) {
1287 REFRELEASE(session);
1288 return (CKR_OPERATION_NOT_INITIALIZED);
1289 }
1290
1291 if (info->matched_objs) {
1292 free(info->matched_objs);
1293 }
1294
1295 bzero(info, sizeof (find_objs_info_t));
1296 REFRELEASE(session);
1297 return (rv);
1298 }
1299