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