da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * CDDL HEADER START
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The contents of this file are subject to the terms of the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Common Development and Distribution License (the "License").
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * You may not use this file except in compliance with the License.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * or http://www.opensolaris.org/os/licensing.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * See the License for the specific language governing permissions
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * and limitations under the License.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * When distributing Covered Code, include this CDDL HEADER in each
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If applicable, add the following below this CDDL HEADER, with the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * fields enclosed by brackets "[]" replaced with your own identifying
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * information: Portions Copyright [yyyy] [name of copyright owner]
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * CDDL HEADER END
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*
dc20a3024900c47dd2ee44b9707e6df38f7d62a5as * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Use is subject to license terms.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#include <unistd.h>
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#include <string.h>
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#include <cryptoutil.h>
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#include <pthread.h>
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#include <security/cryptoki.h>
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#include "pkcs11Global.h"
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#include "pkcs11Slot.h"
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#include "pkcs11Conf.h"
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#include "pkcs11Session.h"
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#include "metaGlobal.h"
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#pragma init(pkcs11_init)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#pragma fini(pkcs11_fini)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic struct CK_FUNCTION_LIST functionList = {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw { 2, 20 }, /* version */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_Initialize,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_Finalize,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_GetInfo,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_GetFunctionList,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_GetSlotList,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_GetSlotInfo,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_GetTokenInfo,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_GetMechanismList,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_GetMechanismInfo,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_InitToken,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_InitPIN,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_SetPIN,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_OpenSession,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_CloseSession,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_CloseAllSessions,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_GetSessionInfo,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_GetOperationState,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_SetOperationState,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_Login,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_Logout,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_CreateObject,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_CopyObject,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_DestroyObject,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_GetObjectSize,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_GetAttributeValue,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_SetAttributeValue,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_FindObjectsInit,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_FindObjects,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_FindObjectsFinal,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_EncryptInit,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_Encrypt,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_EncryptUpdate,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_EncryptFinal,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_DecryptInit,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_Decrypt,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_DecryptUpdate,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_DecryptFinal,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_DigestInit,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_Digest,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_DigestUpdate,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_DigestKey,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_DigestFinal,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_SignInit,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_Sign,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_SignUpdate,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_SignFinal,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_SignRecoverInit,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_SignRecover,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_VerifyInit,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_Verify,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_VerifyUpdate,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_VerifyFinal,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_VerifyRecoverInit,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_VerifyRecover,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_DigestEncryptUpdate,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_DecryptDigestUpdate,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_SignEncryptUpdate,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_DecryptVerifyUpdate,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_GenerateKey,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_GenerateKeyPair,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_WrapKey,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_UnwrapKey,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_DeriveKey,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_SeedRandom,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_GenerateRandom,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_GetFunctionStatus,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_CancelFunction,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw C_WaitForSlotEvent
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw};
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwboolean_t pkcs11_initialized = B_FALSE;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwboolean_t pkcs11_cant_create_threads = B_FALSE;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwboolean_t fini_called = B_FALSE;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic boolean_t pkcs11_atfork_initialized = B_FALSE;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic pid_t pkcs11_pid = 0;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/* protects pkcs11_[initialized|pid], and fastpath */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic pthread_mutex_t globalmutex = PTHREAD_MUTEX_INITIALIZER;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic CK_RV finalize_common(CK_VOID_PTR pReserved);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void pkcs11_init();
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void pkcs11_fini();
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Ensure that before a fork, all mutexes are taken.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * We cannot acquire globalmutex, because it can cause deadlock when
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * atfork() and fork() are called in parallel. It can happen when
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * C_Ininitialize() tries to dlopen() a provider. The dlopen() operation
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * is protected by globalmutex and when another thread calls fork()
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * pkcs11_fork_prepare cannot acquire the mutex again and thus it must wait.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * When a provider tries to register its atfork handler, atfork() must
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * wait on fork(). See the comment in fork() libc function for more details.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Order:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * 1. slottable->st_mutex
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * 2. all slottable->st_slots' mutexes
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwpkcs11_fork_prepare(void)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw{
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw int i;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (pkcs11_initialized) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (slottable != NULL) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) pthread_mutex_lock(&slottable->st_mutex);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* Take the sl_mutex of all slots */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw for (i = slottable->st_first;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw i <= slottable->st_last; i++) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (slottable->st_slots[i] != NULL) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) pthread_mutex_lock(
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw &slottable->st_slots[i]->sl_mutex);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw}
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Ensure that after a fork, in the parent, all mutexes are released in opposite
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * order to pkcs11_fork_prepare().
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwpkcs11_fork_parent(void)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw{
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw int i;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (pkcs11_initialized) {
7b59d02d2a384be9a08087b14defadd214b3c1ddjb if (slottable != NULL) {
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb /* Release the sl_mutex of all slots */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw for (i = slottable->st_first;
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb i <= slottable->st_last; i++) {
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb if (slottable->st_slots[i] != NULL) {
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb (void) pthread_mutex_unlock(
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb &slottable->st_slots[i]->sl_mutex);
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb (void) pthread_mutex_unlock(&slottable->st_mutex);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw}
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb/*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Ensure that after a fork, in the child, all mutexes are released in opposite
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * order to pkcs11_fork_prepare() and cleanup is done.
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb * Because we need to handle fork correctly before library is initialized two
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * handlers are necessary.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * 1) pkcs11_fork_child() - unlock mutexes
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * 2) pkcs11_fork_child_fini() - cleanup library after fork, it is registered in
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * C_Initialize() after providers initialization.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbstatic void
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbpkcs11_fork_child(void)
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb{
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb int i;
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb if (pkcs11_initialized) {
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb if (slottable != NULL) {
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb /* Release the sl_mutex of all slots */
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb for (i = slottable->st_first;
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb i <= slottable->st_last; i++) {
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb if (slottable->st_slots[i] != NULL) {
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb (void) pthread_mutex_unlock(
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw &slottable->st_slots[i]->sl_mutex);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) pthread_mutex_unlock(&slottable->st_mutex);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) pthread_mutex_destroy(&globalmutex);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) pthread_mutex_init(&globalmutex, NULL);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw}
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/* Library cleanup have to be last afterfork child handler. */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwpkcs11_fork_child_fini(void)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw{
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb pkcs11_fini();
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb}
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbCK_RV
faa1795a28a5c712eed6d0a3f84d98c368a316c6jbC_Initialize(CK_VOID_PTR pInitArgs)
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb{
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb CK_RV rv;
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb uentrylist_t *pliblist = NULL;
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb int initialize_pid;
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb /*
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb * Grab lock to insure only one thread enters
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb * this function at a time.
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb */
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb (void) pthread_mutex_lock(&globalmutex);
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb initialize_pid = getpid();
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb /* Make sure function hasn't been called twice */
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb if (pkcs11_initialized) {
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb if (initialize_pid == pkcs11_pid) {
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb (void) pthread_mutex_unlock(&globalmutex);
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb return (CKR_CRYPTOKI_ALREADY_INITIALIZED);
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb } else {
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb /*
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb * A fork has happened and the child is
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb * reinitializing. Do a finalize_common() to close
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb * out any state from the parent, and then
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb * continue on.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) finalize_common(NULL);
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb /* Check if application has provided mutex-handling functions */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (pInitArgs != NULL) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw CK_C_INITIALIZE_ARGS_PTR initargs =
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb (CK_C_INITIALIZE_ARGS_PTR) pInitArgs;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* pReserved should not be set */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (initargs->pReserved != NULL) {
dc20a3024900c47dd2ee44b9707e6df38f7d62a5as rv = CKR_ARGUMENTS_BAD;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw goto errorexit;
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Make sure function pointers are either all NULL or
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * all set.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (!(((initargs->CreateMutex != NULL) &&
7b59d02d2a384be9a08087b14defadd214b3c1ddjb (initargs->LockMutex != NULL) &&
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb (initargs->UnlockMutex != NULL) &&
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (initargs->DestroyMutex != NULL)) ||
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ((initargs->CreateMutex == NULL) &&
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (initargs->LockMutex == NULL) &&
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (initargs->UnlockMutex == NULL) &&
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (initargs->DestroyMutex == NULL)))) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rv = CKR_ARGUMENTS_BAD;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw goto errorexit;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (!(initargs->flags & CKF_OS_LOCKING_OK)) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (initargs->CreateMutex != NULL) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Do not accept application supplied
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * locking primitives.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rv = CKR_CANT_LOCK;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw goto errorexit;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (initargs->flags & CKF_LIBRARY_CANT_CREATE_OS_THREADS) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Calling application does not want the library
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * to create threads. This will effect
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * C_WaitForSlotEvent().
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw pkcs11_cant_create_threads = B_TRUE;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* Initialize slot table */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rv = pkcs11_slottable_initialize();
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (rv != CKR_OK)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw goto errorexit;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
7b59d02d2a384be9a08087b14defadd214b3c1ddjb /* Get the list of providers */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (get_pkcs11conf_info(&pliblist) != SUCCESS) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rv = CKR_FUNCTION_FAILED;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw goto errorexit;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Load each provider, check for accessible slots,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * and populate slottable. If metaslot is enabled,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * it will be initialized as well.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rv = pkcs11_slot_mapping(pliblist, pInitArgs);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (rv != CKR_OK)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw goto errorexit;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw pkcs11_initialized = B_TRUE;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw pkcs11_pid = initialize_pid;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* Children inherit parent's atfork handlers */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (!pkcs11_atfork_initialized) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) pthread_atfork(NULL, NULL, pkcs11_fork_child_fini);
7b59d02d2a384be9a08087b14defadd214b3c1ddjb pkcs11_atfork_initialized = B_TRUE;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) pthread_mutex_unlock(&globalmutex);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* Cleanup data structures no longer needed */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw free_uentrylist(pliblist);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (CKR_OK);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwerrorexit:
3db3f65c6274eb042354801a308c8e9bc4994553amw /* Cleanup any data structures that have already been allocated */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (slottable)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) pkcs11_slottable_delete();
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (pliblist)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) free_uentrylist(pliblist);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) pthread_mutex_unlock(&globalmutex);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (rv);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
faa1795a28a5c712eed6d0a3f84d98c368a316c6jb}
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
/*
* C_Finalize is a wrapper around finalize_common. The
* globalmutex should be locked by C_Finalize().
*
* When an explicit C_Finalize() call is received, all
* plugins currently in the slottable will also be
* finalized. This must occur, even if libpkcs11(3lib)
* was not the first one to initialize the plugins, since it
* is the only way in PKCS#11 to force a refresh of the
* slot listings (ie to get new hardware devices).
*/
CK_RV
C_Finalize(CK_VOID_PTR pReserved)
{
CK_RV rv;
(void) pthread_mutex_lock(&globalmutex);
rv = finalize_common(pReserved);
(void) pthread_mutex_unlock(&globalmutex);
return (rv);
}
/*
* finalize_common() does the work for C_Finalize. globalmutex
* must be held before calling this function.
*/
static CK_RV
finalize_common(CK_VOID_PTR pReserved)
{
CK_RV rv;
if (!pkcs11_initialized) {
return (CKR_CRYPTOKI_NOT_INITIALIZED);
}
if (pReserved != NULL) {
return (CKR_ARGUMENTS_BAD);
}
purefastpath = B_FALSE;
policyfastpath = B_FALSE;
fast_funcs = NULL;
fast_slot = 0;
pkcs11_initialized = B_FALSE;
pkcs11_cant_create_threads = B_FALSE;
pkcs11_pid = 0;
/* Check if C_WaitForSlotEvent() is currently active */
(void) pthread_mutex_lock(&slottable->st_mutex);
if (slottable->st_wfse_active) {
/*
* Wait for this thread to proceed far enough to block or
* end on its own. Otherwise, teardown of slottable may
* occurr before this active function completes.
*/
while (slottable->st_wfse_active) {
/*
* If C_WaitForSlotEvent is blocking, wake it up and
* return error to calling application.
*/
if (slottable->st_blocking) {
slottable->st_list_signaled = B_TRUE;
(void) pthread_cond_signal(
&slottable->st_wait_cond);
(void) pthread_mutex_unlock(
&slottable->st_mutex);
(void) pthread_join(slottable->st_tid, NULL);
}
}
} else {
(void) pthread_mutex_unlock(&slottable->st_mutex);
}
rv = pkcs11_slottable_delete();
return (rv);
}
static void
pkcs11_init()
{
(void) pthread_atfork(pkcs11_fork_prepare,
pkcs11_fork_parent, pkcs11_fork_child);
}
/*
* pkcs11_fini() function required to make sure complete cleanup
* is done of plugins if the framework is ever unloaded without
* a C_Finalize() call. This would be common when applications
* load and unload other libraries that use libpkcs11(3lib), since
* shared libraries should not call C_Finalize().
*
* If pkcs11_fini() is used, we set fini_called to B_TRUE so that
* pkcs11_slottable_delete() will not call C_Finalize() on the plugins.
*
* This is to protect in cases where the application has dlopened
* an object (for example, dlobj) that links to libpkcs11(3lib), but
* the application is unaware that the object is doing PKCS#11 calls
* underneath. This application may later directly dlopen one of the
* plugins (like pkcs11_softtoken.so, or any other 3rd party provided
* plugin) in order to directly perform PKCS#11 operations.
*
* While it is still actively using the PKCS#11 plugin directly,
* the application may finish with dlobj and dlclose it. As the
* reference count for libpkcs11(3lib) has become 0, pkcs11_fini()
* will be run by the linker. Even though libpkcs11(3lib) was the
* first to initialize the plugin in this case, it is not safe for
* libpkcs11(3lib) to finalize the plugin, as the application would
* lose state.
*/
static void
pkcs11_fini()
{
(void) pthread_mutex_lock(&globalmutex);
/* if we're not initilized, do not attempt to finalize */
if (!pkcs11_initialized) {
(void) pthread_mutex_unlock(&globalmutex);
return;
}
fini_called = B_TRUE;
(void) finalize_common(NULL_PTR);
(void) pthread_mutex_unlock(&globalmutex);
}
CK_RV
C_GetInfo(CK_INFO_PTR pInfo)
{
/* Check for a fastpath */
if (purefastpath || policyfastpath) {
return (fast_funcs->C_GetInfo(pInfo));
}
if (!pkcs11_initialized)
return (CKR_CRYPTOKI_NOT_INITIALIZED);
if (pInfo == NULL) {
return (CKR_ARGUMENTS_BAD);
}
/*
* Copy data into the provided buffer, use strncpy() instead
* of strlcpy() so that the strings are NOT NULL terminated,
* as required by the PKCS#11 standard
*/
(void) strncpy((char *)pInfo->manufacturerID, MANUFACTURER_ID,
PKCS11_STRING_LENGTH);
(void) strncpy((char *)pInfo->libraryDescription,
LIBRARY_DESCRIPTION, PKCS11_STRING_LENGTH);
pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR;
pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR;
pInfo->flags = 0;
pInfo->libraryVersion.major = LIBRARY_VERSION_MAJOR;
pInfo->libraryVersion.minor = LIBRARY_VERSION_MINOR;
return (CKR_OK);
}
/*
* This function is unaffected by the fast-path, since it is likely
* called before C_Initialize is, so we will not yet know the status
* of the fast-path. Additionally, policy will still need to be
* enforced if applicable.
*/
CK_RV
C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
{
if (ppFunctionList == NULL) {
return (CKR_ARGUMENTS_BAD);
}
*ppFunctionList = &functionList;
return (CKR_OK);
}
/*
* This function is no longer supported in this revision of the PKCS#11
* standard. It is maintained for backwards compatibility only.
*/
/*ARGSUSED*/
CK_RV
C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
{
return (CKR_FUNCTION_NOT_PARALLEL);
}
/*
* This function is no longer supported in this revision of the PKCS#11
* standard. It is maintained for backwards compatibility only.
*/
/*ARGSUSED*/
CK_RV
C_CancelFunction(CK_SESSION_HANDLE hSession)
{
return (CKR_FUNCTION_NOT_PARALLEL);
}