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
109static 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
181boolean_t kms_initialized = B_FALSE;
182static pid_t kms_pid = 0;
183
184
185/* protects kms_initialized and entrance to C_Initialize/Finalize */
186static pthread_mutex_t globalmutex = PTHREAD_MUTEX_INITIALIZER;
187
188ses_to_be_freed_list_t ses_delay_freed;
189object_to_be_freed_list_t obj_delay_freed;
190kms_elem_t **kms_mechhash;	/* Hash table for kCF mech numbers */
191
192static void kms_finalize_common();
193static void kms_cleanup_library();
194static void kms_init();
195static void kms_fini();
196static void kms_fork_prepare();
197static void kms_fork_after();
198
199CK_RV
200C_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
306end:
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 */
316CK_RV
317C_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 */
349static void
350kms_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 */
403static void
404kms_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
423static void
424kms_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 */
435static void
436kms_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
453CK_RV
454C_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
477CK_RV
478C_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*/
494CK_RV
495C_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 */
509void
510kms_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 */
526void
527kms_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*/
544CK_RV
545C_CancelFunction(CK_SESSION_HANDLE hSession)
546{
547	return (CKR_FUNCTION_NOT_PARALLEL);
548}
549