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 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <fcntl.h>
29 #include <pthread.h>
30 #include <strings.h>
31 #include <unistd.h> /* for pid */
32 #include <errno.h>
33 #include <security/cryptoki.h>
34 #include "kernelGlobal.h"
35 #include "kernelSession.h"
36 #include "kernelSlot.h"
37 
38 #pragma fini(kernel_fini)
39 
40 static struct CK_FUNCTION_LIST functionList = {
41 	{ 2, 20 },	/* version */
42 	C_Initialize,
43 	C_Finalize,
44 	C_GetInfo,
45 	C_GetFunctionList,
46 	C_GetSlotList,
47 	C_GetSlotInfo,
48 	C_GetTokenInfo,
49 	C_GetMechanismList,
50 	C_GetMechanismInfo,
51 	C_InitToken,
52 	C_InitPIN,
53 	C_SetPIN,
54 	C_OpenSession,
55 	C_CloseSession,
56 	C_CloseAllSessions,
57 	C_GetSessionInfo,
58 	C_GetOperationState,
59 	C_SetOperationState,
60 	C_Login,
61 	C_Logout,
62 	C_CreateObject,
63 	C_CopyObject,
64 	C_DestroyObject,
65 	C_GetObjectSize,
66 	C_GetAttributeValue,
67 	C_SetAttributeValue,
68 	C_FindObjectsInit,
69 	C_FindObjects,
70 	C_FindObjectsFinal,
71 	C_EncryptInit,
72 	C_Encrypt,
73 	C_EncryptUpdate,
74 	C_EncryptFinal,
75 	C_DecryptInit,
76 	C_Decrypt,
77 	C_DecryptUpdate,
78 	C_DecryptFinal,
79 	C_DigestInit,
80 	C_Digest,
81 	C_DigestUpdate,
82 	C_DigestKey,
83 	C_DigestFinal,
84 	C_SignInit,
85 	C_Sign,
86 	C_SignUpdate,
87 	C_SignFinal,
88 	C_SignRecoverInit,
89 	C_SignRecover,
90 	C_VerifyInit,
91 	C_Verify,
92 	C_VerifyUpdate,
93 	C_VerifyFinal,
94 	C_VerifyRecoverInit,
95 	C_VerifyRecover,
96 	C_DigestEncryptUpdate,
97 	C_DecryptDigestUpdate,
98 	C_SignEncryptUpdate,
99 	C_DecryptVerifyUpdate,
100 	C_GenerateKey,
101 	C_GenerateKeyPair,
102 	C_WrapKey,
103 	C_UnwrapKey,
104 	C_DeriveKey,
105 	C_SeedRandom,
106 	C_GenerateRandom,
107 	C_GetFunctionStatus,
108 	C_CancelFunction,
109 	C_WaitForSlotEvent
110 };
111 
112 boolean_t kernel_initialized = B_FALSE;
113 static pid_t kernel_pid = 0;
114 
115 int kernel_fd = -1;
116 
117 
118 /* protects kernel_initialized and entrance to C_Initialize/Finalize */
119 static pthread_mutex_t globalmutex = PTHREAD_MUTEX_INITIALIZER;
120 
121 ses_to_be_freed_list_t ses_delay_freed;
122 object_to_be_freed_list_t obj_delay_freed;
123 kmh_elem_t **kernel_mechhash;	/* Hash table for kCF mech numbers */
124 
125 static void finalize_common();
126 static void cleanup_library();
127 static void kernel_fini();
128 
129 CK_RV
130 C_Initialize(CK_VOID_PTR pInitArgs)
131 {
132 	int initialize_pid;
133 	boolean_t supplied_ok;
134 	CK_RV rv = CKR_OK;
135 
136 	/*
137 	 * Grab lock to insure that only one thread enters this
138 	 * function at a time.
139 	 */
140 	(void) pthread_mutex_lock(&globalmutex);
141 	initialize_pid = getpid();
142 
143 	if (kernel_initialized) {
144 		if (initialize_pid == kernel_pid) {
145 			/*
146 			 * This process has called C_Initialize already
147 			 */
148 			(void) pthread_mutex_unlock(&globalmutex);
149 			return (CKR_CRYPTOKI_ALREADY_INITIALIZED);
150 		} else {
151 			/*
152 			 * A fork has happened and the child is
153 			 * reinitializing.  Do a cleanup_library to close
154 			 * out any state from the parent, and then
155 			 * continue on.
156 			 */
157 			cleanup_library();
158 		}
159 	}
160 
161 	if (pInitArgs != NULL) {
162 		CK_C_INITIALIZE_ARGS *initargs1 =
163 		    (CK_C_INITIALIZE_ARGS *) pInitArgs;
164 
165 		/* pReserved must be NULL */
166 		if (initargs1->pReserved != NULL) {
167 			(void) pthread_mutex_unlock(&globalmutex);
168 			return (CKR_ARGUMENTS_BAD);
169 		}
170 
171 		/*
172 		 * ALL supplied function pointers need to have the value
173 		 * either NULL or non-NULL.
174 		 */
175 		supplied_ok = (initargs1->CreateMutex == NULL &&
176 		    initargs1->DestroyMutex == NULL &&
177 		    initargs1->LockMutex == NULL &&
178 		    initargs1->UnlockMutex == NULL) ||
179 		    (initargs1->CreateMutex != NULL &&
180 		    initargs1->DestroyMutex != NULL &&
181 		    initargs1->LockMutex != NULL &&
182 		    initargs1->UnlockMutex != NULL);
183 
184 		if (!supplied_ok) {
185 			(void) pthread_mutex_unlock(&globalmutex);
186 			return (CKR_ARGUMENTS_BAD);
187 		}
188 
189 		/*
190 		 * When the CKF_OS_LOCKING_OK flag isn't set and mutex
191 		 * function pointers are supplied by an application,
192 		 * return an error.  We must be able to use our own locks.
193 		 */
194 		if (!(initargs1->flags & CKF_OS_LOCKING_OK) &&
195 		    (initargs1->CreateMutex != NULL)) {
196 			(void) pthread_mutex_unlock(&globalmutex);
197 			return (CKR_CANT_LOCK);
198 		}
199 	}
200 
201 	while ((kernel_fd = open(CRYPTO_DEVICE, O_RDWR)) < 0) {
202 		if (errno != EINTR)
203 			break;
204 	}
205 	if (kernel_fd < 0) {
206 		(void) pthread_mutex_unlock(&globalmutex);
207 		return (CKR_FUNCTION_FAILED);
208 	}
209 
210 	/* Mark kernel_fd "close on exec" */
211 	(void) fcntl(kernel_fd, F_SETFD, FD_CLOEXEC);
212 
213 	/* Create the hash table */
214 	kernel_mechhash = calloc(KMECH_HASHTABLE_SIZE, sizeof (void *));
215 	if (kernel_mechhash == NULL) {
216 		(void) close(kernel_fd);
217 		(void) pthread_mutex_unlock(&globalmutex);
218 		return (CKR_HOST_MEMORY);
219 	}
220 
221 	/* Initialize the slot table */
222 	rv = kernel_slottable_init();
223 	if (rv != CKR_OK) {
224 		free(kernel_mechhash);
225 		(void) close(kernel_fd);
226 		(void) pthread_mutex_unlock(&globalmutex);
227 		return (rv);
228 	}
229 
230 	/* Initialize the object_to_be_freed list */
231 	(void) pthread_mutex_init(&obj_delay_freed.obj_to_be_free_mutex, NULL);
232 	obj_delay_freed.count = 0;
233 	obj_delay_freed.first = NULL;
234 	obj_delay_freed.last = NULL;
235 
236 	/* Initialize the session_to_be_freed list */
237 	(void) pthread_mutex_init(&ses_delay_freed.ses_to_be_free_mutex, NULL);
238 	ses_delay_freed.count = 0;
239 	ses_delay_freed.first = NULL;
240 	ses_delay_freed.last = NULL;
241 
242 	kernel_initialized = B_TRUE;
243 	kernel_pid = initialize_pid;
244 
245 	(void) pthread_mutex_unlock(&globalmutex);
246 
247 	return (CKR_OK);
248 
249 }
250 
251 
252 /*
253  * C_Finalize is a wrapper around finalize_common. The
254  * globalmutex should be locked by C_Finalize().
255  */
256 CK_RV
257 C_Finalize(CK_VOID_PTR pReserved)
258 {
259 	int i;
260 
261 	(void) pthread_mutex_lock(&globalmutex);
262 
263 	if (!kernel_initialized) {
264 		(void) pthread_mutex_unlock(&globalmutex);
265 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
266 	}
267 
268 	/* Check to see if pReseved is NULL */
269 	if (pReserved != NULL) {
270 		(void) pthread_mutex_unlock(&globalmutex);
271 		return (CKR_ARGUMENTS_BAD);
272 	}
273 
274 	/*
275 	 * Delete all the sessions for each slot and release the allocated
276 	 * resources
277 	 */
278 	for (i = 0; i < slot_count; i++) {
279 		kernel_delete_all_sessions(i, B_FALSE);
280 	}
281 
282 	finalize_common();
283 
284 	(void) pthread_mutex_unlock(&globalmutex);
285 
286 	return (CKR_OK);
287 }
288 
289 /*
290  * finalize_common() does the work for C_Finalize.  globalmutex
291  * must be held before calling this function.
292  */
293 static void
294 finalize_common() {
295 
296 	int i;
297 	kmh_elem_t *elem, *next;
298 	kernel_object_t *delay_free_obj, *tmpo;
299 	kernel_session_t *delay_free_ses, *tmps;
300 
301 	/*
302 	 * Free the resources allocated for the slot table and reset
303 	 * slot_count to 0.
304 	 */
305 	if (slot_count > 0) {
306 		for (i = 0; i < slot_count; i++) {
307 			(void) pthread_mutex_destroy(&slot_table[i]->sl_mutex);
308 			(void) free(slot_table[i]);
309 		}
310 		(void) free(slot_table);
311 		slot_count = 0;
312 	}
313 
314 	/* Close CRYPTO_DEVICE */
315 	if (kernel_fd >= 0) {
316 		(void) close(kernel_fd);
317 	}
318 
319 	/* Walk the hash table and free all entries */
320 	for (i = 0; i < KMECH_HASHTABLE_SIZE; i++) {
321 		elem = kernel_mechhash[i];
322 		while (elem != NULL) {
323 			next = elem->knext;
324 			free(elem);
325 			elem = next;
326 		}
327 	}
328 
329 	free(kernel_mechhash);
330 
331 	kernel_fd = -1;
332 	kernel_initialized = B_FALSE;
333 	kernel_pid = 0;
334 
335 	/*
336 	 * free all entries in the delay_freed list
337 	 */
338 	delay_free_obj = obj_delay_freed.first;
339 	while (delay_free_obj != NULL) {
340 		tmpo = delay_free_obj->next;
341 		free(delay_free_obj);
342 		delay_free_obj = tmpo;
343 	}
344 	(void) pthread_mutex_destroy(&obj_delay_freed.obj_to_be_free_mutex);
345 
346 	delay_free_ses = ses_delay_freed.first;
347 	while (delay_free_ses != NULL) {
348 		tmps = delay_free_ses->next;
349 		free(delay_free_ses);
350 		delay_free_ses = tmps;
351 	}
352 	(void) pthread_mutex_destroy(&ses_delay_freed.ses_to_be_free_mutex);
353 }
354 
355 /*
356  * This function cleans up all the resources in the library (user space only)
357  */
358 static void
359 cleanup_library()
360 {
361 	int i;
362 
363 	/*
364 	 * Delete all the sessions for each slot and release the allocated
365 	 * resources from the library.  The boolean argument TRUE indicates
366 	 * that we only wants to clean up the resource in the library only.
367 	 * We don't want to clean up the corresponding kernel part of
368 	 * resources, because they are used by the parent process still.
369 	 */
370 
371 	for (i = 0; i < slot_count; i++) {
372 		kernel_delete_all_sessions(i, B_TRUE);
373 	}
374 
375 	finalize_common();
376 }
377 
378 /*
379  * kernel_fini() function required to make sure complete cleanup
380  * is done if pkcs11_kernel is ever unloaded without
381  * a C_Finalize() call.
382  */
383 static void
384 kernel_fini()
385 {
386 
387 	(void) pthread_mutex_lock(&globalmutex);
388 
389 	/* if we're not initilized, do not attempt to finalize */
390 	if (!kernel_initialized) {
391 		(void) pthread_mutex_unlock(&globalmutex);
392 		return;
393 	}
394 
395 	cleanup_library();
396 
397 	(void) pthread_mutex_unlock(&globalmutex);
398 }
399 
400 CK_RV
401 C_GetInfo(CK_INFO_PTR pInfo)
402 {
403 	if (!kernel_initialized)
404 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
405 
406 	if (pInfo == NULL) {
407 		return (CKR_ARGUMENTS_BAD);
408 	}
409 
410 	/* Check if the cryptoki was initialized */
411 
412 	pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR;
413 	pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR;
414 	(void) strncpy((char *)pInfo->manufacturerID,
415 	    MANUFACTURER_ID, 32);
416 	pInfo->flags = 0;
417 	(void) strncpy((char *)pInfo->libraryDescription,
418 	    LIBRARY_DESCRIPTION, 32);
419 	pInfo->libraryVersion.major = LIBRARY_VERSION_MAJOR;
420 	pInfo->libraryVersion.minor = LIBRARY_VERSION_MINOR;
421 
422 	return (CKR_OK);
423 }
424 
425 CK_RV
426 C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
427 {
428 	if (ppFunctionList == NULL) {
429 		return (CKR_ARGUMENTS_BAD);
430 	}
431 
432 	*ppFunctionList = &functionList;
433 
434 	return (CKR_OK);
435 }
436 
437 /*
438  * PKCS#11 states that C_GetFunctionStatus should always return
439  * CKR_FUNCTION_NOT_PARALLEL
440  */
441 /*ARGSUSED*/
442 CK_RV
443 C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
444 {
445 	return (CKR_FUNCTION_NOT_PARALLEL);
446 }
447 
448 /*
449  * PKCS#11 states that C_CancelFunction should always return
450  * CKR_FUNCTION_NOT_PARALLEL
451  */
452 /*ARGSUSED*/
453 CK_RV
454 C_CancelFunction(CK_SESSION_HANDLE hSession)
455 {
456 	return (CKR_FUNCTION_NOT_PARALLEL);
457 }
458