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 2014, OmniTI Computer Consulting, Inc. All rights reserved.
26 *
27 * Copyright 2020 Joyent, Inc.
28 */
29
30 #include <strings.h>
31 #include <errno.h>
32 #include <cryptoutil.h>
33 #include <unistd.h> /* for pid_t */
34 #include <pthread.h>
35 #include <stddef.h>
36 #include <security/cryptoki.h>
37 #include <sys/debug.h>
38 #include "softGlobal.h"
39 #include "softSession.h"
40 #include "softObject.h"
41 #include "softKeystore.h"
42 #include "softKeystoreUtil.h"
43
44 #pragma init(softtoken_init)
45 #pragma fini(softtoken_fini)
46
47 extern soft_session_t token_session; /* for fork handler */
48
49 static struct CK_FUNCTION_LIST functionList = {
50 { 2, 20 }, /* version */
51 C_Initialize,
52 C_Finalize,
53 C_GetInfo,
54 C_GetFunctionList,
55 C_GetSlotList,
56 C_GetSlotInfo,
57 C_GetTokenInfo,
58 C_GetMechanismList,
59 C_GetMechanismInfo,
60 C_InitToken,
61 C_InitPIN,
62 C_SetPIN,
63 C_OpenSession,
64 C_CloseSession,
65 C_CloseAllSessions,
66 C_GetSessionInfo,
67 C_GetOperationState,
68 C_SetOperationState,
69 C_Login,
70 C_Logout,
71 C_CreateObject,
72 C_CopyObject,
73 C_DestroyObject,
74 C_GetObjectSize,
75 C_GetAttributeValue,
76 C_SetAttributeValue,
77 C_FindObjectsInit,
78 C_FindObjects,
79 C_FindObjectsFinal,
80 C_EncryptInit,
81 C_Encrypt,
82 C_EncryptUpdate,
83 C_EncryptFinal,
84 C_DecryptInit,
85 C_Decrypt,
86 C_DecryptUpdate,
87 C_DecryptFinal,
88 C_DigestInit,
89 C_Digest,
90 C_DigestUpdate,
91 C_DigestKey,
92 C_DigestFinal,
93 C_SignInit,
94 C_Sign,
95 C_SignUpdate,
96 C_SignFinal,
97 C_SignRecoverInit,
98 C_SignRecover,
99 C_VerifyInit,
100 C_Verify,
101 C_VerifyUpdate,
102 C_VerifyFinal,
103 C_VerifyRecoverInit,
104 C_VerifyRecover,
105 C_DigestEncryptUpdate,
106 C_DecryptDigestUpdate,
107 C_SignEncryptUpdate,
108 C_DecryptVerifyUpdate,
109 C_GenerateKey,
110 C_GenerateKeyPair,
111 C_WrapKey,
112 C_UnwrapKey,
113 C_DeriveKey,
114 C_SeedRandom,
115 C_GenerateRandom,
116 C_GetFunctionStatus,
117 C_CancelFunction,
118 C_WaitForSlotEvent
119 };
120
121 boolean_t softtoken_initialized = B_FALSE;
122
123 static pid_t softtoken_pid = 0;
124
125 /*
126 * Lock ordering in pkcs11_softtoken is as follows:
127 * soft_giant_mutex
128 * soft_sessionlist_mutex
129 * soft_slot.slot_mutex
130 * soft_slot.keystore_mutex
131 * token session mutexes
132 * soft_session_t->session_mutex
133 * soft_object_mutex
134 * soft_object_t->object_mutex
135 * obj_delay_freed.obj_to_be_free_mutex
136 * ses_delay_freed.ses_to_br_free_mutex
137 */
138
139 /*
140 * This mutex protects soft_session_list, all_sessions_closing,
141 * and soft_session_tree
142 */
143 pthread_mutex_t soft_sessionlist_mutex;
144 soft_session_t *soft_session_list = NULL;
145 avl_tree_t soft_session_tree;
146
147 /* This protects soft_object_tree */
148 pthread_mutex_t soft_object_mutex;
149 avl_tree_t soft_object_tree;
150
151 int all_sessions_closing = 0;
152
153 slot_t soft_slot;
154 obj_to_be_freed_list_t obj_delay_freed;
155 ses_to_be_freed_list_t ses_delay_freed;
156
157 /* protects softtoken_initialized and access to C_Initialize/C_Finalize */
158 pthread_mutex_t soft_giant_mutex = PTHREAD_MUTEX_INITIALIZER;
159
160 static CK_RV finalize_common(boolean_t force, CK_VOID_PTR pReserved);
161 static void softtoken_init(void);
162 static void softtoken_fini(void);
163 static void softtoken_fork_prepare(void);
164 static void softtoken_fork_after(void);
165 static int session_compare(const void *a, const void *b);
166 static int object_compare(const void *a, const void *b);
167
168 CK_RV
C_Initialize(CK_VOID_PTR pInitArgs)169 C_Initialize(CK_VOID_PTR pInitArgs)
170 {
171 pthread_mutexattr_t attr = { 0 };
172 int initialize_pid;
173 boolean_t supplied_ok;
174 CK_RV rv;
175
176 /*
177 * Get lock to insure only one thread enters this
178 * function at a time.
179 */
180 (void) pthread_mutex_lock(&soft_giant_mutex);
181
182 initialize_pid = getpid();
183
184 if (softtoken_initialized) {
185 if (initialize_pid == softtoken_pid) {
186 /*
187 * This process has called C_Initialize already
188 */
189 (void) pthread_mutex_unlock(&soft_giant_mutex);
190 return (CKR_CRYPTOKI_ALREADY_INITIALIZED);
191 } else {
192 /*
193 * A fork has happened and the child is
194 * reinitializing. Do a finalize_common to close
195 * out any state from the parent, and then
196 * continue on.
197 */
198 (void) finalize_common(B_TRUE, NULL);
199 }
200 }
201
202 if (pInitArgs != NULL) {
203 CK_C_INITIALIZE_ARGS *initargs1 =
204 (CK_C_INITIALIZE_ARGS *) pInitArgs;
205
206 /* pReserved must be NULL */
207 if (initargs1->pReserved != NULL) {
208 (void) pthread_mutex_unlock(&soft_giant_mutex);
209 return (CKR_ARGUMENTS_BAD);
210 }
211
212 /*
213 * ALL supplied function pointers need to have the value
214 * either NULL or non-NULL.
215 */
216 supplied_ok = (initargs1->CreateMutex == NULL &&
217 initargs1->DestroyMutex == NULL &&
218 initargs1->LockMutex == NULL &&
219 initargs1->UnlockMutex == NULL) ||
220 (initargs1->CreateMutex != NULL &&
221 initargs1->DestroyMutex != NULL &&
222 initargs1->LockMutex != NULL &&
223 initargs1->UnlockMutex != NULL);
224
225 if (!supplied_ok) {
226 (void) pthread_mutex_unlock(&soft_giant_mutex);
227 return (CKR_ARGUMENTS_BAD);
228 }
229
230 /*
231 * When the CKF_OS_LOCKING_OK flag isn't set and mutex
232 * function pointers are supplied by an application,
233 * return an error. We must be able to use our own primitives.
234 */
235 if (!(initargs1->flags & CKF_OS_LOCKING_OK) &&
236 (initargs1->CreateMutex != NULL)) {
237 (void) pthread_mutex_unlock(&soft_giant_mutex);
238 return (CKR_CANT_LOCK);
239 }
240 }
241
242 if (pthread_mutexattr_init(&attr) != 0) {
243 (void) pthread_mutex_unlock(&soft_giant_mutex);
244 return (CKR_HOST_MEMORY);
245 }
246
247 VERIFY0(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK));
248
249 /* Initialize the session list lock */
250 if (pthread_mutex_init(&soft_sessionlist_mutex, &attr) != 0) {
251 (void) pthread_mutexattr_destroy(&attr);
252 (void) pthread_mutex_unlock(&soft_giant_mutex);
253 return (CKR_CANT_LOCK);
254 }
255
256 if (pthread_mutex_init(&soft_object_mutex, &attr) != 0) {
257 (void) pthread_mutexattr_destroy(&attr);
258 (void) pthread_mutex_unlock(&soft_giant_mutex);
259 return (CKR_CANT_LOCK);
260 }
261
262 VERIFY0(pthread_mutexattr_destroy(&attr));
263
264 /*
265 * token object related initialization
266 */
267 soft_slot.authenticated = 0;
268 soft_slot.userpin_change_needed = 0;
269 soft_slot.token_object_list = NULL;
270 soft_slot.keystore_load_status = KEYSTORE_UNINITIALIZED;
271
272 if ((rv = soft_init_token_session()) != CKR_OK) {
273 (void) pthread_mutex_destroy(&soft_sessionlist_mutex);
274 (void) pthread_mutex_unlock(&soft_giant_mutex);
275 return (rv);
276 }
277
278 /* Initialize the slot lock */
279 if (pthread_mutex_init(&soft_slot.slot_mutex, NULL) != 0) {
280 (void) pthread_mutex_destroy(&soft_sessionlist_mutex);
281 (void) soft_destroy_token_session();
282 (void) pthread_mutex_unlock(&soft_giant_mutex);
283 return (CKR_CANT_LOCK);
284 }
285
286 /* Initialize the keystore lock */
287 if (pthread_mutex_init(&soft_slot.keystore_mutex, NULL) != 0) {
288 (void) pthread_mutex_destroy(&soft_slot.slot_mutex);
289 (void) pthread_mutex_destroy(&soft_sessionlist_mutex);
290 (void) soft_destroy_token_session();
291 (void) pthread_mutex_unlock(&soft_giant_mutex);
292 return (CKR_CANT_LOCK);
293 }
294
295 /* Initialize the object_to_be_freed list */
296 if (pthread_mutex_init(&obj_delay_freed.obj_to_be_free_mutex, NULL)
297 != 0) {
298 (void) pthread_mutex_destroy(&soft_slot.keystore_mutex);
299 (void) pthread_mutex_destroy(&soft_slot.slot_mutex);
300 (void) pthread_mutex_destroy(&soft_sessionlist_mutex);
301 (void) soft_destroy_token_session();
302 (void) pthread_mutex_unlock(&soft_giant_mutex);
303 return (CKR_CANT_LOCK);
304 }
305 obj_delay_freed.count = 0;
306 obj_delay_freed.first = NULL;
307 obj_delay_freed.last = NULL;
308
309 if (pthread_mutex_init(&ses_delay_freed.ses_to_be_free_mutex, NULL)
310 != 0) {
311 (void) pthread_mutex_destroy(
312 &obj_delay_freed.obj_to_be_free_mutex);
313 (void) pthread_mutex_destroy(&soft_slot.keystore_mutex);
314 (void) pthread_mutex_destroy(&soft_slot.slot_mutex);
315 (void) pthread_mutex_destroy(&soft_sessionlist_mutex);
316 (void) soft_destroy_token_session();
317 (void) pthread_mutex_unlock(&soft_giant_mutex);
318 return (CKR_CANT_LOCK);
319 }
320 ses_delay_freed.count = 0;
321 ses_delay_freed.first = NULL;
322 ses_delay_freed.last = NULL;
323
324 if (rv != CKR_OK) {
325 (void) pthread_mutex_destroy(
326 &ses_delay_freed.ses_to_be_free_mutex);
327 (void) pthread_mutex_destroy(
328 &obj_delay_freed.obj_to_be_free_mutex);
329 (void) pthread_mutex_destroy(&soft_slot.keystore_mutex);
330 (void) pthread_mutex_destroy(&soft_slot.slot_mutex);
331 (void) pthread_mutex_destroy(&soft_sessionlist_mutex);
332 (void) soft_destroy_token_session();
333 (void) pthread_mutex_unlock(&soft_giant_mutex);
334 return (CKR_FUNCTION_FAILED);
335 }
336
337 softtoken_pid = initialize_pid;
338 softtoken_initialized = B_TRUE;
339 (void) pthread_mutex_unlock(&soft_giant_mutex);
340
341 return (CKR_OK);
342 }
343
344 /*
345 * C_Finalize is a wrapper around finalize_common. The
346 * soft_giant_mutex should be locked by C_Finalize().
347 */
348 CK_RV
C_Finalize(CK_VOID_PTR pReserved)349 C_Finalize(CK_VOID_PTR pReserved)
350 {
351
352 CK_RV rv;
353
354 (void) pthread_mutex_lock(&soft_giant_mutex);
355
356 rv = finalize_common(B_FALSE, pReserved);
357
358 (void) pthread_mutex_unlock(&soft_giant_mutex);
359
360 return (rv);
361
362 }
363
364 /*
365 * finalize_common() does the work for C_Finalize. soft_giant_mutex
366 * must be held before calling this function.
367 */
368 static CK_RV
finalize_common(boolean_t force,CK_VOID_PTR pReserved)369 finalize_common(boolean_t force, CK_VOID_PTR pReserved)
370 {
371 CK_RV rv = CKR_OK;
372 struct object *delay_free_obj, *tmpo;
373 struct session *delay_free_ses, *tmps;
374
375 if (!softtoken_initialized) {
376 return (CKR_CRYPTOKI_NOT_INITIALIZED);
377 }
378
379 /* Check to see if pReseved is NULL */
380 if (pReserved != NULL) {
381 return (CKR_ARGUMENTS_BAD);
382 }
383
384 (void) pthread_mutex_lock(&soft_sessionlist_mutex);
385 /*
386 * Set all_sessions_closing flag so any access to any
387 * existing sessions will be rejected.
388 */
389 all_sessions_closing = 1;
390 (void) pthread_mutex_unlock(&soft_sessionlist_mutex);
391
392 /* Delete all the sessions and release the allocated resources */
393 rv = soft_delete_all_sessions(force);
394
395 (void) pthread_mutex_lock(&soft_sessionlist_mutex);
396 /* Reset all_sessions_closing flag. */
397 all_sessions_closing = 0;
398 (void) pthread_mutex_unlock(&soft_sessionlist_mutex);
399
400 softtoken_initialized = B_FALSE;
401 softtoken_pid = 0;
402
403 /*
404 * There used to be calls to cleanup libcryptoutil here. Given that
405 * libcryptoutil can be linked and invoked independently of PKCS#11,
406 * cleaning up libcryptoutil here makes no sense. Decoupling these
407 * two also prevent deadlocks and other artificial dependencies.
408 */
409
410 (void) pthread_mutex_destroy(&soft_object_mutex);
411
412 /* Destroy the session list lock here */
413 (void) pthread_mutex_destroy(&soft_sessionlist_mutex);
414
415 /*
416 * Destroy token object related stuffs
417 * 1. Clean up the token object list
418 * 2. Destroy slot mutex
419 * 3. Destroy mutex in token_session
420 */
421 soft_delete_all_in_core_token_objects(ALL_TOKEN);
422 (void) pthread_mutex_destroy(&soft_slot.slot_mutex);
423 (void) pthread_mutex_destroy(&soft_slot.keystore_mutex);
424 (void) soft_destroy_token_session();
425
426 /*
427 * free all entries in the delay_freed list
428 */
429 delay_free_obj = obj_delay_freed.first;
430 while (delay_free_obj != NULL) {
431 tmpo = delay_free_obj->next;
432 free(delay_free_obj);
433 delay_free_obj = tmpo;
434 }
435
436 soft_slot.keystore_load_status = KEYSTORE_UNINITIALIZED;
437 (void) pthread_mutex_destroy(&obj_delay_freed.obj_to_be_free_mutex);
438
439 delay_free_ses = ses_delay_freed.first;
440 while (delay_free_ses != NULL) {
441 tmps = delay_free_ses->next;
442 free(delay_free_ses);
443 delay_free_ses = tmps;
444 }
445 (void) pthread_mutex_destroy(&ses_delay_freed.ses_to_be_free_mutex);
446
447 return (rv);
448 }
449
450 static void
softtoken_init()451 softtoken_init()
452 {
453 avl_create(&soft_session_tree, session_compare, sizeof (soft_session_t),
454 offsetof(soft_session_t, node));
455
456 avl_create(&soft_object_tree, object_compare, sizeof (soft_object_t),
457 offsetof(soft_object_t, node));
458
459 /* Children inherit parent's atfork handlers */
460 (void) pthread_atfork(softtoken_fork_prepare,
461 softtoken_fork_after, softtoken_fork_after);
462 }
463
464 /*
465 * softtoken_fini() function required to make sure complete cleanup
466 * is done if softtoken is ever unloaded without a C_Finalize() call.
467 */
468 static void
softtoken_fini()469 softtoken_fini()
470 {
471 (void) pthread_mutex_lock(&soft_giant_mutex);
472
473 /* if we're not initilized, do not attempt to finalize */
474 if (!softtoken_initialized) {
475 (void) pthread_mutex_unlock(&soft_giant_mutex);
476 return;
477 }
478
479 (void) finalize_common(B_TRUE, NULL_PTR);
480
481 avl_destroy(&soft_object_tree);
482 avl_destroy(&soft_session_tree);
483
484 (void) pthread_mutex_unlock(&soft_giant_mutex);
485 }
486
487 CK_RV
C_GetInfo(CK_INFO_PTR pInfo)488 C_GetInfo(CK_INFO_PTR pInfo)
489 {
490 if (!softtoken_initialized)
491 return (CKR_CRYPTOKI_NOT_INITIALIZED);
492
493 if (pInfo == NULL) {
494 return (CKR_ARGUMENTS_BAD);
495 }
496
497 /* Provide general information in the provided buffer */
498 pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR;
499 pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR;
500 (void) strncpy((char *)pInfo->manufacturerID,
501 SOFT_MANUFACTURER_ID, 32);
502 pInfo->flags = 0;
503 (void) strncpy((char *)pInfo->libraryDescription,
504 LIBRARY_DESCRIPTION, 32);
505 pInfo->libraryVersion.major = LIBRARY_VERSION_MAJOR;
506 pInfo->libraryVersion.minor = LIBRARY_VERSION_MINOR;
507
508 return (CKR_OK);
509 }
510
511 CK_RV
C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)512 C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
513 {
514 if (ppFunctionList == NULL) {
515 return (CKR_ARGUMENTS_BAD);
516 }
517
518 *ppFunctionList = &functionList;
519
520 return (CKR_OK);
521 }
522
523 /*
524 * PKCS#11 states that C_GetFunctionStatus should always return
525 * CKR_FUNCTION_NOT_PARALLEL
526 */
527 /*ARGSUSED*/
528 CK_RV
C_GetFunctionStatus(CK_SESSION_HANDLE hSession)529 C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
530 {
531 return (CKR_FUNCTION_NOT_PARALLEL);
532 }
533
534 /*
535 * PKCS#11 states that C_CancelFunction should always return
536 * CKR_FUNCTION_NOT_PARALLEL
537 */
538 /*ARGSUSED*/
539 CK_RV
C_CancelFunction(CK_SESSION_HANDLE hSession)540 C_CancelFunction(CK_SESSION_HANDLE hSession)
541 {
542 return (CKR_FUNCTION_NOT_PARALLEL);
543 }
544
545 /*
546 * Take out all mutexes before fork.
547 *
548 * Order:
549 * 1. soft_giant_mutex
550 * 2. soft_sessionlist_mutex
551 * 3. soft_slot.slot_mutex
552 * 4. soft_slot.keystore_mutex
553 * 5. token_session mutexes via soft_acquire_all_session_mutexes()
554 * 6. all soft_session_list mutexes via soft_acquire_all_session_mutexes()
555 * 7. obj_delay_freed.obj_to_be_free_mutex;
556 * 8. ses_delay_freed.ses_to_be_free_mutex
557 */
558 void
softtoken_fork_prepare()559 softtoken_fork_prepare()
560 {
561 (void) pthread_mutex_lock(&soft_giant_mutex);
562 if (softtoken_initialized) {
563 (void) pthread_mutex_lock(&soft_sessionlist_mutex);
564 (void) pthread_mutex_lock(&soft_slot.slot_mutex);
565 (void) pthread_mutex_lock(&soft_slot.keystore_mutex);
566 soft_acquire_all_session_mutexes(&token_session);
567 soft_acquire_all_session_mutexes(soft_session_list);
568 VERIFY0(pthread_mutex_lock(&soft_object_mutex));
569 (void) pthread_mutex_lock(
570 &obj_delay_freed.obj_to_be_free_mutex);
571 (void) pthread_mutex_lock(
572 &ses_delay_freed.ses_to_be_free_mutex);
573 }
574 }
575
576 /*
577 * Release in opposite order to softtoken_fork_prepare().
578 * Function is used for parent and child.
579 */
580 void
softtoken_fork_after()581 softtoken_fork_after()
582 {
583 if (softtoken_initialized) {
584 (void) pthread_mutex_unlock(
585 &ses_delay_freed.ses_to_be_free_mutex);
586 (void) pthread_mutex_unlock(
587 &obj_delay_freed.obj_to_be_free_mutex);
588 VERIFY0(pthread_mutex_unlock(&soft_object_mutex));
589 soft_release_all_session_mutexes(soft_session_list);
590 soft_release_all_session_mutexes(&token_session);
591 (void) pthread_mutex_unlock(&soft_slot.keystore_mutex);
592 (void) pthread_mutex_unlock(&soft_slot.slot_mutex);
593 (void) pthread_mutex_unlock(&soft_sessionlist_mutex);
594 }
595 (void) pthread_mutex_unlock(&soft_giant_mutex);
596 }
597
598 static int
session_compare(const void * a,const void * b)599 session_compare(const void *a, const void *b)
600 {
601 const soft_session_t *l = a;
602 const soft_session_t *r = b;
603
604 if (l->handle < r->handle)
605 return (-1);
606 if (l->handle > r->handle)
607 return (1);
608 return (0);
609 }
610
611 static int
object_compare(const void * a,const void * b)612 object_compare(const void *a, const void *b)
613 {
614 const soft_object_t *l = a;
615 const soft_object_t *r = b;
616
617 if (l->handle < r->handle)
618 return (-1);
619 if (l->handle > r->handle)
620 return (1);
621 return (0);
622 }
623