xref: /onnv-gate/usr/src/lib/pkcs11/pkcs11_kms/common/kmsGeneral.c (revision 12720:3db6e0082404)
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  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
22  */
23 
24 #include <fcntl.h>
25 #include <pthread.h>
26 #include <strings.h>
27 #include <unistd.h> /* for pid */
28 #include <errno.h>
29 #include <security/cryptoki.h>
30 
31 #include "kmsKeystoreUtil.h"
32 #include "kmsGlobal.h"
33 #include "kmsSession.h"
34 #include "kmsSlot.h"
35 
36 /*
37  * PKCS#11 KMS Crypto provider module.
38  *
39  * This module provides access to a Key Management System (v 2.0)
40  * through the Solaris Cryptographic Framework interfaces  (PKCS#11).
41  *
42  * PREREQUISITES
43  * =============
44  * 1. You must have access to a KMS on the network and you must
45  * know the IP address and name of the "Agent" assigned to
46  * you and the passphrase needed to access the Agent information.
47  *
48  * 2. The token configuration must be completed prior
49  * to using this provider using the kmscfg(1m) utility.
50  *
51  * This provider provides support for 3 AES mechanisms:
52  * CKM_AES_KEY_GEN (for 256 bit keys only)
53  * CKM_AES_CBC (encrypt/decrypt)
54  * CKM_AES_CBC_PAD (encrypt/decrypt)
55  *
56  * DETAILS
57  * =======
58  * Each user has their own local configuration for the KMS.
59  * The local configuration information is typically located
60  * in a private token directory - /var/tmp/kms/$USERNAME
61  * The location may be overridden using an environment variable
62  * $KMSTOKEN_DIR.  The user's private token namespace is configured
63  * using kmscfg(1M) which establishes the directory and populates
64  * it with a simple configuration file that this module later uses
65  * to access the KMS.
66  *
67  * INITIALIZING
68  * ============
69  * Once the token configuration is established, C_InitToken
70  * is used to initialize the first contact with the KMS.  This
71  * will cause the provider to contact the KMS and download
72  * the profile configuration data, a server certificate, and a
73  * private entity key and certificate (in a PKCS#12 file).
74  * Once the above data is collected it is stored under $KMSTOKEN_DIR.
75  * The user may then proceed with normal PKCS#11 activity.
76  *
77  * LOGIN
78  * =====
79  * The concept of a "Login" is established when the user provides
80  * a PIN that will successfully unwrap the private data in the
81  * PKCS#12 file downloaded earlier when C_InitToken was called.
82  * If the PKCS#12 file is successfully opened, then the user
83  * is considered "logged in" and may use the private key and
84  * certificate to initiate secure communications with the KMS.
85  *
86  * CHANGE PIN
87  * ==========
88  * The C_SetPIN interface may be used to change the passphrase
89  * on the PKCS#12 file and thus effectively change the passphrase
90  * for the token itself (even though the wrapped private key and
91  * certificate do not change).
92  *
93  * KEY STORAGE
94  * ===========
95  * Keys generated in the KMS are always kept securely in the KMS.
96  * The local token area contains only a list of CKA_LABEL values
97  * for all successfully created keys, no sensitive key data
98  * is stored on the client system.  When a key is "destroyed", the
99  * local references to that key's label is removed and it is no
100  * longer visible to the token provider.
101  *
102  * NOTE: The KMS itself does not have an interface for destroying
103  * keys, it only allows for the keys to be disassociated from
104  * a particular "DataUnit". Key labels should not be re-used.
105  */
106 #pragma init(kms_init)
107 #pragma fini(kms_fini)
108 
109 static struct CK_FUNCTION_LIST functionList = {
110 	{ 2, 20 },	/* version */
111 	C_Initialize,
112 	C_Finalize,
113 	C_GetInfo,
114 	C_GetFunctionList,
115 	C_GetSlotList,
116 	C_GetSlotInfo,
117 	C_GetTokenInfo,
118 	C_GetMechanismList,
119 	C_GetMechanismInfo,
120 	C_InitToken,
121 	C_InitPIN,
122 	C_SetPIN,
123 	C_OpenSession,
124 	C_CloseSession,
125 	C_CloseAllSessions,
126 	C_GetSessionInfo,
127 	C_GetOperationState,
128 	C_SetOperationState,
129 	C_Login,
130 	C_Logout,
131 	C_CreateObject,
132 	C_CopyObject,
133 	C_DestroyObject,
134 	C_GetObjectSize,
135 	C_GetAttributeValue,
136 	C_SetAttributeValue,
137 	C_FindObjectsInit,
138 	C_FindObjects,
139 	C_FindObjectsFinal,
140 	C_EncryptInit,
141 	C_Encrypt,
142 	C_EncryptUpdate,
143 	C_EncryptFinal,
144 	C_DecryptInit,
145 	C_Decrypt,
146 	C_DecryptUpdate,
147 	C_DecryptFinal,
148 	C_DigestInit,
149 	C_Digest,
150 	C_DigestUpdate,
151 	C_DigestKey,
152 	C_DigestFinal,
153 	C_SignInit,
154 	C_Sign,
155 	C_SignUpdate,
156 	C_SignFinal,
157 	C_SignRecoverInit,
158 	C_SignRecover,
159 	C_VerifyInit,
160 	C_Verify,
161 	C_VerifyUpdate,
162 	C_VerifyFinal,
163 	C_VerifyRecoverInit,
164 	C_VerifyRecover,
165 	C_DigestEncryptUpdate,
166 	C_DecryptDigestUpdate,
167 	C_SignEncryptUpdate,
168 	C_DecryptVerifyUpdate,
169 	C_GenerateKey,
170 	C_GenerateKeyPair,
171 	C_WrapKey,
172 	C_UnwrapKey,
173 	C_DeriveKey,
174 	C_SeedRandom,
175 	C_GenerateRandom,
176 	C_GetFunctionStatus,
177 	C_CancelFunction,
178 	C_WaitForSlotEvent
179 };
180 
181 boolean_t kms_initialized = B_FALSE;
182 static pid_t kms_pid = 0;
183 
184 
185 /* protects kms_initialized and entrance to C_Initialize/Finalize */
186 static pthread_mutex_t globalmutex = PTHREAD_MUTEX_INITIALIZER;
187 
188 ses_to_be_freed_list_t ses_delay_freed;
189 object_to_be_freed_list_t obj_delay_freed;
190 kms_elem_t **kms_mechhash;	/* Hash table for kCF mech numbers */
191 
192 static void kms_finalize_common();
193 static void kms_cleanup_library();
194 static void kms_init();
195 static void kms_fini();
196 static void kms_fork_prepare();
197 static void kms_fork_after();
198 
199 CK_RV
C_Initialize(CK_VOID_PTR pInitArgs)200 C_Initialize(CK_VOID_PTR pInitArgs)
201 {
202 	int initialize_pid;
203 	boolean_t supplied_ok;
204 	CK_RV rv = CKR_OK;
205 
206 	/*
207 	 * Grab lock to insure that only one thread enters this
208 	 * function at a time.
209 	 */
210 	(void) pthread_mutex_lock(&globalmutex);
211 	initialize_pid = getpid();
212 
213 	if (kms_initialized) {
214 		if (initialize_pid == kms_pid) {
215 			/*
216 			 * This process has called C_Initialize already
217 			 */
218 			(void) pthread_mutex_unlock(&globalmutex);
219 			return (CKR_CRYPTOKI_ALREADY_INITIALIZED);
220 		} else {
221 			/*
222 			 * A fork has happened and the child is
223 			 * reinitializing.  Do a kms_cleanup_library to close
224 			 * out any state from the parent, and then
225 			 * continue on.
226 			 */
227 			kms_cleanup_library();
228 		}
229 	}
230 
231 	if (pInitArgs != NULL) {
232 		CK_C_INITIALIZE_ARGS *initargs1 =
233 		    (CK_C_INITIALIZE_ARGS *) pInitArgs;
234 
235 		/* pReserved must be NULL */
236 		if (initargs1->pReserved != NULL) {
237 			(void) pthread_mutex_unlock(&globalmutex);
238 			return (CKR_ARGUMENTS_BAD);
239 		}
240 
241 		/*
242 		 * ALL supplied function pointers need to have the value
243 		 * either NULL or non-NULL.
244 		 */
245 		supplied_ok = (initargs1->CreateMutex == NULL &&
246 		    initargs1->DestroyMutex == NULL &&
247 		    initargs1->LockMutex == NULL &&
248 		    initargs1->UnlockMutex == NULL) ||
249 		    (initargs1->CreateMutex != NULL &&
250 		    initargs1->DestroyMutex != NULL &&
251 		    initargs1->LockMutex != NULL &&
252 		    initargs1->UnlockMutex != NULL);
253 
254 		if (!supplied_ok) {
255 			(void) pthread_mutex_unlock(&globalmutex);
256 			return (CKR_ARGUMENTS_BAD);
257 		}
258 
259 		/*
260 		 * When the CKF_OS_LOCKING_OK flag isn't set and mutex
261 		 * function pointers are supplied by an application,
262 		 * return an error.  We must be able to use our own locks.
263 		 */
264 		if (!(initargs1->flags & CKF_OS_LOCKING_OK) &&
265 		    (initargs1->CreateMutex != NULL)) {
266 			(void) pthread_mutex_unlock(&globalmutex);
267 			return (CKR_CANT_LOCK);
268 		}
269 	}
270 
271 	/* Create the hash table */
272 	kms_mechhash = calloc(KMECH_HASHTABLE_SIZE, sizeof (void *));
273 	if (kms_mechhash == NULL) {
274 		(void) pthread_mutex_unlock(&globalmutex);
275 		return (CKR_HOST_MEMORY);
276 	}
277 
278 	/* Initialize the slot table */
279 	rv = kms_slottable_init();
280 	if (rv != CKR_OK) {
281 		free(kms_mechhash);
282 		goto end;
283 	}
284 
285 	/* Initialize the object_to_be_freed list */
286 	(void) pthread_mutex_init(&obj_delay_freed.obj_to_be_free_mutex, NULL);
287 	obj_delay_freed.count = 0;
288 	obj_delay_freed.first = NULL;
289 	obj_delay_freed.last = NULL;
290 
291 	/* Initialize the session_to_be_freed list */
292 	(void) pthread_mutex_init(&ses_delay_freed.ses_to_be_free_mutex, NULL);
293 	ses_delay_freed.count = 0;
294 	ses_delay_freed.first = NULL;
295 	ses_delay_freed.last = NULL;
296 
297 	rv = KMS_Initialize();
298 	if (rv != CKR_OK) {
299 		free(kms_mechhash);
300 		goto end;
301 	}
302 
303 	kms_initialized = B_TRUE;
304 	kms_pid = initialize_pid;
305 
306 end:
307 	(void) pthread_mutex_unlock(&globalmutex);
308 
309 	return (CKR_OK);
310 }
311 
312 /*
313  * C_Finalize is a wrapper around kms_finalize_common. The
314  * globalmutex should be locked by C_Finalize().
315  */
316 CK_RV
C_Finalize(CK_VOID_PTR pReserved)317 C_Finalize(CK_VOID_PTR pReserved)
318 {
319 	(void) pthread_mutex_lock(&globalmutex);
320 
321 	if (!kms_initialized) {
322 		(void) pthread_mutex_unlock(&globalmutex);
323 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
324 	}
325 
326 	/* Check to see if pReseved is NULL */
327 	if (pReserved != NULL) {
328 		(void) pthread_mutex_unlock(&globalmutex);
329 		return (CKR_ARGUMENTS_BAD);
330 	}
331 
332 	/*
333 	 * Delete all the sessions for each slot and release the allocated
334 	 * resources
335 	 */
336 	kms_delete_all_sessions(B_FALSE);
337 
338 	kms_finalize_common();
339 
340 	(void) pthread_mutex_unlock(&globalmutex);
341 
342 	return (CKR_OK);
343 }
344 
345 /*
346  * kms_finalize_common() does the work for C_Finalize.  globalmutex
347  * must be held before calling this function.
348  */
349 static void
kms_finalize_common()350 kms_finalize_common() {
351 
352 	int i;
353 	kms_elem_t *elem, *next;
354 	kms_object_t *delay_free_obj, *tmpo;
355 	kms_session_t *delay_free_ses, *tmps;
356 
357 	cleanup_slottable();
358 	/* Walk the hash table and free all entries */
359 	for (i = 0; i < KMECH_HASHTABLE_SIZE; i++) {
360 		elem = kms_mechhash[i];
361 		while (elem != NULL) {
362 			next = elem->knext;
363 			free(elem);
364 			elem = next;
365 		}
366 	}
367 
368 	free(kms_mechhash);
369 
370 	kms_mechhash = NULL;
371 	kms_initialized = B_FALSE;
372 	kms_pid = 0;
373 
374 	/*
375 	 * free all entries in the delay_freed list
376 	 */
377 	delay_free_obj = obj_delay_freed.first;
378 	while (delay_free_obj != NULL) {
379 		tmpo = delay_free_obj->next;
380 		free(delay_free_obj);
381 		delay_free_obj = tmpo;
382 	}
383 	obj_delay_freed.count = 0;
384 	obj_delay_freed.first = NULL;
385 	obj_delay_freed.last = NULL;
386 	(void) pthread_mutex_destroy(&obj_delay_freed.obj_to_be_free_mutex);
387 
388 	delay_free_ses = ses_delay_freed.first;
389 	while (delay_free_ses != NULL) {
390 		tmps = delay_free_ses->next;
391 		free(delay_free_ses);
392 		delay_free_ses = tmps;
393 	}
394 	ses_delay_freed.count = 0;
395 	ses_delay_freed.first = NULL;
396 	ses_delay_freed.last = NULL;
397 	(void) pthread_mutex_destroy(&ses_delay_freed.ses_to_be_free_mutex);
398 }
399 
400 /*
401  * This function cleans up all the resources in the library (user space only)
402  */
403 static void
kms_cleanup_library()404 kms_cleanup_library()
405 {
406 	kms_slot_t *pslot = get_slotinfo();
407 
408 	if (pslot)
409 		kms_cleanup_pri_objects_in_slot(pslot, NULL);
410 
411 	/*
412 	 * Delete all the sessions for each slot and release the allocated
413 	 * resources from the library.  The boolean argument TRUE indicates
414 	 * that we only wants to clean up the resource in the library only.
415 	 * We don't want to clean up the corresponding kernel part of
416 	 * resources, because they are used by the parent process still.
417 	 */
418 	kms_delete_all_sessions(B_TRUE);
419 
420 	kms_finalize_common();
421 }
422 
423 static void
kms_init()424 kms_init()
425 {
426 	(void) pthread_atfork(kms_fork_prepare, kms_fork_after,
427 	    kms_fork_after);
428 }
429 
430 /*
431  * kms_fini() function required to make sure complete cleanup
432  * is done if pkcs11_kms is ever unloaded without
433  * a C_Finalize() call.
434  */
435 static void
kms_fini()436 kms_fini()
437 {
438 	(void) pthread_mutex_lock(&globalmutex);
439 
440 	(void) KMS_Finalize();
441 
442 	/* if we're not initilized, do not attempt to finalize */
443 	if (!kms_initialized) {
444 		(void) pthread_mutex_unlock(&globalmutex);
445 		return;
446 	}
447 
448 	kms_cleanup_library();
449 
450 	(void) pthread_mutex_unlock(&globalmutex);
451 }
452 
453 CK_RV
C_GetInfo(CK_INFO_PTR pInfo)454 C_GetInfo(CK_INFO_PTR pInfo)
455 {
456 	if (!kms_initialized)
457 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
458 
459 	if (pInfo == NULL) {
460 		return (CKR_ARGUMENTS_BAD);
461 	}
462 
463 	/* Check if the cryptoki was initialized */
464 	pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR;
465 	pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR;
466 	(void) strncpy((char *)pInfo->manufacturerID,
467 	    MANUFACTURER_ID, 32);
468 	pInfo->flags = 0;
469 	(void) strncpy((char *)pInfo->libraryDescription,
470 	    LIBRARY_DESCRIPTION, 32);
471 	pInfo->libraryVersion.major = LIBRARY_VERSION_MAJOR;
472 	pInfo->libraryVersion.minor = LIBRARY_VERSION_MINOR;
473 
474 	return (CKR_OK);
475 }
476 
477 CK_RV
C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)478 C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
479 {
480 	if (ppFunctionList == NULL) {
481 		return (CKR_ARGUMENTS_BAD);
482 	}
483 
484 	*ppFunctionList = &functionList;
485 
486 	return (CKR_OK);
487 }
488 
489 /*
490  * PKCS#11 states that C_GetFunctionStatus should always return
491  * CKR_FUNCTION_NOT_PARALLEL
492  */
493 /*ARGSUSED*/
494 CK_RV
C_GetFunctionStatus(CK_SESSION_HANDLE hSession)495 C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
496 {
497 	return (CKR_FUNCTION_NOT_PARALLEL);
498 }
499 
500 /*
501  * Take out all mutexes before fork.
502  * Order:
503  * 1. globalmutex
504  * 2. all slots mutexes (and all their sessions) via
505  *    kms_acquire_all_slots_mutexes()
506  * 3. obj_delay_freed.obj_to_be_free_mutex;
507  * 4. ses_delay_freed.ses_to_be_free_mutex
508  */
509 void
kms_fork_prepare()510 kms_fork_prepare()
511 {
512 	(void) pthread_mutex_lock(&globalmutex);
513 	if (kms_initialized) {
514 		kms_acquire_all_slots_mutexes();
515 		(void) pthread_mutex_lock(
516 		    &obj_delay_freed.obj_to_be_free_mutex);
517 		(void) pthread_mutex_lock(
518 		    &ses_delay_freed.ses_to_be_free_mutex);
519 	}
520 }
521 
522 /*
523  * Release in opposite order to kms_fork_prepare().
524  * Function is used for parent and child.
525  */
526 void
kms_fork_after()527 kms_fork_after()
528 {
529 	if (kms_initialized) {
530 		(void) pthread_mutex_unlock(
531 		    &ses_delay_freed.ses_to_be_free_mutex);
532 		(void) pthread_mutex_unlock(
533 		    &obj_delay_freed.obj_to_be_free_mutex);
534 		kms_release_all_slots_mutexes();
535 	}
536 	(void) pthread_mutex_unlock(&globalmutex);
537 }
538 
539 /*
540  * PKCS#11 states that C_CancelFunction should always return
541  * CKR_FUNCTION_NOT_PARALLEL
542  */
543 /*ARGSUSED*/
544 CK_RV
C_CancelFunction(CK_SESSION_HANDLE hSession)545 C_CancelFunction(CK_SESSION_HANDLE hSession)
546 {
547 	return (CKR_FUNCTION_NOT_PARALLEL);
548 }
549