xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_softtoken/common/softGeneral.c (revision d8a7fe16f62711cdc5c4267da8b34ff24a6b668c)
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 <strings.h>
27 #include <errno.h>
28 #include <cryptoutil.h>
29 #include <unistd.h> /* for pid_t */
30 #include <pthread.h>
31 #include <security/cryptoki.h>
32 #include "softGlobal.h"
33 #include "softSession.h"
34 #include "softObject.h"
35 #include "softKeystore.h"
36 #include "softKeystoreUtil.h"
37 
38 #pragma init(softtoken_init)
39 #pragma fini(softtoken_fini)
40 
41 extern soft_session_t token_session; /* for fork handler */
42 
43 static struct CK_FUNCTION_LIST functionList = {
44 	{ 2, 20 },	/* version */
45 	C_Initialize,
46 	C_Finalize,
47 	C_GetInfo,
48 	C_GetFunctionList,
49 	C_GetSlotList,
50 	C_GetSlotInfo,
51 	C_GetTokenInfo,
52 	C_GetMechanismList,
53 	C_GetMechanismInfo,
54 	C_InitToken,
55 	C_InitPIN,
56 	C_SetPIN,
57 	C_OpenSession,
58 	C_CloseSession,
59 	C_CloseAllSessions,
60 	C_GetSessionInfo,
61 	C_GetOperationState,
62 	C_SetOperationState,
63 	C_Login,
64 	C_Logout,
65 	C_CreateObject,
66 	C_CopyObject,
67 	C_DestroyObject,
68 	C_GetObjectSize,
69 	C_GetAttributeValue,
70 	C_SetAttributeValue,
71 	C_FindObjectsInit,
72 	C_FindObjects,
73 	C_FindObjectsFinal,
74 	C_EncryptInit,
75 	C_Encrypt,
76 	C_EncryptUpdate,
77 	C_EncryptFinal,
78 	C_DecryptInit,
79 	C_Decrypt,
80 	C_DecryptUpdate,
81 	C_DecryptFinal,
82 	C_DigestInit,
83 	C_Digest,
84 	C_DigestUpdate,
85 	C_DigestKey,
86 	C_DigestFinal,
87 	C_SignInit,
88 	C_Sign,
89 	C_SignUpdate,
90 	C_SignFinal,
91 	C_SignRecoverInit,
92 	C_SignRecover,
93 	C_VerifyInit,
94 	C_Verify,
95 	C_VerifyUpdate,
96 	C_VerifyFinal,
97 	C_VerifyRecoverInit,
98 	C_VerifyRecover,
99 	C_DigestEncryptUpdate,
100 	C_DecryptDigestUpdate,
101 	C_SignEncryptUpdate,
102 	C_DecryptVerifyUpdate,
103 	C_GenerateKey,
104 	C_GenerateKeyPair,
105 	C_WrapKey,
106 	C_UnwrapKey,
107 	C_DeriveKey,
108 	C_SeedRandom,
109 	C_GenerateRandom,
110 	C_GetFunctionStatus,
111 	C_CancelFunction,
112 	C_WaitForSlotEvent
113 };
114 
115 boolean_t softtoken_initialized = B_FALSE;
116 
117 static pid_t softtoken_pid = 0;
118 
119 /* This mutex protects soft_session_list, all_sessions_closing */
120 pthread_mutex_t soft_sessionlist_mutex;
121 soft_session_t *soft_session_list = NULL;
122 
123 int all_sessions_closing = 0;
124 
125 slot_t soft_slot;
126 obj_to_be_freed_list_t obj_delay_freed;
127 ses_to_be_freed_list_t ses_delay_freed;
128 
129 /* protects softtoken_initialized and access to C_Initialize/C_Finalize */
130 pthread_mutex_t soft_giant_mutex = PTHREAD_MUTEX_INITIALIZER;
131 
132 /* fips mode setting */
133 int softtoken_fips_mode = CRYPTO_FIPS_MODE_DISABLED;
134 
135 static CK_RV finalize_common(boolean_t force, CK_VOID_PTR pReserved);
136 static void softtoken_init();
137 static void softtoken_fini();
138 static void softtoken_fork_prepare();
139 static void softtoken_fork_after();
140 
141 CK_RV
142 C_Initialize(CK_VOID_PTR pInitArgs)
143 {
144 
145 	int initialize_pid;
146 	boolean_t supplied_ok;
147 	CK_RV rv;
148 
149 	/*
150 	 * Get lock to insure only one thread enters this
151 	 * function at a time.
152 	 */
153 	(void) pthread_mutex_lock(&soft_giant_mutex);
154 
155 	initialize_pid = getpid();
156 
157 	if (softtoken_initialized) {
158 		if (initialize_pid == softtoken_pid) {
159 			/*
160 			 * This process has called C_Initialize already
161 			 */
162 			(void) pthread_mutex_unlock(&soft_giant_mutex);
163 			return (CKR_CRYPTOKI_ALREADY_INITIALIZED);
164 		} else {
165 			/*
166 			 * A fork has happened and the child is
167 			 * reinitializing.  Do a finalize_common to close
168 			 * out any state from the parent, and then
169 			 * continue on.
170 			 */
171 			(void) finalize_common(B_TRUE, NULL);
172 		}
173 	}
174 
175 	if (pInitArgs != NULL) {
176 		CK_C_INITIALIZE_ARGS *initargs1 =
177 		    (CK_C_INITIALIZE_ARGS *) pInitArgs;
178 
179 		/* pReserved must be NULL */
180 		if (initargs1->pReserved != NULL) {
181 			(void) pthread_mutex_unlock(&soft_giant_mutex);
182 			return (CKR_ARGUMENTS_BAD);
183 		}
184 
185 		/*
186 		 * ALL supplied function pointers need to have the value
187 		 * either NULL or non-NULL.
188 		 */
189 		supplied_ok = (initargs1->CreateMutex == NULL &&
190 		    initargs1->DestroyMutex == NULL &&
191 		    initargs1->LockMutex == NULL &&
192 		    initargs1->UnlockMutex == NULL) ||
193 		    (initargs1->CreateMutex != NULL &&
194 		    initargs1->DestroyMutex != NULL &&
195 		    initargs1->LockMutex != NULL &&
196 		    initargs1->UnlockMutex != NULL);
197 
198 		if (!supplied_ok) {
199 			(void) pthread_mutex_unlock(&soft_giant_mutex);
200 			return (CKR_ARGUMENTS_BAD);
201 		}
202 
203 		/*
204 		 * When the CKF_OS_LOCKING_OK flag isn't set and mutex
205 		 * function pointers are supplied by an application,
206 		 * return an error.  We must be able to use our own primitives.
207 		 */
208 		if (!(initargs1->flags & CKF_OS_LOCKING_OK) &&
209 		    (initargs1->CreateMutex != NULL)) {
210 			(void) pthread_mutex_unlock(&soft_giant_mutex);
211 			return (CKR_CANT_LOCK);
212 		}
213 	}
214 
215 	/* Initialize the session list lock */
216 	if (pthread_mutex_init(&soft_sessionlist_mutex, NULL) != 0) {
217 		(void) pthread_mutex_unlock(&soft_giant_mutex);
218 		return (CKR_CANT_LOCK);
219 	}
220 
221 	/*
222 	 * token object related initialization
223 	 */
224 	soft_slot.authenticated = 0;
225 	soft_slot.userpin_change_needed = 0;
226 	soft_slot.token_object_list = NULL;
227 	soft_slot.keystore_load_status = KEYSTORE_UNINITIALIZED;
228 
229 	if ((rv = soft_init_token_session()) != CKR_OK) {
230 		(void) pthread_mutex_destroy(&soft_sessionlist_mutex);
231 		(void) pthread_mutex_unlock(&soft_giant_mutex);
232 		return (rv);
233 	}
234 
235 	/* Initialize the slot lock */
236 	if (pthread_mutex_init(&soft_slot.slot_mutex, NULL) != 0) {
237 		(void) pthread_mutex_destroy(&soft_sessionlist_mutex);
238 		(void) soft_destroy_token_session();
239 		(void) pthread_mutex_unlock(&soft_giant_mutex);
240 		return (CKR_CANT_LOCK);
241 	}
242 
243 	/* Initialize the keystore lock */
244 	if (pthread_mutex_init(&soft_slot.keystore_mutex, NULL) != 0) {
245 		(void) pthread_mutex_destroy(&soft_slot.slot_mutex);
246 		(void) pthread_mutex_destroy(&soft_sessionlist_mutex);
247 		(void) soft_destroy_token_session();
248 		(void) pthread_mutex_unlock(&soft_giant_mutex);
249 		return (CKR_CANT_LOCK);
250 	}
251 
252 	/* Initialize the object_to_be_freed list */
253 	if (pthread_mutex_init(&obj_delay_freed.obj_to_be_free_mutex, NULL)
254 	    != 0) {
255 		(void) pthread_mutex_destroy(&soft_slot.keystore_mutex);
256 		(void) pthread_mutex_destroy(&soft_slot.slot_mutex);
257 		(void) pthread_mutex_destroy(&soft_sessionlist_mutex);
258 		(void) soft_destroy_token_session();
259 		(void) pthread_mutex_unlock(&soft_giant_mutex);
260 		return (CKR_CANT_LOCK);
261 	}
262 	obj_delay_freed.count = 0;
263 	obj_delay_freed.first = NULL;
264 	obj_delay_freed.last = NULL;
265 
266 	if (pthread_mutex_init(&ses_delay_freed.ses_to_be_free_mutex, NULL)
267 	    != 0) {
268 		(void) pthread_mutex_destroy(
269 		    &obj_delay_freed.obj_to_be_free_mutex);
270 		(void) pthread_mutex_destroy(&soft_slot.keystore_mutex);
271 		(void) pthread_mutex_destroy(&soft_slot.slot_mutex);
272 		(void) pthread_mutex_destroy(&soft_sessionlist_mutex);
273 		(void) soft_destroy_token_session();
274 		(void) pthread_mutex_unlock(&soft_giant_mutex);
275 		return (CKR_CANT_LOCK);
276 	}
277 	ses_delay_freed.count = 0;
278 	ses_delay_freed.first = NULL;
279 	ses_delay_freed.last = NULL;
280 
281 	/*
282 	 * Perform POST when fips mode is enabled.
283 	 */
284 	if ((rv = get_fips_mode(&softtoken_fips_mode)) == CKR_OK) {
285 		if (softtoken_fips_mode == CRYPTO_FIPS_MODE_ENABLED) {
286 			rv = soft_fips_post();
287 		}
288 	}
289 
290 	if (rv != CKR_OK) {
291 		(void) pthread_mutex_destroy(
292 		    &ses_delay_freed.ses_to_be_free_mutex);
293 		(void) pthread_mutex_destroy(
294 		    &obj_delay_freed.obj_to_be_free_mutex);
295 		(void) pthread_mutex_destroy(&soft_slot.keystore_mutex);
296 		(void) pthread_mutex_destroy(&soft_slot.slot_mutex);
297 		(void) pthread_mutex_destroy(&soft_sessionlist_mutex);
298 		(void) soft_destroy_token_session();
299 		(void) pthread_mutex_unlock(&soft_giant_mutex);
300 		return (CKR_FUNCTION_FAILED);
301 	}
302 
303 	softtoken_pid = initialize_pid;
304 	softtoken_initialized = B_TRUE;
305 	(void) pthread_mutex_unlock(&soft_giant_mutex);
306 
307 	return (CKR_OK);
308 }
309 
310 /*
311  * C_Finalize is a wrapper around finalize_common. The
312  * soft_giant_mutex should be locked by C_Finalize().
313  */
314 CK_RV
315 C_Finalize(CK_VOID_PTR pReserved)
316 {
317 
318 	CK_RV rv;
319 
320 	(void) pthread_mutex_lock(&soft_giant_mutex);
321 
322 	rv = finalize_common(B_FALSE, pReserved);
323 
324 	(void) pthread_mutex_unlock(&soft_giant_mutex);
325 
326 	return (rv);
327 
328 }
329 
330 /*
331  * finalize_common() does the work for C_Finalize.  soft_giant_mutex
332  * must be held before calling this function.
333  */
334 static CK_RV
335 finalize_common(boolean_t force, CK_VOID_PTR pReserved) {
336 
337 	CK_RV rv = CKR_OK;
338 	struct object *delay_free_obj, *tmpo;
339 	struct session *delay_free_ses, *tmps;
340 
341 	if (!softtoken_initialized) {
342 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
343 	}
344 
345 	/* Check to see if pReseved is NULL */
346 	if (pReserved != NULL) {
347 		return (CKR_ARGUMENTS_BAD);
348 	}
349 
350 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
351 	/*
352 	 * Set all_sessions_closing flag so any access to any
353 	 * existing sessions will be rejected.
354 	 */
355 	all_sessions_closing = 1;
356 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
357 
358 	/* Delete all the sessions and release the allocated resources */
359 	rv = soft_delete_all_sessions(force);
360 
361 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
362 	/* Reset all_sessions_closing flag. */
363 	all_sessions_closing = 0;
364 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
365 
366 	softtoken_initialized = B_FALSE;
367 	softtoken_pid = 0;
368 
369 	pkcs11_close_urandom();
370 	pkcs11_close_urandom_seed();
371 	pkcs11_close_random();
372 
373 	/* Destroy the session list lock here */
374 	(void) pthread_mutex_destroy(&soft_sessionlist_mutex);
375 
376 	/*
377 	 * Destroy token object related stuffs
378 	 * 1. Clean up the token object list
379 	 * 2. Destroy slot mutex
380 	 * 3. Destroy mutex in token_session
381 	 */
382 	soft_delete_all_in_core_token_objects(ALL_TOKEN);
383 	(void) pthread_mutex_destroy(&soft_slot.slot_mutex);
384 	(void) pthread_mutex_destroy(&soft_slot.keystore_mutex);
385 	(void) soft_destroy_token_session();
386 
387 	/*
388 	 * free all entries in the delay_freed list
389 	 */
390 	delay_free_obj = obj_delay_freed.first;
391 	while (delay_free_obj != NULL) {
392 		tmpo = delay_free_obj->next;
393 		free(delay_free_obj);
394 		delay_free_obj = tmpo;
395 	}
396 
397 	soft_slot.keystore_load_status = KEYSTORE_UNINITIALIZED;
398 	(void) pthread_mutex_destroy(&obj_delay_freed.obj_to_be_free_mutex);
399 
400 	delay_free_ses = ses_delay_freed.first;
401 	while (delay_free_ses != NULL) {
402 		tmps = delay_free_ses->next;
403 		free(delay_free_ses);
404 		delay_free_ses = tmps;
405 	}
406 	(void) pthread_mutex_destroy(&ses_delay_freed.ses_to_be_free_mutex);
407 
408 	return (rv);
409 }
410 
411 static void
412 softtoken_init()
413 {
414 	/* Children inherit parent's atfork handlers */
415 	(void) pthread_atfork(softtoken_fork_prepare,
416 	    softtoken_fork_after, softtoken_fork_after);
417 }
418 
419 /*
420  * softtoken_fini() function required to make sure complete cleanup
421  * is done if softtoken is ever unloaded without a C_Finalize() call.
422  */
423 static void
424 softtoken_fini()
425 {
426 	(void) pthread_mutex_lock(&soft_giant_mutex);
427 
428 	/* if we're not initilized, do not attempt to finalize */
429 	if (!softtoken_initialized) {
430 		(void) pthread_mutex_unlock(&soft_giant_mutex);
431 		return;
432 	}
433 
434 	(void) finalize_common(B_TRUE, NULL_PTR);
435 
436 	(void) pthread_mutex_unlock(&soft_giant_mutex);
437 }
438 
439 CK_RV
440 C_GetInfo(CK_INFO_PTR pInfo)
441 {
442 	if (!softtoken_initialized)
443 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
444 
445 	if (pInfo == NULL) {
446 		return (CKR_ARGUMENTS_BAD);
447 	}
448 
449 	/* Provide general information in the provided buffer */
450 	pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR;
451 	pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR;
452 	(void) strncpy((char *)pInfo->manufacturerID,
453 	    SOFT_MANUFACTURER_ID, 32);
454 	pInfo->flags = 0;
455 	(void) strncpy((char *)pInfo->libraryDescription,
456 	    LIBRARY_DESCRIPTION, 32);
457 	pInfo->libraryVersion.major = LIBRARY_VERSION_MAJOR;
458 	pInfo->libraryVersion.minor = LIBRARY_VERSION_MINOR;
459 
460 	return (CKR_OK);
461 }
462 
463 CK_RV
464 C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
465 {
466 	if (ppFunctionList == NULL) {
467 		return (CKR_ARGUMENTS_BAD);
468 	}
469 
470 	*ppFunctionList = &functionList;
471 
472 	return (CKR_OK);
473 }
474 
475 /*
476  * PKCS#11 states that C_GetFunctionStatus should always return
477  * CKR_FUNCTION_NOT_PARALLEL
478  */
479 /*ARGSUSED*/
480 CK_RV
481 C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
482 {
483 	return (CKR_FUNCTION_NOT_PARALLEL);
484 }
485 
486 /*
487  * PKCS#11 states that C_CancelFunction should always return
488  * CKR_FUNCTION_NOT_PARALLEL
489  */
490 /*ARGSUSED*/
491 CK_RV
492 C_CancelFunction(CK_SESSION_HANDLE hSession)
493 {
494 	return (CKR_FUNCTION_NOT_PARALLEL);
495 }
496 
497 /*
498  * Take out all mutexes before fork.
499  *
500  * Order:
501  * 1. soft_giant_mutex
502  * 2. soft_sessionlist_mutex
503  * 3. soft_slot.slot_mutex
504  * 4. soft_slot.keystore_mutex
505  * 5. token_session mutexes via soft_acquire_all_session_mutexes()
506  * 6. all soft_session_list mutexes via soft_acquire_all_session_mutexes()
507  * 7. obj_delay_freed.obj_to_be_free_mutex;
508  * 8. ses_delay_freed.ses_to_be_free_mutex
509  */
510 void
511 softtoken_fork_prepare()
512 {
513 	(void) pthread_mutex_lock(&soft_giant_mutex);
514 	if (softtoken_initialized) {
515 		(void) pthread_mutex_lock(&soft_sessionlist_mutex);
516 		(void) pthread_mutex_lock(&soft_slot.slot_mutex);
517 		(void) pthread_mutex_lock(&soft_slot.keystore_mutex);
518 		soft_acquire_all_session_mutexes(&token_session);
519 		soft_acquire_all_session_mutexes(soft_session_list);
520 		(void) pthread_mutex_lock(
521 		    &obj_delay_freed.obj_to_be_free_mutex);
522 		(void) pthread_mutex_lock(
523 		    &ses_delay_freed.ses_to_be_free_mutex);
524 	}
525 }
526 
527 /*
528  * Release in opposite order to softtoken_fork_prepare().
529  * Function is used for parent and child.
530  */
531 void
532 softtoken_fork_after()
533 {
534 	if (softtoken_initialized) {
535 		(void) pthread_mutex_unlock(
536 		    &ses_delay_freed.ses_to_be_free_mutex);
537 		(void) pthread_mutex_unlock(
538 		    &obj_delay_freed.obj_to_be_free_mutex);
539 		soft_release_all_session_mutexes(soft_session_list);
540 		soft_release_all_session_mutexes(&token_session);
541 		(void) pthread_mutex_unlock(&soft_slot.keystore_mutex);
542 		(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
543 		(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
544 	}
545 	(void) pthread_mutex_unlock(&soft_giant_mutex);
546 }
547