xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelGeneral.c (revision ed093b41a93e8563e6e1e5dae0768dda2a7bcc27)
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
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
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
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
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
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
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
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
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
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
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
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
506 C_CancelFunction(CK_SESSION_HANDLE hSession)
507 {
508 	return (CKR_FUNCTION_NOT_PARALLEL);
509 }
510