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 <fcntl.h>
27 #include <pthread.h>
28 #include <strings.h>
29 #include <unistd.h> /* for pid */
30 #include <errno.h>
31 #include <security/cryptoki.h>
32 #include "kernelGlobal.h"
33 #include "kernelSession.h"
34 #include "kernelSlot.h"
35
36 #pragma init(kernel_init)
37 #pragma fini(kernel_fini)
38
39 static struct CK_FUNCTION_LIST functionList = {
40 { 2, 20 }, /* version */
41 C_Initialize,
42 C_Finalize,
43 C_GetInfo,
44 C_GetFunctionList,
45 C_GetSlotList,
46 C_GetSlotInfo,
47 C_GetTokenInfo,
48 C_GetMechanismList,
49 C_GetMechanismInfo,
50 C_InitToken,
51 C_InitPIN,
52 C_SetPIN,
53 C_OpenSession,
54 C_CloseSession,
55 C_CloseAllSessions,
56 C_GetSessionInfo,
57 C_GetOperationState,
58 C_SetOperationState,
59 C_Login,
60 C_Logout,
61 C_CreateObject,
62 C_CopyObject,
63 C_DestroyObject,
64 C_GetObjectSize,
65 C_GetAttributeValue,
66 C_SetAttributeValue,
67 C_FindObjectsInit,
68 C_FindObjects,
69 C_FindObjectsFinal,
70 C_EncryptInit,
71 C_Encrypt,
72 C_EncryptUpdate,
73 C_EncryptFinal,
74 C_DecryptInit,
75 C_Decrypt,
76 C_DecryptUpdate,
77 C_DecryptFinal,
78 C_DigestInit,
79 C_Digest,
80 C_DigestUpdate,
81 C_DigestKey,
82 C_DigestFinal,
83 C_SignInit,
84 C_Sign,
85 C_SignUpdate,
86 C_SignFinal,
87 C_SignRecoverInit,
88 C_SignRecover,
89 C_VerifyInit,
90 C_Verify,
91 C_VerifyUpdate,
92 C_VerifyFinal,
93 C_VerifyRecoverInit,
94 C_VerifyRecover,
95 C_DigestEncryptUpdate,
96 C_DecryptDigestUpdate,
97 C_SignEncryptUpdate,
98 C_DecryptVerifyUpdate,
99 C_GenerateKey,
100 C_GenerateKeyPair,
101 C_WrapKey,
102 C_UnwrapKey,
103 C_DeriveKey,
104 C_SeedRandom,
105 C_GenerateRandom,
106 C_GetFunctionStatus,
107 C_CancelFunction,
108 C_WaitForSlotEvent
109 };
110
111 boolean_t kernel_initialized = B_FALSE;
112 static pid_t kernel_pid = 0;
113
114 extern pthread_mutex_t mechhash_mutex;
115
116 int kernel_fd = -1;
117
118
119 /* protects kernel_initialized and entrance to C_Initialize/Finalize */
120 static pthread_mutex_t globalmutex = PTHREAD_MUTEX_INITIALIZER;
121
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 */
125
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();
132
133 CK_RV
C_Initialize(CK_VOID_PTR pInitArgs)134 C_Initialize(CK_VOID_PTR pInitArgs)
135 {
136 int initialize_pid;
137 boolean_t supplied_ok;
138 CK_RV rv = CKR_OK;
139
140 /*
141 * Grab lock to insure that only one thread enters this
142 * function at a time.
143 */
144 (void) pthread_mutex_lock(&globalmutex);
145 initialize_pid = getpid();
146
147 if (kernel_initialized) {
148 if (initialize_pid == kernel_pid) {
149 /*
150 * This process has called C_Initialize already
151 */
152 (void) pthread_mutex_unlock(&globalmutex);
153 return (CKR_CRYPTOKI_ALREADY_INITIALIZED);
154 } else {
155 /*
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
159 * continue on.
160 */
161 cleanup_library();
162 }
163 }
164
165 if (pInitArgs != NULL) {
166 CK_C_INITIALIZE_ARGS *initargs1 =
167 (CK_C_INITIALIZE_ARGS *) pInitArgs;
168
169 /* pReserved must be NULL */
170 if (initargs1->pReserved != NULL) {
171 (void) pthread_mutex_unlock(&globalmutex);
172 return (CKR_ARGUMENTS_BAD);
173 }
174
175 /*
176 * ALL supplied function pointers need to have the value
177 * either NULL or non-NULL.
178 */
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);
187
188 if (!supplied_ok) {
189 (void) pthread_mutex_unlock(&globalmutex);
190 return (CKR_ARGUMENTS_BAD);
191 }
192
193 /*
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.
197 */
198 if (!(initargs1->flags & CKF_OS_LOCKING_OK) &&
199 (initargs1->CreateMutex != NULL)) {
200 (void) pthread_mutex_unlock(&globalmutex);
201 return (CKR_CANT_LOCK);
202 }
203 }
204
205 while ((kernel_fd = open(CRYPTO_DEVICE, O_RDWR)) < 0) {
206 if (errno != EINTR)
207 break;
208 }
209 if (kernel_fd < 0) {
210 (void) pthread_mutex_unlock(&globalmutex);
211 return (CKR_FUNCTION_FAILED);
212 }
213
214 /* Mark kernel_fd "close on exec" */
215 (void) fcntl(kernel_fd, F_SETFD, FD_CLOEXEC);
216
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);
223 }
224
225 /* Initialize the slot table */
226 rv = kernel_slottable_init();
227 if (rv != CKR_OK) {
228 free(kernel_mechhash);
229 (void) close(kernel_fd);
230 (void) pthread_mutex_unlock(&globalmutex);
231 return (rv);
232 }
233
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;
239
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;
245
246 kernel_initialized = B_TRUE;
247 kernel_pid = initialize_pid;
248
249 (void) pthread_mutex_unlock(&globalmutex);
250
251 return (CKR_OK);
252
253 }
254
255
256 /*
257 * C_Finalize is a wrapper around finalize_common. The
258 * globalmutex should be locked by C_Finalize().
259 */
260 CK_RV
C_Finalize(CK_VOID_PTR pReserved)261 C_Finalize(CK_VOID_PTR pReserved)
262 {
263 int i;
264
265 (void) pthread_mutex_lock(&globalmutex);
266
267 if (!kernel_initialized) {
268 (void) pthread_mutex_unlock(&globalmutex);
269 return (CKR_CRYPTOKI_NOT_INITIALIZED);
270 }
271
272 /* Check to see if pReseved is NULL */
273 if (pReserved != NULL) {
274 (void) pthread_mutex_unlock(&globalmutex);
275 return (CKR_ARGUMENTS_BAD);
276 }
277
278 /*
279 * Delete all the sessions for each slot and release the allocated
280 * resources
281 */
282 for (i = 0; i < slot_count; i++) {
283 kernel_delete_all_sessions(i, B_FALSE);
284 }
285
286 finalize_common();
287
288 (void) pthread_mutex_unlock(&globalmutex);
289
290 return (CKR_OK);
291 }
292
293 /*
294 * finalize_common() does the work for C_Finalize. globalmutex
295 * must be held before calling this function.
296 */
297 static void
finalize_common()298 finalize_common() {
299
300 int i;
301 kmh_elem_t *elem, *next;
302 kernel_object_t *delay_free_obj, *tmpo;
303 kernel_session_t *delay_free_ses, *tmps;
304
305 /*
306 * Free the resources allocated for the slot table and reset
307 * slot_count to 0.
308 */
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]);
313 }
314 (void) free(slot_table);
315 slot_count = 0;
316 }
317
318 /* Close CRYPTO_DEVICE */
319 if (kernel_fd >= 0) {
320 (void) close(kernel_fd);
321 }
322
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) {
327 next = elem->knext;
328 free(elem);
329 elem = next;
330 }
331 }
332
333 free(kernel_mechhash);
334
335 kernel_fd = -1;
336 kernel_initialized = B_FALSE;
337 kernel_pid = 0;
338
339 /*
340 * free all entries in the delay_freed list
341 */
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;
347 }
348 (void) pthread_mutex_destroy(&obj_delay_freed.obj_to_be_free_mutex);
349
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;
355 }
356 (void) pthread_mutex_destroy(&ses_delay_freed.ses_to_be_free_mutex);
357 }
358
359 /*
360 * This function cleans up all the resources in the library (user space only)
361 */
362 static void
cleanup_library()363 cleanup_library()
364 {
365 int i;
366
367 /*
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.
373 */
374
375 for (i = 0; i < slot_count; i++) {
376 kernel_delete_all_sessions(i, B_TRUE);
377 }
378
379 finalize_common();
380 }
381
382 static void
kernel_init()383 kernel_init()
384 {
385 (void) pthread_atfork(kernel_fork_prepare, kernel_fork_after,
386 kernel_fork_after);
387 }
388
389 /*
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.
393 */
394 static void
kernel_fini()395 kernel_fini()
396 {
397
398 (void) pthread_mutex_lock(&globalmutex);
399
400 /* if we're not initilized, do not attempt to finalize */
401 if (!kernel_initialized) {
402 (void) pthread_mutex_unlock(&globalmutex);
403 return;
404 }
405
406 cleanup_library();
407
408 (void) pthread_mutex_unlock(&globalmutex);
409 }
410
411 CK_RV
C_GetInfo(CK_INFO_PTR pInfo)412 C_GetInfo(CK_INFO_PTR pInfo)
413 {
414 if (!kernel_initialized)
415 return (CKR_CRYPTOKI_NOT_INITIALIZED);
416
417 if (pInfo == NULL) {
418 return (CKR_ARGUMENTS_BAD);
419 }
420
421 /* Check if the cryptoki was initialized */
422
423 pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR;
424 pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR;
425 (void) strncpy((char *)pInfo->manufacturerID,
426 MANUFACTURER_ID, 32);
427 pInfo->flags = 0;
428 (void) strncpy((char *)pInfo->libraryDescription,
429 LIBRARY_DESCRIPTION, 32);
430 pInfo->libraryVersion.major = LIBRARY_VERSION_MAJOR;
431 pInfo->libraryVersion.minor = LIBRARY_VERSION_MINOR;
432
433 return (CKR_OK);
434 }
435
436 CK_RV
C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)437 C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
438 {
439 if (ppFunctionList == NULL) {
440 return (CKR_ARGUMENTS_BAD);
441 }
442
443 *ppFunctionList = &functionList;
444
445 return (CKR_OK);
446 }
447
448 /*
449 * PKCS#11 states that C_GetFunctionStatus should always return
450 * CKR_FUNCTION_NOT_PARALLEL
451 */
452 /*ARGSUSED*/
453 CK_RV
C_GetFunctionStatus(CK_SESSION_HANDLE hSession)454 C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
455 {
456 return (CKR_FUNCTION_NOT_PARALLEL);
457 }
458
459 /*
460 * Take out all mutexes before fork.
461 * Order:
462 * 1. globalmutex
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
467 */
468 void
kernel_fork_prepare()469 kernel_fork_prepare()
470 {
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);
479 }
480 }
481
482 /*
483 * Release in opposite order to kernel_fork_prepare().
484 * Function is used for parent and child.
485 */
486 void
kernel_fork_after()487 kernel_fork_after()
488 {
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();
496 }
497 (void) pthread_mutex_unlock(&globalmutex);
498 }
499
500 /*
501 * PKCS#11 states that C_CancelFunction should always return
502 * CKR_FUNCTION_NOT_PARALLEL
503 */
504 /*ARGSUSED*/
505 CK_RV
C_CancelFunction(CK_SESSION_HANDLE hSession)506 C_CancelFunction(CK_SESSION_HANDLE hSession)
507 {
508 return (CKR_FUNCTION_NOT_PARALLEL);
509 }
510