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