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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 #include <unistd.h> /* for pid */
31 #include <security/cryptoki.h>
32 #include "kernelGlobal.h"
33 #include "kernelSession.h"
34 #include "kernelSlot.h"
36 #pragma init(kernel_init)
37 #pragma fini(kernel_fini)
39 static struct CK_FUNCTION_LIST functionList
= {
40 { 2, 20 }, /* version */
95 C_DigestEncryptUpdate
,
96 C_DecryptDigestUpdate
,
98 C_DecryptVerifyUpdate
,
111 boolean_t kernel_initialized
= B_FALSE
;
112 static pid_t kernel_pid
= 0;
114 extern pthread_mutex_t mechhash_mutex
;
119 /* protects kernel_initialized and entrance to C_Initialize/Finalize */
120 static pthread_mutex_t globalmutex
= PTHREAD_MUTEX_INITIALIZER
;
122 ses_to_be_freed_list_t ses_delay_freed
;
123 object_to_be_freed_list_t obj_delay_freed
;
124 kmh_elem_t
**kernel_mechhash
; /* Hash table for kCF mech numbers */
126 static void finalize_common();
127 static void cleanup_library();
128 static void kernel_init();
129 static void kernel_fini();
130 static void kernel_fork_prepare();
131 static void kernel_fork_after();
134 C_Initialize(CK_VOID_PTR pInitArgs
)
137 boolean_t supplied_ok
;
141 * Grab lock to insure that only one thread enters this
142 * function at a time.
144 (void) pthread_mutex_lock(&globalmutex
);
145 initialize_pid
= getpid();
147 if (kernel_initialized
) {
148 if (initialize_pid
== kernel_pid
) {
150 * This process has called C_Initialize already
152 (void) pthread_mutex_unlock(&globalmutex
);
153 return (CKR_CRYPTOKI_ALREADY_INITIALIZED
);
156 * A fork has happened and the child is
157 * reinitializing. Do a cleanup_library to close
158 * out any state from the parent, and then
165 if (pInitArgs
!= NULL
) {
166 CK_C_INITIALIZE_ARGS
*initargs1
=
167 (CK_C_INITIALIZE_ARGS
*) pInitArgs
;
169 /* pReserved must be NULL */
170 if (initargs1
->pReserved
!= NULL
) {
171 (void) pthread_mutex_unlock(&globalmutex
);
172 return (CKR_ARGUMENTS_BAD
);
176 * ALL supplied function pointers need to have the value
177 * either NULL or non-NULL.
179 supplied_ok
= (initargs1
->CreateMutex
== NULL
&&
180 initargs1
->DestroyMutex
== NULL
&&
181 initargs1
->LockMutex
== NULL
&&
182 initargs1
->UnlockMutex
== NULL
) ||
183 (initargs1
->CreateMutex
!= NULL
&&
184 initargs1
->DestroyMutex
!= NULL
&&
185 initargs1
->LockMutex
!= NULL
&&
186 initargs1
->UnlockMutex
!= NULL
);
189 (void) pthread_mutex_unlock(&globalmutex
);
190 return (CKR_ARGUMENTS_BAD
);
194 * When the CKF_OS_LOCKING_OK flag isn't set and mutex
195 * function pointers are supplied by an application,
196 * return an error. We must be able to use our own locks.
198 if (!(initargs1
->flags
& CKF_OS_LOCKING_OK
) &&
199 (initargs1
->CreateMutex
!= NULL
)) {
200 (void) pthread_mutex_unlock(&globalmutex
);
201 return (CKR_CANT_LOCK
);
205 while ((kernel_fd
= open(CRYPTO_DEVICE
, O_RDWR
)) < 0) {
210 (void) pthread_mutex_unlock(&globalmutex
);
211 return (CKR_FUNCTION_FAILED
);
214 /* Mark kernel_fd "close on exec" */
215 (void) fcntl(kernel_fd
, F_SETFD
, FD_CLOEXEC
);
217 /* Create the hash table */
218 kernel_mechhash
= calloc(KMECH_HASHTABLE_SIZE
, sizeof (void *));
219 if (kernel_mechhash
== NULL
) {
220 (void) close(kernel_fd
);
221 (void) pthread_mutex_unlock(&globalmutex
);
222 return (CKR_HOST_MEMORY
);
225 /* Initialize the slot table */
226 rv
= kernel_slottable_init();
228 free(kernel_mechhash
);
229 (void) close(kernel_fd
);
230 (void) pthread_mutex_unlock(&globalmutex
);
234 /* Initialize the object_to_be_freed list */
235 (void) pthread_mutex_init(&obj_delay_freed
.obj_to_be_free_mutex
, NULL
);
236 obj_delay_freed
.count
= 0;
237 obj_delay_freed
.first
= NULL
;
238 obj_delay_freed
.last
= NULL
;
240 /* Initialize the session_to_be_freed list */
241 (void) pthread_mutex_init(&ses_delay_freed
.ses_to_be_free_mutex
, NULL
);
242 ses_delay_freed
.count
= 0;
243 ses_delay_freed
.first
= NULL
;
244 ses_delay_freed
.last
= NULL
;
246 kernel_initialized
= B_TRUE
;
247 kernel_pid
= initialize_pid
;
249 (void) pthread_mutex_unlock(&globalmutex
);
257 * C_Finalize is a wrapper around finalize_common. The
258 * globalmutex should be locked by C_Finalize().
261 C_Finalize(CK_VOID_PTR pReserved
)
265 (void) pthread_mutex_lock(&globalmutex
);
267 if (!kernel_initialized
) {
268 (void) pthread_mutex_unlock(&globalmutex
);
269 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
272 /* Check to see if pReseved is NULL */
273 if (pReserved
!= NULL
) {
274 (void) pthread_mutex_unlock(&globalmutex
);
275 return (CKR_ARGUMENTS_BAD
);
279 * Delete all the sessions for each slot and release the allocated
282 for (i
= 0; i
< slot_count
; i
++) {
283 kernel_delete_all_sessions(i
, B_FALSE
);
288 (void) pthread_mutex_unlock(&globalmutex
);
294 * finalize_common() does the work for C_Finalize. globalmutex
295 * must be held before calling this function.
301 kmh_elem_t
*elem
, *next
;
302 kernel_object_t
*delay_free_obj
, *tmpo
;
303 kernel_session_t
*delay_free_ses
, *tmps
;
306 * Free the resources allocated for the slot table and reset
309 if (slot_count
> 0) {
310 for (i
= 0; i
< slot_count
; i
++) {
311 (void) pthread_mutex_destroy(&slot_table
[i
]->sl_mutex
);
312 (void) free(slot_table
[i
]);
314 (void) free(slot_table
);
318 /* Close CRYPTO_DEVICE */
319 if (kernel_fd
>= 0) {
320 (void) close(kernel_fd
);
323 /* Walk the hash table and free all entries */
324 for (i
= 0; i
< KMECH_HASHTABLE_SIZE
; i
++) {
325 elem
= kernel_mechhash
[i
];
326 while (elem
!= NULL
) {
333 free(kernel_mechhash
);
336 kernel_initialized
= B_FALSE
;
340 * free all entries in the delay_freed list
342 delay_free_obj
= obj_delay_freed
.first
;
343 while (delay_free_obj
!= NULL
) {
344 tmpo
= delay_free_obj
->next
;
345 free(delay_free_obj
);
346 delay_free_obj
= tmpo
;
348 (void) pthread_mutex_destroy(&obj_delay_freed
.obj_to_be_free_mutex
);
350 delay_free_ses
= ses_delay_freed
.first
;
351 while (delay_free_ses
!= NULL
) {
352 tmps
= delay_free_ses
->next
;
353 free(delay_free_ses
);
354 delay_free_ses
= tmps
;
356 (void) pthread_mutex_destroy(&ses_delay_freed
.ses_to_be_free_mutex
);
360 * This function cleans up all the resources in the library (user space only)
368 * Delete all the sessions for each slot and release the allocated
369 * resources from the library. The boolean argument TRUE indicates
370 * that we only wants to clean up the resource in the library only.
371 * We don't want to clean up the corresponding kernel part of
372 * resources, because they are used by the parent process still.
375 for (i
= 0; i
< slot_count
; i
++) {
376 kernel_delete_all_sessions(i
, B_TRUE
);
385 (void) pthread_atfork(kernel_fork_prepare
, kernel_fork_after
,
390 * kernel_fini() function required to make sure complete cleanup
391 * is done if pkcs11_kernel is ever unloaded without
392 * a C_Finalize() call.
398 (void) pthread_mutex_lock(&globalmutex
);
400 /* if we're not initilized, do not attempt to finalize */
401 if (!kernel_initialized
) {
402 (void) pthread_mutex_unlock(&globalmutex
);
408 (void) pthread_mutex_unlock(&globalmutex
);
412 C_GetInfo(CK_INFO_PTR pInfo
)
414 if (!kernel_initialized
)
415 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
418 return (CKR_ARGUMENTS_BAD
);
421 /* Check if the cryptoki was initialized */
423 pInfo
->cryptokiVersion
.major
= CRYPTOKI_VERSION_MAJOR
;
424 pInfo
->cryptokiVersion
.minor
= CRYPTOKI_VERSION_MINOR
;
425 (void) strncpy((char *)pInfo
->manufacturerID
,
426 MANUFACTURER_ID
, 32);
428 (void) strncpy((char *)pInfo
->libraryDescription
,
429 LIBRARY_DESCRIPTION
, 32);
430 pInfo
->libraryVersion
.major
= LIBRARY_VERSION_MAJOR
;
431 pInfo
->libraryVersion
.minor
= LIBRARY_VERSION_MINOR
;
437 C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList
)
439 if (ppFunctionList
== NULL
) {
440 return (CKR_ARGUMENTS_BAD
);
443 *ppFunctionList
= &functionList
;
449 * PKCS#11 states that C_GetFunctionStatus should always return
450 * CKR_FUNCTION_NOT_PARALLEL
454 C_GetFunctionStatus(CK_SESSION_HANDLE hSession
)
456 return (CKR_FUNCTION_NOT_PARALLEL
);
460 * Take out all mutexes before fork.
463 * 2. all slots mutexes (and all their sessions) via
464 * kernel_acquire_all_slots_mutexes()
465 * 3. obj_delay_freed.obj_to_be_free_mutex;
466 * 4. ses_delay_freed.ses_to_be_free_mutex
469 kernel_fork_prepare()
471 (void) pthread_mutex_lock(&globalmutex
);
472 if (kernel_initialized
) {
473 kernel_acquire_all_slots_mutexes();
474 (void) pthread_mutex_lock(
475 &obj_delay_freed
.obj_to_be_free_mutex
);
476 (void) pthread_mutex_lock(
477 &ses_delay_freed
.ses_to_be_free_mutex
);
478 (void) pthread_mutex_lock(&mechhash_mutex
);
483 * Release in opposite order to kernel_fork_prepare().
484 * Function is used for parent and child.
489 if (kernel_initialized
) {
490 (void) pthread_mutex_unlock(&mechhash_mutex
);
491 (void) pthread_mutex_unlock(
492 &ses_delay_freed
.ses_to_be_free_mutex
);
493 (void) pthread_mutex_unlock(
494 &obj_delay_freed
.obj_to_be_free_mutex
);
495 kernel_release_all_slots_mutexes();
497 (void) pthread_mutex_unlock(&globalmutex
);
501 * PKCS#11 states that C_CancelFunction should always return
502 * CKR_FUNCTION_NOT_PARALLEL
506 C_CancelFunction(CK_SESSION_HANDLE hSession
)
508 return (CKR_FUNCTION_NOT_PARALLEL
);