xref: /titanic_50/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelGeneral.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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, 11 },	/* 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 static CK_RV finalize_common(CK_VOID_PTR pReserved);
123 static void cleanup_library();
124 static void kernel_fini();
125 
126 CK_RV
127 C_Initialize(CK_VOID_PTR pInitArgs)
128 {
129 
130 	int initialize_pid;
131 	boolean_t supplied_ok;
132 	CK_RV rv = CKR_OK;
133 
134 	/*
135 	 * Grab lock to insure that only one thread enters this
136 	 * function at a time.
137 	 */
138 	(void) pthread_mutex_lock(&globalmutex);
139 	initialize_pid = getpid();
140 
141 	if (kernel_initialized) {
142 		if (initialize_pid == kernel_pid) {
143 			/*
144 			 * This process has called C_Initialize already
145 			 */
146 			(void) pthread_mutex_unlock(&globalmutex);
147 			return (CKR_CRYPTOKI_ALREADY_INITIALIZED);
148 		} else {
149 			/*
150 			 * A fork has happened and the child is
151 			 * reinitializing.  Do a cleanup_library to close
152 			 * out any state from the parent, and then
153 			 * continue on.
154 			 */
155 			cleanup_library();
156 		}
157 	}
158 
159 	if (pInitArgs != NULL) {
160 		CK_C_INITIALIZE_ARGS *initargs1 =
161 		    (CK_C_INITIALIZE_ARGS *) pInitArgs;
162 
163 		/* pReserved must be NULL */
164 		if (initargs1->pReserved != NULL) {
165 			(void) pthread_mutex_unlock(&globalmutex);
166 			return (CKR_ARGUMENTS_BAD);
167 		}
168 
169 		/*
170 		 * ALL supplied function pointers need to have the value
171 		 * either NULL or non-NULL.
172 		 */
173 		supplied_ok = (initargs1->CreateMutex == NULL &&
174 		    initargs1->DestroyMutex == NULL &&
175 		    initargs1->LockMutex == NULL &&
176 		    initargs1->UnlockMutex == NULL) ||
177 		    (initargs1->CreateMutex != NULL &&
178 		    initargs1->DestroyMutex != NULL &&
179 		    initargs1->LockMutex != NULL &&
180 		    initargs1->UnlockMutex != NULL);
181 
182 		if (!supplied_ok) {
183 			(void) pthread_mutex_unlock(&globalmutex);
184 			return (CKR_ARGUMENTS_BAD);
185 		}
186 
187 		/*
188 		 * When the CKF_OS_LOCKING_OK flag isn't set and mutex
189 		 * function pointers are supplied by an application,
190 		 * return an error.  We must be able to use our own locks.
191 		 */
192 		if (!(initargs1->flags & CKF_OS_LOCKING_OK) &&
193 		    (initargs1->CreateMutex != NULL)) {
194 			(void) pthread_mutex_unlock(&globalmutex);
195 			return (CKR_CANT_LOCK);
196 		}
197 	}
198 
199 	while ((kernel_fd = open(CRYPTO_DEVICE, O_RDWR)) < 0) {
200 		if (errno != EINTR)
201 			break;
202 	}
203 	if (kernel_fd < 0) {
204 		(void) pthread_mutex_unlock(&globalmutex);
205 		return (CKR_FUNCTION_FAILED);
206 	}
207 
208 	/* Mark kernel_fd "close on exec" */
209 	(void) fcntl(kernel_fd, F_SETFD, FD_CLOEXEC);
210 
211 	/* Initialize the slot table */
212 	rv = kernel_slottable_init();
213 	if (rv != CKR_OK) {
214 		(void) close(kernel_fd);
215 		(void) pthread_mutex_unlock(&globalmutex);
216 		return (rv);
217 	}
218 
219 	kernel_initialized = B_TRUE;
220 	kernel_pid = initialize_pid;
221 
222 	(void) pthread_mutex_unlock(&globalmutex);
223 
224 	return (CKR_OK);
225 
226 }
227 
228 
229 /*
230  * C_Finalize is a wrapper around finalize_common. The
231  * globalmutex should be locked by C_Finalize().
232  */
233 CK_RV
234 C_Finalize(CK_VOID_PTR pReserved)
235 {
236 
237 	CK_RV rv;
238 
239 	(void) pthread_mutex_lock(&globalmutex);
240 
241 	rv = finalize_common(pReserved);
242 
243 	(void) pthread_mutex_unlock(&globalmutex);
244 
245 	return (rv);
246 }
247 
248 /*
249  * finalize_common() does the work for C_Finalize.  globalmutex
250  * must be held before calling this function.
251  */
252 static CK_RV
253 finalize_common(CK_VOID_PTR pReserved) {
254 
255 	int i;
256 
257 	if (!kernel_initialized) {
258 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
259 	}
260 
261 	/* Check to see if pReseved is NULL */
262 	if (pReserved != NULL) {
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 		(void) kernel_delete_all_sessions(i, B_FALSE);
272 	}
273 
274 	/*
275 	 * Free the resources allocated for the slot table and reset
276 	 * slot_count to 0.
277 	 */
278 	if (slot_count > 0) {
279 		for (i = 0; i < slot_count; i++) {
280 			(void) pthread_mutex_destroy(&slot_table[i]->sl_mutex);
281 			(void) free(slot_table[i]);
282 		}
283 		(void) free(slot_table);
284 		slot_count = 0;
285 	}
286 
287 	/* Close CRYPTO_DEVICE */
288 	if (kernel_fd >= 0) {
289 		(void) close(kernel_fd);
290 	}
291 
292 	kernel_fd = -1;
293 	kernel_initialized = B_FALSE;
294 	kernel_pid = 0;
295 
296 	return (CKR_OK);
297 }
298 
299 /*
300  * This function cleans up all the resources in the library (user space only)
301  */
302 static void
303 cleanup_library()
304 {
305 	int i;
306 
307 	/*
308 	 * Delete all the sessions for each slot and release the allocated
309 	 * resources from the library.  The boolean argument TRUE indicates
310 	 * that we only wants to clean up the resource in the library only.
311 	 * We don't want to clean up the corresponding kernel part of
312 	 * resources, because they are used by the parent process still.
313 	 */
314 
315 	for (i = 0; i < slot_count; i++) {
316 		(void) kernel_delete_all_sessions(i, B_TRUE);
317 	}
318 
319 	/*
320 	 * Free the resources allocated for the slot table and reset
321 	 * slot_count to 0.
322 	 */
323 	if (slot_count > 0) {
324 		for (i = 0; i < slot_count; i++) {
325 			(void) pthread_mutex_destroy(&slot_table[i]->sl_mutex);
326 			(void) free(slot_table[i]);
327 		}
328 		(void) free(slot_table);
329 		slot_count = 0;
330 	}
331 
332 	/* Close CRYPTO_DEVICE */
333 	if (kernel_fd >= 0) {
334 		(void) close(kernel_fd);
335 	}
336 
337 	kernel_fd = -1;
338 	kernel_initialized = B_FALSE;
339 	kernel_pid = 0;
340 
341 }
342 
343 /*
344  * kernel_fini() function required to make sure complete cleanup
345  * is done if pkcs11_kernel is ever unloaded without
346  * a C_Finalize() call.
347  */
348 static void
349 kernel_fini()
350 {
351 
352 	(void) pthread_mutex_lock(&globalmutex);
353 
354 	/* if we're not initilized, do not attempt to finalize */
355 	if (!kernel_initialized) {
356 		(void) pthread_mutex_unlock(&globalmutex);
357 		return;
358 	}
359 
360 	cleanup_library();
361 
362 	(void) pthread_mutex_unlock(&globalmutex);
363 }
364 
365 CK_RV
366 C_GetInfo(CK_INFO_PTR pInfo)
367 {
368 	if (!kernel_initialized)
369 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
370 
371 	if (pInfo == NULL) {
372 		return (CKR_ARGUMENTS_BAD);
373 	}
374 
375 	/* Check if the cryptoki was initialized */
376 
377 	pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR;
378 	pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR;
379 	(void) strncpy((char *)pInfo->manufacturerID,
380 	    MANUFACTURER_ID, 32);
381 	pInfo->flags = 0;
382 	(void) strncpy((char *)pInfo->libraryDescription,
383 	    LIBRARY_DESCRIPTION, 32);
384 	pInfo->libraryVersion.major = LIBRARY_VERSION_MAJOR;
385 	pInfo->libraryVersion.minor = LIBRARY_VERSION_MINOR;
386 
387 	return (CKR_OK);
388 }
389 
390 CK_RV
391 C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
392 {
393 	if (ppFunctionList == NULL) {
394 		return (CKR_ARGUMENTS_BAD);
395 	}
396 
397 	*ppFunctionList = &functionList;
398 
399 	return (CKR_OK);
400 }
401 
402 /*
403  * PKCS#11 states that C_GetFunctionStatus should always return
404  * CKR_FUNCTION_NOT_PARALLEL
405  */
406 /*ARGSUSED*/
407 CK_RV
408 C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
409 {
410 	return (CKR_FUNCTION_NOT_PARALLEL);
411 }
412 
413 /*
414  * PKCS#11 states that C_CancelFunction should always return
415  * CKR_FUNCTION_NOT_PARALLEL
416  */
417 /*ARGSUSED*/
418 CK_RV
419 C_CancelFunction(CK_SESSION_HANDLE hSession)
420 {
421 	return (CKR_FUNCTION_NOT_PARALLEL);
422 }
423