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