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