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 #include <pthread.h>
27 #include <stdlib.h>
28 #include <security/cryptoki.h>
29 #include "softGlobal.h"
30 #include "softObject.h"
31 #include "softSession.h"
32 #include "softKeystore.h"
33 #include "softKeystoreUtil.h"
34
35
36 CK_RV
C_CreateObject(CK_SESSION_HANDLE hSession,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_OBJECT_HANDLE_PTR phObject)37 C_CreateObject(CK_SESSION_HANDLE hSession,
38 CK_ATTRIBUTE_PTR pTemplate,
39 CK_ULONG ulCount,
40 CK_OBJECT_HANDLE_PTR phObject)
41 {
42
43 CK_RV rv;
44 soft_session_t *session_p;
45 boolean_t lock_held = B_FALSE;
46
47 if (!softtoken_initialized)
48 return (CKR_CRYPTOKI_NOT_INITIALIZED);
49
50 /*
51 * Obtain the session pointer. Also, increment the session
52 * reference count.
53 */
54 rv = handle2session(hSession, &session_p);
55 if (rv != CKR_OK)
56 return (rv);
57
58 if ((pTemplate == NULL) || (ulCount == 0) ||
59 (phObject == NULL)) {
60 rv = CKR_ARGUMENTS_BAD;
61 goto clean_exit;
62 }
63
64 /* Create a new object. */
65 rv = soft_add_object(pTemplate, ulCount, phObject, session_p);
66
67 clean_exit:
68 /*
69 * Decrement the session reference count.
70 * We do not hold the session lock.
71 */
72 SES_REFRELE(session_p, lock_held);
73 return (rv);
74 }
75
76 CK_RV
C_CopyObject(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_OBJECT_HANDLE_PTR phNewObject)77 C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
78 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
79 CK_OBJECT_HANDLE_PTR phNewObject)
80 {
81
82 CK_RV rv;
83 soft_session_t *session_p;
84 boolean_t lock_held = B_FALSE;
85 soft_object_t *old_object, *new_object = NULL;
86 ulong_t i;
87
88 if (!softtoken_initialized)
89 return (CKR_CRYPTOKI_NOT_INITIALIZED);
90
91 /*
92 * Obtain the session pointer. Also, increment the session
93 * reference count.
94 */
95 rv = handle2session(hSession, &session_p);
96 if (rv != CKR_OK)
97 return (rv);
98
99 /* Check arguments */
100 if (((ulCount > 0) && (pTemplate == NULL)) ||
101 (phNewObject == NULL)) {
102 rv = CKR_ARGUMENTS_BAD;
103 goto clean_exit;
104 }
105
106 /* Obtain the object pointer. */
107 HANDLE2OBJECT(hObject, old_object, rv);
108 if (rv != CKR_OK) {
109 goto clean_exit;
110 }
111
112 /*
113 * Copy the old object to a new object.
114 * The 3rd argument with SOFT_COPY_OBJ value indicates that
115 * everything in the object will be duplicated for C_CopyObject.
116 * The 4th argument has the session pointer that will be
117 * saved in the new copy of the session object.
118 */
119 (void) pthread_mutex_lock(&old_object->object_mutex);
120 rv = soft_copy_object(old_object, &new_object, SOFT_COPY_OBJECT,
121 session_p);
122
123 if ((rv != CKR_OK) || (new_object == NULL)) {
124 /* Most likely we ran out of space. */
125 (void) pthread_mutex_unlock(&old_object->object_mutex);
126 goto clean_exit1;
127 }
128
129 /* No need to hold the lock on the old object. */
130 (void) pthread_mutex_unlock(&old_object->object_mutex);
131
132 /* Modifiy the objects if requested */
133 for (i = 0; i < ulCount; i++) {
134 /* Set the requested attribute into the new object. */
135 rv = soft_set_attribute(new_object, &pTemplate[i], B_TRUE);
136 if (rv != CKR_OK) {
137 goto fail;
138 }
139 }
140
141 rv = soft_pin_expired_check(new_object);
142 if (rv != CKR_OK) {
143 goto fail;
144 }
145
146 /*
147 * Does the new object violate the creation rule or access rule?
148 */
149 rv = soft_object_write_access_check(session_p, new_object);
150 if (rv != CKR_OK) {
151 goto fail;
152 }
153
154 /*
155 * If the new object is a token object, it will be added
156 * to token object list and write to disk.
157 */
158 if (IS_TOKEN_OBJECT(new_object)) {
159 new_object->version = 1;
160 /*
161 * Write to the keystore file.
162 */
163 rv = soft_put_object_to_keystore(new_object);
164 if (rv != CKR_OK) {
165 goto fail;
166 }
167
168 new_object->session_handle = (CK_SESSION_HANDLE)NULL;
169 /*
170 * Add the newly created token object to the global
171 * token object list in the slot struct.
172 */
173 soft_add_token_object_to_slot(new_object);
174 OBJ_REFRELE(old_object);
175 SES_REFRELE(session_p, lock_held);
176 *phNewObject = (CK_ULONG)new_object;
177
178 return (CKR_OK);
179 }
180
181 /* Insert new object into this session's object list */
182 soft_add_object_to_session(new_object, session_p);
183
184 /*
185 * Decrement the session reference count.
186 * We do not hold the session lock.
187 */
188 OBJ_REFRELE(old_object);
189 SES_REFRELE(session_p, lock_held);
190
191 /* set handle of the new object */
192 *phNewObject = (CK_ULONG)new_object;
193
194 return (rv);
195
196 fail:
197 soft_cleanup_object(new_object);
198 free(new_object);
199
200 clean_exit1:
201 OBJ_REFRELE(old_object);
202 clean_exit:
203 SES_REFRELE(session_p, lock_held);
204 return (rv);
205 }
206
207 CK_RV
C_DestroyObject(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject)208 C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
209 {
210
211 CK_RV rv;
212 soft_object_t *object_p;
213 soft_session_t *session_p = (soft_session_t *)(hSession);
214 boolean_t lock_held = B_FALSE;
215 CK_SESSION_HANDLE creating_session;
216
217
218 if (!softtoken_initialized)
219 return (CKR_CRYPTOKI_NOT_INITIALIZED);
220
221 /*
222 * The reason that we don't call handle2session is because
223 * the argument hSession may not be the creating_session of
224 * the object to be destroyed, and we want to avoid the lock
225 * contention. The handle2session will be called later for
226 * the creating_session.
227 */
228 if ((session_p == NULL) ||
229 (session_p->magic_marker != SOFTTOKEN_SESSION_MAGIC)) {
230 return (CKR_SESSION_HANDLE_INVALID);
231 }
232
233 /* Obtain the object pointer. */
234 HANDLE2OBJECT_DESTROY(hObject, object_p, rv);
235 if (rv != CKR_OK) {
236 return (rv);
237 }
238
239 /* Obtain the session handle which object belongs to. */
240 creating_session = object_p->session_handle;
241
242 if (creating_session == NULL) {
243 /*
244 * This is a token object to be deleted.
245 * For token object, there is no creating session concept,
246 * therefore, creating_session is always NULL.
247 */
248 rv = soft_pin_expired_check(object_p);
249 if (rv != CKR_OK) {
250 return (rv);
251 }
252
253 /* Obtain the session pointer just for validity check. */
254 rv = handle2session(hSession, &session_p);
255 if (rv != CKR_OK) {
256 return (rv);
257 }
258
259 rv = soft_object_write_access_check(session_p, object_p);
260 if (rv != CKR_OK) {
261 SES_REFRELE(session_p, lock_held);
262 return (rv);
263 }
264
265 /*
266 * Set OBJECT_IS_DELETING flag so any access to this
267 * object will be rejected.
268 */
269 (void) pthread_mutex_lock(&object_p->object_mutex);
270 if (object_p->obj_delete_sync & OBJECT_IS_DELETING) {
271 (void) pthread_mutex_unlock(&object_p->object_mutex);
272 SES_REFRELE(session_p, lock_held);
273 return (CKR_OBJECT_HANDLE_INVALID);
274 }
275 object_p->obj_delete_sync |= OBJECT_IS_DELETING;
276 (void) pthread_mutex_unlock(&object_p->object_mutex);
277 SES_REFRELE(session_p, lock_held);
278
279 /*
280 * Delete a token object by calling soft_delete_token_object()
281 * with the second argument B_TRUE indicating to delete the
282 * object from keystore and the third argument B_FALSE
283 * indicating that the caller does not hold the slot mutex.
284 */
285 soft_delete_token_object(object_p, B_TRUE, B_FALSE);
286 return (CKR_OK);
287 }
288
289 /*
290 * Obtain the session pointer. Also, increment the session
291 * reference count.
292 */
293 rv = handle2session(creating_session, &session_p);
294 if (rv != CKR_OK) {
295 return (rv);
296 }
297
298 /*
299 * Set OBJECT_IS_DELETING flag so any access to this
300 * object will be rejected.
301 */
302 (void) pthread_mutex_lock(&object_p->object_mutex);
303 if (object_p->obj_delete_sync & OBJECT_IS_DELETING) {
304 (void) pthread_mutex_unlock(&object_p->object_mutex);
305 SES_REFRELE(session_p, lock_held);
306 return (CKR_OBJECT_HANDLE_INVALID);
307 }
308 object_p->obj_delete_sync |= OBJECT_IS_DELETING;
309 (void) pthread_mutex_unlock(&object_p->object_mutex);
310
311 /*
312 * Delete an object by calling soft_delete_object()
313 * with a FALSE boolean argument indicating that
314 * the caller does not hold the session lock.
315 */
316 soft_delete_object(session_p, object_p, B_FALSE, B_FALSE);
317
318 /*
319 * Decrement the session reference count.
320 * We do not hold the session lock.
321 */
322 SES_REFRELE(session_p, lock_held);
323
324 return (rv);
325 }
326
327
328 CK_RV
C_GetAttributeValue(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)329 C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
330 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
331 {
332
333 CK_RV rv = CKR_OK, rv1 = CKR_OK;
334 soft_object_t *object_p;
335 soft_session_t *session_p;
336 boolean_t lock_held = B_FALSE;
337 ulong_t i;
338
339 if (!softtoken_initialized)
340 return (CKR_CRYPTOKI_NOT_INITIALIZED);
341
342 /*
343 * Obtain the session pointer. Also, increment the session
344 * reference count.
345 */
346 rv = handle2session(hSession, &session_p);
347 if (rv != CKR_OK)
348 return (rv);
349
350 if ((pTemplate == NULL) || (ulCount == 0)) {
351 /*
352 * Decrement the session reference count.
353 * We do not hold the session lock.
354 */
355 SES_REFRELE(session_p, lock_held);
356 return (CKR_ARGUMENTS_BAD);
357 }
358
359 /* Obtain the object pointer. */
360 HANDLE2OBJECT(hObject, object_p, rv);
361 if (rv != CKR_OK) {
362 /*
363 * Decrement the session reference count.
364 * We do not hold the session lock.
365 */
366 SES_REFRELE(session_p, lock_held);
367 return (rv);
368 }
369
370 if (IS_TOKEN_OBJECT(object_p)) {
371
372 rv = soft_keystore_load_latest_object(object_p);
373 if (rv != CKR_OK) {
374 OBJ_REFRELE(object_p);
375 SES_REFRELE(session_p, lock_held);
376 return (rv);
377 }
378 }
379
380 /* Acquire the lock on the object. */
381 (void) pthread_mutex_lock(&object_p->object_mutex);
382
383 for (i = 0; i < ulCount; i++) {
384 /*
385 * Get the value of each attribute in the template.
386 * (We must process EVERY attribute in the template.)
387 */
388 rv = soft_get_attribute(object_p, &pTemplate[i]);
389 if (rv != CKR_OK)
390 /* At least we catch some type of error. */
391 rv1 = rv;
392 }
393
394 /* Release the object lock */
395 (void) pthread_mutex_unlock(&object_p->object_mutex);
396
397 /*
398 * Decrement the session reference count.
399 * We do not hold the session lock.
400 */
401 OBJ_REFRELE(object_p);
402 SES_REFRELE(session_p, lock_held);
403
404 rv = rv1;
405 return (rv);
406 }
407
408
409 CK_RV
C_SetAttributeValue(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)410 C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
411 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
412 {
413 CK_RV rv = CKR_OK;
414 soft_object_t *object_p;
415 soft_object_t *new_object = NULL;
416 soft_session_t *session_p;
417 boolean_t lock_held = B_FALSE;
418 ulong_t i;
419
420 if (!softtoken_initialized)
421 return (CKR_CRYPTOKI_NOT_INITIALIZED);
422
423 /*
424 * Obtain the session pointer. Also, increment the session
425 * reference count.
426 */
427 rv = handle2session(hSession, &session_p);
428 if (rv != CKR_OK)
429 return (rv);
430
431 if ((pTemplate == NULL) || (ulCount == 0)) {
432 /*
433 * Decrement the session reference count.
434 * We do not hold the session lock.
435 */
436 SES_REFRELE(session_p, lock_held);
437 return (CKR_ARGUMENTS_BAD);
438 }
439
440 /* Obtain the object pointer. */
441 HANDLE2OBJECT(hObject, object_p, rv);
442 if (rv != CKR_OK) {
443 /*
444 * Decrement the session reference count.
445 * We do not hold the session lock.
446 */
447 SES_REFRELE(session_p, lock_held);
448 return (rv);
449 }
450
451 if (object_p->bool_attr_mask & NOT_MODIFIABLE_BOOL_ON) {
452 rv = CKR_ATTRIBUTE_READ_ONLY;
453 goto fail_1;
454 }
455
456 /*
457 * Start working on the object, so we need to set the write lock so that
458 * no one can write to it but still can read it.
459 */
460 if (IS_TOKEN_OBJECT(object_p)) {
461 rv = soft_keystore_load_latest_object(object_p);
462 if (rv != CKR_OK) {
463 goto fail_1;
464 }
465 }
466
467 /*
468 * Copy the old object to a new object. We work on the copied
469 * version because in case of error we still keep the old one
470 * intact.
471 * The 3rd argument with SOFT_SET_ATTR_VALUE value indicates that
472 * not everything will be duplicated for C_SetAttributeValue.
473 * Information not duplicated are those attributes that are not
474 * modifiable.
475 */
476 (void) pthread_mutex_lock(&object_p->object_mutex);
477 rv = soft_copy_object(object_p, &new_object, SOFT_SET_ATTR_VALUE, NULL);
478
479 if ((rv != CKR_OK) || (new_object == NULL)) {
480 /* Most likely we ran out of space. */
481 (void) pthread_mutex_unlock(&object_p->object_mutex);
482 /*
483 * Decrement the session reference count.
484 * We do not hold the session lock.
485 */
486 goto fail_1;
487 }
488
489 /*
490 * No need to hold the lock on the old object, because we
491 * will be working on the new scratch object.
492 */
493 (void) pthread_mutex_unlock(&object_p->object_mutex);
494
495 rv = soft_object_write_access_check(session_p, new_object);
496 if (rv != CKR_OK) {
497 goto fail;
498 }
499
500 for (i = 0; i < ulCount; i++) {
501 /* Set the requested attribute into the new object. */
502 rv = soft_set_attribute(new_object, &pTemplate[i], B_FALSE);
503
504 if (rv != CKR_OK) {
505 goto fail;
506 }
507 }
508
509 /*
510 * We've successfully set all the requested attributes.
511 * Merge the new object with the old object, then destory
512 * the new one. The reason to do the merging is because we
513 * have to keep the original object handle (address of object).
514 */
515 (void) pthread_mutex_lock(&object_p->object_mutex);
516
517 soft_merge_object(object_p, new_object);
518
519 /*
520 * The object has been modified, so we write it back to keystore.
521 */
522 if (IS_TOKEN_OBJECT(object_p)) {
523 object_p->version++;
524 rv = soft_modify_object_to_keystore(object_p);
525 }
526
527 (void) pthread_mutex_unlock(&object_p->object_mutex);
528 free(new_object);
529
530 /*
531 * Decrement the session reference count.
532 * We do not hold the session lock.
533 */
534 OBJ_REFRELE(object_p);
535 SES_REFRELE(session_p, lock_held);
536 return (rv);
537
538 fail:
539 soft_cleanup_object(new_object);
540 free(new_object);
541
542 fail_1:
543 OBJ_REFRELE(object_p);
544 SES_REFRELE(session_p, lock_held);
545
546 return (rv);
547 }
548
549 /*ARGSUSED*/
550 CK_RV
C_GetObjectSize(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ULONG_PTR pulSize)551 C_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
552 CK_ULONG_PTR pulSize)
553 {
554 if (!softtoken_initialized)
555 return (CKR_CRYPTOKI_NOT_INITIALIZED);
556
557 return (CKR_FUNCTION_NOT_SUPPORTED);
558 }
559
560 CK_RV
C_FindObjectsInit(CK_SESSION_HANDLE sh,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)561 C_FindObjectsInit(CK_SESSION_HANDLE sh, CK_ATTRIBUTE_PTR pTemplate,
562 CK_ULONG ulCount)
563 {
564
565 CK_RV rv;
566 soft_session_t *session_p;
567 boolean_t lock_held = B_TRUE;
568
569 if (!softtoken_initialized)
570 return (CKR_CRYPTOKI_NOT_INITIALIZED);
571
572 /*
573 * Obtain the session pointer. Also, increment the session
574 * reference count.
575 */
576 rv = handle2session(sh, &session_p);
577 if (rv != CKR_OK)
578 return (rv);
579
580 /* Check the arguments */
581 if ((ulCount > 0) && (pTemplate == NULL)) {
582 /* decrement the session count, we do not hold the lock */
583 lock_held = B_FALSE;
584 SES_REFRELE(session_p, lock_held);
585 return (CKR_ARGUMENTS_BAD);
586 }
587
588 /* Acquire the session lock */
589 (void) pthread_mutex_lock(&session_p->session_mutex);
590
591 /* Check to see if find operation is already active */
592 if (session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE) {
593 /* decrement the session count, and unlock the mutex */
594 SES_REFRELE(session_p, lock_held);
595 return (CKR_OPERATION_ACTIVE);
596 } else {
597 /*
598 * This active flag will remain ON until application calls
599 * C_FindObjectsFinal.
600 */
601 session_p->find_objects.flags = CRYPTO_OPERATION_ACTIVE;
602 }
603
604 (void) pthread_mutex_unlock(&session_p->session_mutex);
605
606 rv = soft_find_objects_init(session_p, pTemplate, ulCount);
607
608 if (rv != CKR_OK) {
609 (void) pthread_mutex_lock(&session_p->session_mutex);
610 session_p->find_objects.flags = 0;
611 (void) pthread_mutex_unlock(&session_p->session_mutex);
612 }
613
614 /* decrement the session count, and unlock the mutex */
615 lock_held = B_FALSE;
616 SES_REFRELE(session_p, lock_held);
617 return (rv);
618 }
619
620 CK_RV
C_FindObjects(CK_SESSION_HANDLE sh,CK_OBJECT_HANDLE_PTR phObject,CK_ULONG ulMaxObjectCount,CK_ULONG_PTR pulObjectCount)621 C_FindObjects(CK_SESSION_HANDLE sh,
622 CK_OBJECT_HANDLE_PTR phObject,
623 CK_ULONG ulMaxObjectCount,
624 CK_ULONG_PTR pulObjectCount)
625 {
626 soft_session_t *session_p;
627 CK_RV rv = CKR_OK;
628 boolean_t lock_held = B_TRUE;
629
630 if (!softtoken_initialized)
631 return (CKR_CRYPTOKI_NOT_INITIALIZED);
632
633 /*
634 * Obtain the session pointer. Also, increment the session
635 * reference count.
636 */
637 rv = handle2session(sh, &session_p);
638 if (rv != CKR_OK)
639 return (rv);
640
641 /* check for invalid arguments */
642 if (((phObject == NULL) && (ulMaxObjectCount != 0)) ||
643 (pulObjectCount == NULL)) {
644 /* decrement the session count, we do not hold the lock */
645 lock_held = B_FALSE;
646 SES_REFRELE(session_p, lock_held);
647 return (CKR_ARGUMENTS_BAD);
648 }
649
650 if (ulMaxObjectCount == 0) {
651 /* don't need to do anything, just return */
652 *pulObjectCount = 0;
653 /* decrement the session count, we do not hold the lock */
654 lock_held = B_FALSE;
655 SES_REFRELE(session_p, lock_held);
656 return (CKR_OK);
657 }
658
659 /* Acquire the session lock */
660 (void) pthread_mutex_lock(&session_p->session_mutex);
661
662 /* Check to see if find operation is active */
663 if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) {
664 SES_REFRELE(session_p, lock_held);
665 return (CKR_OPERATION_NOT_INITIALIZED);
666 }
667
668 soft_find_objects(session_p, phObject, ulMaxObjectCount,
669 pulObjectCount);
670
671 /* decrement the session count, and release the lock */
672 SES_REFRELE(session_p, lock_held);
673 return (rv);
674 }
675
676 CK_RV
C_FindObjectsFinal(CK_SESSION_HANDLE sh)677 C_FindObjectsFinal(CK_SESSION_HANDLE sh)
678 {
679 soft_session_t *session_p;
680 CK_RV rv;
681 boolean_t lock_held = B_TRUE;
682
683 if (!softtoken_initialized)
684 return (CKR_CRYPTOKI_NOT_INITIALIZED);
685
686 /*
687 * Obtain the session pointer. Also, increment the session
688 * reference count.
689 */
690 rv = handle2session(sh, &session_p);
691 if (rv != CKR_OK)
692 return (rv);
693
694 /* Acquire the session lock */
695 (void) pthread_mutex_lock(&session_p->session_mutex);
696
697 /* Check to see if find operation is active */
698 if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) {
699 SES_REFRELE(session_p, lock_held);
700 return (CKR_OPERATION_NOT_INITIALIZED);
701 }
702
703 soft_find_objects_final(session_p);
704
705 /* decrement the session count, and release the lock */
706 SES_REFRELE(session_p, lock_held);
707 return (rv);
708 }
709