pkcs11Conf.c revision 735564919188238196dbd0d320770dda59b38369
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <dlfcn.h>
#include <fcntl.h>
#include <link.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <door.h>
#include <pthread.h>
#include <libscf.h>
#include <cryptoutil.h>
#include <security/cryptoki.h>
#include "pkcs11Global.h"
#include "pkcs11Conf.h"
#include "pkcs11Slot.h"
#include "metaGlobal.h"
/*
* Fastpath is used when there is only one slot available from a single provider
* plugged into the framework this is the common case.
* These globals are used to track the function pointers and policy when
* the fast-path is activated.
* This will need to be revisted if per-slot policy is ever
* implemented.
*/
CK_SLOT_ID fast_slot = 0;
void (*Tmp_GetThreshold)(void *) = NULL;
static const char *conf_err = "See cryptoadm(1M). Skipping this plug-in.";
#define CRYPTOSVC_DEFAULT_INSTANCE_FMRI "svc:/system/cryptosvc:default"
#define MAX_CRYPTOSVC_ONLINE_TRIES 5
/*
* Set up metaslot for the framework using either user configuration
* or system wide configuration options
*
* Also sets up the global "slottable" to have the first slot be metaslot.
*/
static CK_RV
/* process policies for mechanisms */
if (rv == CKR_HOST_MEMORY) {
"libpkcs11: Could not parse configuration,"
"out of memory. Cannot continue parsing "
"%s.\n", _PATH_PKCS11_CONF);
return (rv);
} else if (rv == CKR_MECHANISM_INVALID) {
/*
* Configuration file is corrupted for metaslot
*/
"libpkcs11: Policy invalid or corrupted "
"for metaslot. Use cryptoadm(1M) to fix "
"this. Disabling metaslot functionality.\n");
return (rv);
}
}
/*
* Check for metaslot policy. If all mechanisms are
* disabled, disable metaslot since there is nothing
* interesting for it to do
*/
(prov_pol_mechs == NULL)) {
return (rv);
}
/*
* save system wide value for metaslot's keystore.
* If either slot description or token label is specified by
* the user, the system wide value for both is ignored.
*/
if ((metaslot_entry) &&
/*
* blank_str is used for comparing with token label,
* and slot description, make sure it is better than
* the larger of both
*/
blank_str, TOKEN_LABEL_SIZE) != 0) {
(void) strlcpy(
(char *)metaslot_config.keystore_token,
(const char *)metaslot_entry->metaslot_ks_token,
}
blank_str, SLOT_DESCRIPTION_SIZE) != 0) {
(void) strlcpy(
(char *)metaslot_config.keystore_slot,
(const char *)metaslot_entry->metaslot_ks_slot,
}
}
/* check system-wide value for auto_key_migrate */
/* take user's specified value */
} else {
if (metaslot_entry) {
/* use system-wide default */
} else {
/*
* there's no system wide metaslot entry,
* default auto_key_migrate to true
*/
}
}
/* Make first slotID be 0, for metaslot. */
/* Set up the slottable entry for metaslot */
return (rv);
}
/*
* The metaslot entry was prealloc'd by
* pkcs11_slottable_increase()
*/
if (metaslot_entry) {
} else {
/* if no metaslot entry, assume all mechs are enabled */
cur_slot->sl_pol_count = 0;
}
cur_slot->sl_prov_id = 0;
/* Call the meta_Initialize() to initialize metaslot */
"libpkcs11: Can't initialize metaslot (%s)",
goto cleanup;
}
return (CKR_OK);
if (cur_slot) {
}
return (rv);
}
/*
* cryptosvc_is_online()
*
* Determine if the SMF service instance is in the online state or
* not. A number of operations depend on this state.
*/
static boolean_t
cryptosvc_is_online(void)
{
char *str;
}
return (ret);
}
/*
* cryptosvc_is_down()
*
* Determine if the SMF service instance is in the disabled state or
* maintenance state. A number of operations depend on this state.
*/
static boolean_t
cryptosvc_is_down(void)
{
char *str;
}
return (ret);
}
/* Generic function for all door calls to kcfd. */
{
int kcfdfd = -1;
int r;
int is_cryptosvc_up_count = 0;
int door_errno = 0;
/* save errno and test for EINTR or EAGAIN */
door_errno = errno;
if (door_errno == EINTR ||
door_errno == EAGAIN)
continue;
/* if disabled or maintenance mode - bail */
if (cryptosvc_is_down())
break;
/* exceeded our number of tries? */
break;
/* any other state, try again up to 1/2 minute */
(void) sleep(5);
}
if (kcfdfd == -1) {
if (!cryptosvc_is_online()) {
" kcfd door_file %s: %s. %s is not online."
" (see svcs -xv for details).",
} else {
" kcfd door_file %s: %s.", _PATH_KCFD_DOOR,
}
goto verifycleanup;
}
/* Mark the door "close on exec" */
goto verifycleanup;
}
else {
}
/* save errno and test for certain errors */
door_errno = errno;
continue;
/* if disabled or maintenance mode - bail */
if (cryptosvc_is_down())
break;
/* exceeded our number of tries? */
break;
/* if stale door_handle, retry the open */
if (door_errno == EBADF) {
(void) sleep(5);
goto verifycleanup;
} else
break;
}
if (r != 0) {
if (!cryptosvc_is_online()) {
" - unable to utilize cryptographic "
"services. (see svcs -xv for details).",
} else {
"of door_file %s failed with error %s.",
}
goto verifycleanup;
}
/*LINTED*/
"libpkcs11: kcfd and libelfsign versions "
goto verifycleanup;
}
if (kcfdfd != -1) {
}
}
if (try_door_open_again) {
goto open_door_file;
}
return (estatus);
}
/*
* For each provider found in pkcs11.conf: expand $ISA if necessary,
* verify the module is signed, load the provider, find all of its
* slots, and store the function list and disabled policy.
*
* This function requires that the uentrylist_t and pkcs11_slottable_t
* already have memory allocated, and that the uentrylist_t is already
* populated with provider and policy information.
*
* pInitArgs can be set to NULL, but is normally the same value
* the framework's C_Initialize() was called with.
*
* Unless metaslot is explicitly disabled, it is setup when all other
* providers are loaded.
*/
{
/* Enabled or Disabled policy */
uint_t prov_count = 0;
CK_ULONG i;
/* number of slots in the framework, not including metaslot */
uint_t slot_count = 0;
char *estatus_str = NULL;
/* Check FIPS 140 configuration and execute check if enabled */
(void) get_fips_mode(&fips140_mode);
if (fips140_mode) {
if (estatus != ELFSIGN_SUCCESS) {
"integrity check.");
return (CKR_GENERAL_ERROR);
}
}
/* Loop through all of the provider listed in pkcs11.conf */
/*
* Skip standard processing for metaslot
* entry since it is not an actual library
* that can be dlopened.
* It will be initialized later.
*/
if (metaslot_entry != NULL) {
"libpkcs11: multiple entries for metaslot "
"detected. All but the first entry will "
"be ignored");
} else {
}
goto contparse;
}
/* Check for Instruction Set Architecture indicator */
/* Substitute the architecture dependent path */
strlen(PKCS11_ISA) +
"libpksc11: parsing %s, out of memory. "
"Cannot continue parsing.",
goto conferror;
}
*isa = '\000';
"libpkcs11: parsing %s, out of memory. "
"Cannot continue parsing.",
goto conferror;
}
/*
* Open the provider. Use RTLD_NOW to make sure we
* will not encounter symbol referencing errors later.
* Use RTLD_GROUP to limit the provider to it's own
* symbols, which prevents it from mistakenly accessing
* the framework's C_* functions.
*/
/*
* If we failed to load it, we will just skip this
* provider and move on to the next one.
*/
"libpkcs11: Cannot load PKCS#11 library %s. "
"dlerror: %s. %s",
conf_err);
goto contparse;
}
/* Get the pointer to provider's C_GetFunctionList() */
/*
* If we failed to get the pointer to C_GetFunctionList(),
* skip this provider and continue to the next one.
*/
if (Tmp_C_GetFunctionList == NULL) {
"libpkcs11: Could not dlsym() C_GetFunctionList() "
"for %s. May not be a PKCS#11 library. %s",
goto contparse;
}
/* Get the provider's function list */
/*
* If we failed to get the provider's function list,
* skip this provider and continue to the next one.
*/
"libpkcs11: Could not get function list for %s. "
"%s Error: %s.",
goto contparse;
}
/* Initialize this provider */
/*
* If we failed to initialize this provider,
* skip this provider and continue to the next one.
*/
"libpkcs11: Could not initialize %s. "
"%s Error: %s.",
goto contparse;
}
/*
* Make sure this provider is implementing the same
* major version, and at least the same minor version
* that we are.
*/
/*
* If we can't verify that we are implementing the
* same major version, or if it is definitely not the same
* version, we need to skip this provider.
*/
"libpkcs11: Could not verify version of "
"%s. %s Error: %s.", fullpath,
} else {
"libpkcs11: Only CRYPTOKI major version "
"%d is supported. %s is major "
"version %d. %s",
}
goto contparse;
}
/*
* Warn the administrator (at debug) that a provider with
* a significantly older or newer version of
* CRYPTOKI is being used. It should not cause
* problems, but logging a warning makes it easier
* to debug later.
*/
"libpkcs11: %s CRYPTOKI minor version, %d, may "
"not be compatible with minor version %d.",
}
/*
* Find out how many slots this provider has,
* call with tokenPresent set to FALSE so all
* potential slots are returned.
*/
NULL, &prov_slot_count);
/*
* If the call failed, or if no slots are returned,
* then skip this provider and continue to next one.
*/
"libpksc11: Could not get slot list from %s. "
"%s Error: %s.",
goto contparse;
}
if (prov_slot_count == 0) {
cryptodebug("libpkcs11: No slots presented from %s. "
"Skipping this plug-in at this time.\n",
fullpath);
goto contparse;
}
/*
* Verify that the module is signed correctly.
*
* NOTE: there is a potential race condition here,
* since the module is verified well after we have
* opened the provider via dlopen(). This could be
* resolved by a variant of dlopen() that would take a
* file descriptor as an argument and by changing the
* kcfd libelfsign door protocol to use and fd instead
* of a path - but that wouldn't work in the kernel case.
*/
switch (estatus) {
case ELFSIGN_UNKNOWN:
case ELFSIGN_SUCCESS:
case ELFSIGN_RESTRICTED:
break;
case ELFSIGN_NOTSIGNED:
break;
case ELFSIGN_FAILED:
break;
default:
"signature verification. "
"System may have been tampered with.");
}
if (estatus_str != NULL) {
estatus == ELFSIGN_UNKNOWN ?
"Cannot continue parsing " _PATH_PKCS11_CONF:
conf_err);
estatus_str = NULL;
if (estatus == ELFSIGN_UNKNOWN) {
prov_funcs = NULL;
goto conferror;
}
goto contparse;
}
/* Allocate memory for the slot list */
if (prov_slots == NULL) {
"libpkcs11: Could not allocate memory for "
"plug-in slots. Cannot continue parsing %s\n",
goto conferror;
}
/* Get slot list from provider */
/* if second call fails, drop this provider */
"libpkcs11: Second call to C_GetSlotList() for %s "
"failed. %s Error: %s.",
goto contparse;
}
/*
* Parse the list of disabled or enabled mechanisms, will
* apply to each of the provider's slots.
*/
if (rv == CKR_HOST_MEMORY) {
"libpkcs11: Could not parse configuration,"
"out of memory. Cannot continue parsing "
"%s.", _PATH_PKCS11_CONF);
goto conferror;
} else if (rv == CKR_MECHANISM_INVALID) {
/*
* Configuration file is corrupted for this
* provider.
*/
"libpkcs11: Policy invalid or corrupted "
"for %s. Use cryptoadm(1M) to fix "
"this. Skipping this plug-in.",
fullpath);
goto contparse;
}
}
/* Allocate memory in our slottable for these slots */
/*
* If any error is returned, it will be memory related,
* so we need to abort the attempt at filling the
* slottable.
*/
"libpkcs11: slottable could not increase. "
"Cannot continue parsing %s.",
goto conferror;
}
/* Configure information for each new slot */
for (i = 0; i < prov_slot_count; i++) {
/* allocate slot in framework */
"libpkcs11: Could not allocate "
"new slot. Cannot continue parsing %s.",
goto conferror;
}
slot_count++;
}
/*
* Get the pointer to private interface _SUNW_GetThreshold()
* in pkcs11_kernel.
*/
if (Tmp_GetThreshold == NULL) {
/* Get the threshold values for the supported mechs */
if (Tmp_GetThreshold != NULL) {
(void) memset(meta_mechs_threshold, 0,
sizeof (meta_mechs_threshold));
}
}
/* Set and reset values to process next provider */
prov_count++;
prov_slot_count = 0;
prov_funcs = NULL;
}
if (prov_slots != NULL) {
prov_slots = NULL;
}
}
if (slot_count == 0) {
/*
* there's no other slot in the framework,
* there is nothing to do
*/
goto config_complete;
}
/* determine if metaslot should be enabled */
/*
* Check to see if any environment variable is defined
* by the user for configuring metaslot. Users'
* setting always take precedence over the system wide
* setting. So, we will first check for any user's
* defined env variables before looking at the system-wide
* configuration.
*/
/* no metaslot entry in /etc/crypto/pkcs11.conf */
if (!metaslot_entry) {
/*
* If user env variable indicates metaslot should be enabled,
* but there's no entry in /etc/crypto/pkcs11.conf for
* metaslot at all, will respect the user's defined value
*/
if ((metaslot_config.enabled_specified) &&
(metaslot_config.enabled)) {
}
} else {
if (!metaslot_config.enabled_specified) {
/*
* take system wide value if
* it is not specified by user
*/
} else {
}
}
/*
*
* As long as the user or system configuration file does not
* disable metaslot, it will be enabled regardless of the
* number of slots plugged into the framework. Therefore,
* metaslot is enabled even when there's only one slot
* plugged into the framework. This is necessary for
* presenting a consistent token label view to applications.
*
* However, for the case where there is only 1 slot plugged into
* the framework, we can use "fastpath".
*
* "fastpath" will pass all of the application's requests
* directly to the underlying provider. Only when policy is in
* effect will we need to keep slotID around.
*
* When metaslot is enabled, and fastpath is enabled,
* all the metaslot processing will be skipped.
* When there is only 1 slot, there's
* really not much metaslot can do in terms of combining functionality
* of different slots, and object migration.
*
*/
/* check to see if fastpath can be used */
if ((cur_slot->sl_pol_count == 0) &&
/* No policy is in effect, don't need slotid */
} else {
}
}
goto config_complete;
}
/*
* If we get here, there are more than 2 slots in the framework,
* we need to set up metaslot if it is enabled
*/
if (metaslot_enabled) {
goto conferror;
}
}
return (CKR_OK);
/*
* This cleanup code is only exercised when a major,
* unrecoverable error like "out of memory" occurs.
*/
if (prov_funcs != NULL) {
}
}
}
if (prov_slots != NULL) {
prov_slots = NULL;
}
return (rv);
}
/*
* pkcs11_mech_parse will take hex mechanism ids, as a list of
* strings, and convert them to CK_MECHANISM_TYPE_PTR.
*/
int mech_count)
{
"Cannot continue.",
return (CKR_HOST_MEMORY);
}
/*
* The following will loop mech_count times, as there are
* exactly mech_count items in the str_list.
*/
errno = 0;
/*
* "name" is a hexadecimal number, preceded by 0x.
*/
if ((cur_mech == 0) &&
return (CKR_MECHANISM_INVALID);
}
tmp_list++;
}
return (CKR_OK);
}
/*
* pkcs11_is_dismech is provided a slotid and a mechanism.
* If mech is not disabled, then return B_FALSE.
*/
{
ulong_t i;
/* Find the associated slot and get the mech policy info */
/* Check for policy */
/* no policy */
return (B_FALSE);
/*
* We have an empty enabled list, which means no
* mechanisms are exempted from this policy: all
* are disabled.
*/
return (B_TRUE);
}
for (i = 0; i < pol_count; i++) {
/*
* If it matches, return status based on this
* being and enabled or a disabled list of mechs.
*/
}
}
/* mech was not found in list */
}