2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <sys/types.h>
2N/A#include <sys/stat.h>
2N/A#include <dlfcn.h>
2N/A#include <fcntl.h>
2N/A#include <link.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <strings.h>
2N/A#include <errno.h>
2N/A#include <door.h>
2N/A#include <pthread.h>
2N/A#include <sys/mman.h>
2N/A#include <libscf.h>
2N/A#include <cryptoutil.h>
2N/A
2N/A#include <sys/crypto/elfsign.h>
2N/A#include <cryptoutil.h>
2N/A#include <fips/fips_checksum.h>
2N/A
2N/A#include <security/cryptoki.h>
2N/A#include "pkcs11Global.h"
2N/A#include "pkcs11Conf.h"
2N/A#include "pkcs11Slot.h"
2N/A#include "metaGlobal.h"
2N/A
2N/A/*
2N/A * Fastpath is used when there is only one slot available from a single provider
2N/A * plugged into the framework this is the common case.
2N/A * These globals are used to track the function pointers and policy when
2N/A * the fast-path is activated.
2N/A * This will need to be revisited if per-slot policy is ever
2N/A * implemented.
2N/A */
2N/Aboolean_t purefastpath = B_FALSE;
2N/Aboolean_t policyfastpath = B_FALSE;
2N/ACK_FUNCTION_LIST_PTR fast_funcs = NULL;
2N/ACK_SLOT_ID fast_slot = 0;
2N/Aboolean_t metaslot_enabled = B_FALSE;
2N/Aboolean_t metaslot_auto_key_migrate = B_FALSE;
2N/Ametaslot_config_t metaslot_config;
2N/Avoid (*Tmp_GetThreshold)(void *) = NULL;
2N/Acipher_mechs_threshold_t meta_mechs_threshold[MAX_NUM_THRESHOLD];
2N/A
2N/Astatic const char *conf_err = "See cryptoadm(1M). Skipping this plug-in.";
2N/A
2N/A#define CRYPTOSVC_DEFAULT_INSTANCE_FMRI "svc:/system/cryptosvc:default"
2N/A#define MAX_CRYPTOSVC_ONLINE_TRIES 5
2N/A
2N/A/*
2N/A * Set up metaslot for the framework using either user configuration
2N/A * or system wide configuration options
2N/A *
2N/A * Also sets up the global "slottable" to have the first slot be metaslot.
2N/A */
2N/Astatic CK_RV
2N/Asetup_metaslot(uentry_t *metaslot_entry)
2N/A{
2N/A CK_RV rv = CKR_OK;
2N/A CK_MECHANISM_TYPE_PTR prov_pol_mechs = NULL;
2N/A pkcs11_slot_t *cur_slot;
2N/A
2N/A /* process policies for mechanisms */
2N/A if ((metaslot_entry) && (metaslot_entry->count > 0)) {
2N/A rv = pkcs11_mech_parse(metaslot_entry->policylist,
2N/A &prov_pol_mechs, metaslot_entry->count);
2N/A
2N/A if (rv == CKR_HOST_MEMORY) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: Could not parse configuration,"
2N/A "out of memory. Cannot continue parsing "
2N/A "%s.\n", _PATH_PKCS11_CONF);
2N/A return (rv);
2N/A } else if (rv == CKR_MECHANISM_INVALID) {
2N/A /*
2N/A * Configuration file is corrupted for metaslot
2N/A */
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: Policy invalid or corrupted "
2N/A "for metaslot. Use cryptoadm(1M) to fix "
2N/A "this. Disabling metaslot functionality.\n");
2N/A metaslot_enabled = B_FALSE;
2N/A return (rv);
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Check for metaslot policy. If all mechanisms are
2N/A * disabled, disable metaslot since there is nothing
2N/A * interesting for it to do
2N/A */
2N/A if ((metaslot_entry) && (metaslot_entry->flag_enabledlist) &&
2N/A (prov_pol_mechs == NULL)) {
2N/A metaslot_enabled = B_FALSE;
2N/A return (CKR_OK);
2N/A }
2N/A
2N/A /*
2N/A * save system wide value for metaslot's keystore.
2N/A * If either slot description or token label is specified by
2N/A * the user, the system wide value for both is ignored.
2N/A */
2N/A if ((metaslot_entry) &&
2N/A (!metaslot_config.keystore_token_specified) &&
2N/A (!metaslot_config.keystore_slot_specified)) {
2N/A /*
2N/A * blank_str is used for comparing with token label,
2N/A * and slot description, make sure it is better than
2N/A * the larger of both
2N/A */
2N/A char blank_str[TOKEN_LABEL_SIZE + SLOT_DESCRIPTION_SIZE];
2N/A
2N/A bzero(blank_str, sizeof (blank_str));
2N/A
2N/A if (memcmp(metaslot_entry->metaslot_ks_token,
2N/A blank_str, TOKEN_LABEL_SIZE) != 0) {
2N/A metaslot_config.keystore_token_specified = B_TRUE;
2N/A (void) strlcpy(
2N/A (char *)metaslot_config.keystore_token,
2N/A (const char *)metaslot_entry->metaslot_ks_token,
2N/A TOKEN_LABEL_SIZE);
2N/A }
2N/A
2N/A if (memcmp(metaslot_entry->metaslot_ks_slot,
2N/A blank_str, SLOT_DESCRIPTION_SIZE) != 0) {
2N/A metaslot_config.keystore_slot_specified = B_TRUE;
2N/A (void) strlcpy(
2N/A (char *)metaslot_config.keystore_slot,
2N/A (const char *)metaslot_entry->metaslot_ks_slot,
2N/A SLOT_DESCRIPTION_SIZE);
2N/A }
2N/A }
2N/A
2N/A /* check system-wide value for auto_key_migrate */
2N/A if (metaslot_config.auto_key_migrate_specified) {
2N/A /* take user's specified value */
2N/A metaslot_auto_key_migrate = metaslot_config.auto_key_migrate;
2N/A } else {
2N/A if (metaslot_entry) {
2N/A /* use system-wide default */
2N/A metaslot_auto_key_migrate =
2N/A metaslot_entry->flag_metaslot_auto_key_migrate;
2N/A } else {
2N/A /*
2N/A * there's no system wide metaslot entry,
2N/A * default auto_key_migrate to true
2N/A */
2N/A metaslot_auto_key_migrate = B_TRUE;
2N/A }
2N/A }
2N/A
2N/A
2N/A /* Make first slotID be 0, for metaslot. */
2N/A slottable->st_first = 0;
2N/A
2N/A /* Set up the slottable entry for metaslot */
2N/A slottable->st_slots[0] = NULL;
2N/A cur_slot = calloc(1, sizeof (pkcs11_slot_t));
2N/A if (cur_slot == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A return (rv);
2N/A }
2N/A cur_slot->sl_wfse_state = WFSE_CLEAR;
2N/A cur_slot->sl_enabledpol = B_FALSE;
2N/A cur_slot->sl_no_wfse = B_FALSE;
2N/A (void) pthread_mutex_init(&cur_slot->sl_mutex, NULL);
2N/A
2N/A /*
2N/A * The metaslot entry was prealloc'd by
2N/A * pkcs11_slottable_increase()
2N/A */
2N/A (void) pthread_mutex_lock(&slottable->st_mutex);
2N/A slottable->st_slots[0] = cur_slot;
2N/A (void) pthread_mutex_unlock(&slottable->st_mutex);
2N/A
2N/A (void) pthread_mutex_lock(&cur_slot->sl_mutex);
2N/A cur_slot->sl_id = METASLOT_SLOTID;
2N/A cur_slot->sl_func_list = &metaslot_functionList;
2N/A if (metaslot_entry) {
2N/A cur_slot->sl_enabledpol = metaslot_entry->flag_enabledlist;
2N/A cur_slot->sl_pol_count = metaslot_entry->count;
2N/A } else {
2N/A /* if no metaslot entry, assume all mechs are enabled */
2N/A cur_slot->sl_enabledpol = B_FALSE;
2N/A cur_slot->sl_pol_count = 0;
2N/A }
2N/A cur_slot->sl_pol_mechs = prov_pol_mechs;
2N/A cur_slot->sl_dldesc = NULL; /* not applicable */
2N/A cur_slot->sl_prov_id = 0;
2N/A (void) pthread_mutex_unlock(&cur_slot->sl_mutex);
2N/A
2N/A /* Call the meta_Initialize() to initialize metaslot */
2N/A rv = meta_Initialize(NULL);
2N/A if (rv != CKR_OK) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: Can't initialize metaslot (%s)",
2N/A pkcs11_strerror(rv));
2N/A goto cleanup;
2N/A }
2N/A
2N/A return (CKR_OK);
2N/A
2N/Acleanup:
2N/A metaslot_enabled = B_FALSE;
2N/A slottable->st_slots[0] = NULL;
2N/A
2N/A if (cur_slot) {
2N/A (void) pthread_mutex_destroy(&cur_slot->sl_mutex);
2N/A free(cur_slot);
2N/A }
2N/A return (rv);
2N/A}
2N/A
2N/Aboolean_t
2N/Apkcs11_token_is_metaslot_obj_store(const char *token_name)
2N/A{
2N/A CK_TOKEN_INFO metainfo;
2N/A CK_SLOT_ID true_id;
2N/A
2N/A if (!metaslot_enabled ||
2N/A token_name == NULL || strlen(token_name) > TOKEN_LABEL_SIZE) {
2N/A return (B_FALSE);
2N/A }
2N/A
2N/A true_id = TRUEID(metaslot_keystore_slotid);
2N/A if (FUNCLIST(metaslot_keystore_slotid)->C_GetTokenInfo(true_id,
2N/A &metainfo) != CKR_OK) {
2N/A return (B_FALSE);
2N/A }
2N/A
2N/A if (memcmp_pad_max(metainfo.label, sizeof (metainfo.label),
2N/A (void *)token_name, strlen(token_name), TOKEN_LABEL_SIZE) == 0) {
2N/A return (B_TRUE);
2N/A }
2N/A
2N/A return (B_FALSE);
2N/A}
2N/A
2N/A/*
2N/A * cryptosvc_is_online()
2N/A *
2N/A * Determine if the SMF service instance is in the online state or
2N/A * not. A number of operations depend on this state.
2N/A */
2N/Astatic boolean_t
2N/Acryptosvc_is_online(void)
2N/A{
2N/A char *str;
2N/A boolean_t ret = B_FALSE;
2N/A
2N/A if ((str = smf_get_state(CRYPTOSVC_DEFAULT_INSTANCE_FMRI)) != NULL) {
2N/A ret = (strcmp(str, SCF_STATE_STRING_ONLINE) == 0);
2N/A free(str);
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * cryptosvc_is_down()
2N/A *
2N/A * Determine if the SMF service instance is in the disabled state or
2N/A * maintenance state. A number of operations depend on this state.
2N/A */
2N/Astatic boolean_t
2N/Acryptosvc_is_down(void)
2N/A{
2N/A char *str;
2N/A boolean_t ret = B_FALSE;
2N/A
2N/A if ((str = smf_get_state(CRYPTOSVC_DEFAULT_INSTANCE_FMRI)) != NULL) {
2N/A ret = ((strcmp(str, SCF_STATE_STRING_DISABLED) == 0) ||
2N/A (strcmp(str, SCF_STATE_STRING_MAINT) == 0));
2N/A free(str);
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/A
2N/A/* Generic function for all door calls to kcfd. */
2N/Astatic ELFsign_status_t
2N/Akcfd_door_call(char *fullpath, CK_RV *rv)
2N/A{
2N/A boolean_t try_door_open_again = B_FALSE;
2N/A int kcfdfd = -1;
2N/A door_arg_t darg;
2N/A kcf_door_arg_t *kda = NULL;
2N/A kcf_door_arg_t *rkda = NULL;
2N/A int r;
2N/A int is_cryptosvc_up_count = 0;
2N/A int door_errno = 0;
2N/A ELFsign_status_t estatus = ELFSIGN_UNKNOWN;
2N/A
2N/Aopen_door_file:
2N/A
2N/A while ((kcfdfd = open(_PATH_KCFD_DOOR, O_RDONLY)) == -1) {
2N/A /* save errno and test for EINTR or EAGAIN */
2N/A door_errno = errno;
2N/A if (door_errno == EINTR ||
2N/A door_errno == EAGAIN)
2N/A continue;
2N/A /* if disabled or maintenance mode - bail */
2N/A if (cryptosvc_is_down())
2N/A break;
2N/A /* exceeded our number of tries? */
2N/A if (is_cryptosvc_up_count > MAX_CRYPTOSVC_ONLINE_TRIES)
2N/A break;
2N/A /* any other state, try again up to 1/2 minute */
2N/A (void) sleep(5);
2N/A is_cryptosvc_up_count++;
2N/A }
2N/A if (kcfdfd == -1) {
2N/A if (!cryptosvc_is_online()) {
2N/A cryptoerror(LOG_ERR, "libpkcs11: unable to communicate"
2N/A " with kcfd, door_file %s: %s. %s is not online."
2N/A " (see svcs -xv for details).",
2N/A _PATH_KCFD_DOOR, strerror(door_errno),
2N/A CRYPTOSVC_DEFAULT_INSTANCE_FMRI);
2N/A } else {
2N/A cryptoerror(LOG_ERR, "libpkcs11: unable to open"
2N/A " kcfd door_file %s: %s.", _PATH_KCFD_DOOR,
2N/A strerror(door_errno));
2N/A }
2N/A *rv = CKR_CRYPTOKI_NOT_INITIALIZED;
2N/A estatus = ELFSIGN_UNAVAILABLE;
2N/A goto verifycleanup;
2N/A }
2N/A
2N/A /* Mark the door "close on exec" */
2N/A (void) fcntl(kcfdfd, F_SETFD, FD_CLOEXEC);
2N/A
2N/A if ((kda = malloc(sizeof (kcf_door_arg_t))) == NULL) {
2N/A cryptoerror(LOG_ERR, "libpkcs11: malloc of kda "
2N/A "failed: %s", strerror(errno));
2N/A goto verifycleanup;
2N/A }
2N/A
2N/A kda->da_version = KCF_KCFD_VERSION1;
2N/A (void) strlcpy(kda->da_u.filename, fullpath, strlen(fullpath) + 1);
2N/A
2N/A kda->da_iskernel = B_FALSE;
2N/A
2N/A darg.data_ptr = (char *)kda;
2N/A darg.data_size = sizeof (kcf_door_arg_t);
2N/A darg.desc_ptr = NULL;
2N/A darg.desc_num = 0;
2N/A darg.rbuf = (char *)kda;
2N/A darg.rsize = sizeof (kcf_door_arg_t);
2N/A
2N/A while ((r = door_call(kcfdfd, &darg)) != 0) {
2N/A /* save errno and test for certain errors */
2N/A door_errno = errno;
2N/A if (door_errno == EINTR || door_errno == EAGAIN)
2N/A continue;
2N/A /* if disabled or maintenance mode - bail */
2N/A if (cryptosvc_is_down())
2N/A break;
2N/A /* exceeded our number of tries? */
2N/A if (is_cryptosvc_up_count > MAX_CRYPTOSVC_ONLINE_TRIES)
2N/A break;
2N/A /* if stale door_handle, retry the open */
2N/A if (door_errno == EBADF) {
2N/A try_door_open_again = B_TRUE;
2N/A is_cryptosvc_up_count++;
2N/A (void) sleep(5);
2N/A goto verifycleanup;
2N/A } else
2N/A break;
2N/A }
2N/A
2N/A if (r != 0) {
2N/A if (!cryptosvc_is_online()) {
2N/A cryptoerror(LOG_ERR, "%s is not online "
2N/A " - unable to utilize cryptographic "
2N/A "services. (see svcs -xv for details).",
2N/A CRYPTOSVC_DEFAULT_INSTANCE_FMRI);
2N/A } else {
2N/A cryptoerror(LOG_ERR, "libpkcs11: door_call "
2N/A "of door_file %s failed with error %s.",
2N/A _PATH_KCFD_DOOR, strerror(door_errno));
2N/A }
2N/A *rv = CKR_CRYPTOKI_NOT_INITIALIZED;
2N/A estatus = ELFSIGN_UNAVAILABLE;
2N/A goto verifycleanup;
2N/A }
2N/A
2N/A /*LINTED*/
2N/A rkda = (kcf_door_arg_t *)darg.rbuf;
2N/A if (rkda->da_version != KCF_KCFD_VERSION1) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: kcfd and libelfsign versions "
2N/A "don't match: got %d expected %d", rkda->da_version,
2N/A KCF_KCFD_VERSION1);
2N/A goto verifycleanup;
2N/A }
2N/A estatus = rkda->da_u.result.status;
2N/Averifycleanup:
2N/A if (kcfdfd != -1) {
2N/A (void) close(kcfdfd);
2N/A }
2N/A if (rkda != NULL && rkda != kda)
2N/A (void) munmap((char *)rkda, darg.rsize);
2N/A if (kda != NULL) {
2N/A bzero(kda, sizeof (kda));
2N/A free(kda);
2N/A kda = NULL;
2N/A rkda = NULL; /* rkda is an alias of kda */
2N/A }
2N/A if (try_door_open_again) {
2N/A try_door_open_again = B_FALSE;
2N/A goto open_door_file;
2N/A }
2N/A
2N/A return (estatus);
2N/A}
2N/A
2N/A
2N/A#define NUM_FILES(files) (sizeof (files) / sizeof (char *))
2N/A
2N/A/* Userland FIPS 140 Boundary Files */
2N/Astatic char *userland_fips140_files[] = {
2N/A#ifdef _LP64
2N/A "/usr/lib/64/libpkcs11.so.1",
2N/A "/usr/lib/security/64/pkcs11_softtoken.so.1",
2N/A "/lib/64/libmd.so.1",
2N/A "/lib/64/libcryptoutil.so.1",
2N/A "/usr/lib/64/libsoftcrypto.so.1"
2N/A#else
2N/A "/usr/lib/libpkcs11.so.1",
2N/A "/usr/lib/security/pkcs11_softtoken.so.1",
2N/A "/lib/libmd.so.1",
2N/A "/lib/libcryptoutil.so.1",
2N/A "/usr/lib/libsoftcrypto.so.1"
2N/A#endif
2N/A};
2N/A
2N/A
2N/A/*
2N/A * For each provider found in pkcs11.conf: expand $ISA if necessary,
2N/A * verify the module is signed, load the provider, find all of its
2N/A * slots, and store the function list and disabled policy.
2N/A *
2N/A * This function requires that the uentrylist_t and pkcs11_slottable_t
2N/A * already have memory allocated, and that the uentrylist_t is already
2N/A * populated with provider and policy information.
2N/A *
2N/A * pInitArgs can be set to NULL, but is normally the same value
2N/A * the framework's C_Initialize() was called with.
2N/A *
2N/A * Unless metaslot is explicitly disabled, it is setup when all other
2N/A * providers are loaded.
2N/A */
2N/ACK_RV
2N/Apkcs11_slot_mapping(uentrylist_t *pplist, CK_VOID_PTR pInitArgs)
2N/A{
2N/A CK_RV rv = CKR_OK;
2N/A CK_RV prov_rv; /* Provider's return code */
2N/A CK_INFO prov_info;
2N/A CK_RV (*Tmp_C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR);
2N/A CK_FUNCTION_LIST_PTR prov_funcs = NULL; /* Provider's function list */
2N/A CK_ULONG prov_slot_count; /* Number of slots */
2N/A CK_SLOT_ID slot_id; /* slotID assigned for framework */
2N/A CK_SLOT_ID_PTR prov_slots = NULL; /* Provider's slot list */
2N/A /* Enabled or Disabled policy */
2N/A CK_MECHANISM_TYPE_PTR prov_pol_mechs = NULL;
2N/A
2N/A void *dldesc = NULL;
2N/A char *isa, *fullpath = NULL, *dl_error;
2N/A uentrylist_t *phead;
2N/A uint_t prov_count = 0;
2N/A pkcs11_slot_t *cur_slot;
2N/A CK_ULONG i;
2N/A size_t len;
2N/A uentry_t *metaslot_entry = NULL;
2N/A /* number of slots in the framework, not including metaslot */
2N/A uint_t slot_count = 0;
2N/A
2N/A ELFsign_status_t estatus = ELFSIGN_UNKNOWN;
2N/A char *estatus_str = NULL;
2N/A int fips140_mode = CRYPTO_FIPS_MODE_DISABLED;
2N/A
2N/A /* Check FIPS 140 configuration and execute check if enabled */
2N/A (void) get_fips_mode(&fips140_mode);
2N/A if (fips140_mode) {
2N/A int i;
2N/A for (i = 0; i < NUM_FILES(userland_fips140_files); i++) {
2N/A rv = fips_check_module(userland_fips140_files[i]);
2N/A if (rv != 0) {
2N/A cryptoerror(LOG_ERR, "libpkcs11: failed FIPS "
2N/A "140 integrity check for %s.",
2N/A userland_fips140_files[i]);
2N/A return (CKR_GENERAL_ERROR);
2N/A }
2N/A }
2N/A }
2N/A
2N/A phead = pplist;
2N/A
2N/A /* Loop through all of the provider listed in pkcs11.conf */
2N/A while (phead != NULL) {
2N/A if (!strcasecmp(phead->puent->name, "metaslot")) {
2N/A /*
2N/A * Skip standard processing for metaslot
2N/A * entry since it is not an actual library
2N/A * that can be dlopened.
2N/A * It will be initialized later.
2N/A */
2N/A if (metaslot_entry != NULL) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: multiple entries for metaslot "
2N/A "detected. All but the first entry will "
2N/A "be ignored");
2N/A } else {
2N/A metaslot_entry = phead->puent;
2N/A }
2N/A goto contparse;
2N/A }
2N/A
2N/A if (!strcasecmp(phead->puent->name, FIPS_KEYWORD)) {
2N/A /*
2N/A * Skip standard processing for fips-140
2N/A * entry since it is not an actual library
2N/A * that can be dlopened.
2N/A */
2N/A goto contparse;
2N/A }
2N/A
2N/A /* Check for Instruction Set Architecture indicator */
2N/A if ((isa = strstr(phead->puent->name, PKCS11_ISA)) != NULL) {
2N/A /* Substitute the architecture dependent path */
2N/A len = strlen(phead->puent->name) -
2N/A strlen(PKCS11_ISA) +
2N/A strlen(PKCS11_ISA_DIR) + 1;
2N/A if ((fullpath = (char *)malloc(len)) == NULL) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpksc11: parsing %s, out of memory. "
2N/A "Cannot continue parsing.",
2N/A _PATH_PKCS11_CONF);
2N/A rv = CKR_HOST_MEMORY;
2N/A goto conferror;
2N/A }
2N/A *isa = '\000';
2N/A isa += strlen(PKCS11_ISA);
2N/A (void) snprintf(fullpath, len, "%s%s%s",
2N/A phead->puent->name, PKCS11_ISA_DIR, isa);
2N/A } else if ((fullpath = strdup(phead->puent->name)) == 0) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: parsing %s, out of memory. "
2N/A "Cannot continue parsing.",
2N/A _PATH_PKCS11_CONF);
2N/A rv = CKR_HOST_MEMORY;
2N/A goto conferror;
2N/A }
2N/A
2N/A /*
2N/A * Open the provider. We assume all of our plugins have
2N/A * their symbols properly defined, so the use of RTLD_NOW
2N/A * to flush out errors immediately is not necessary.
2N/A *
2N/A * Note that for proper operation, all plugins must be
2N/A * built with direct bindings enabled.
2N/A */
2N/A dldesc = dlopen(fullpath, RTLD_LAZY);
2N/A
2N/A /*
2N/A * If we failed to load it, we will just skip this
2N/A * provider and move on to the next one.
2N/A */
2N/A if (dldesc == NULL) {
2N/A dl_error = dlerror();
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: Cannot load PKCS#11 library %s. "
2N/A "dlerror: %s. %s",
2N/A fullpath, dl_error != NULL ? dl_error : "Unknown",
2N/A conf_err);
2N/A goto contparse;
2N/A }
2N/A
2N/A /* Get the pointer to provider's C_GetFunctionList() */
2N/A Tmp_C_GetFunctionList =
2N/A (CK_RV(*)())dlsym(dldesc, "C_GetFunctionList");
2N/A
2N/A /*
2N/A * If we failed to get the pointer to C_GetFunctionList(),
2N/A * skip this provider and continue to the next one.
2N/A */
2N/A if (Tmp_C_GetFunctionList == NULL) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: Could not dlsym() C_GetFunctionList() "
2N/A "for %s. May not be a PKCS#11 library. %s",
2N/A fullpath, conf_err);
2N/A (void) dlclose(dldesc);
2N/A goto contparse;
2N/A }
2N/A
2N/A
2N/A /* Get the provider's function list */
2N/A prov_rv = Tmp_C_GetFunctionList(&prov_funcs);
2N/A
2N/A /*
2N/A * If we failed to get the provider's function list,
2N/A * skip this provider and continue to the next one.
2N/A */
2N/A if (prov_rv != CKR_OK) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: Could not get function list for %s. "
2N/A "%s Error: %s.",
2N/A fullpath, conf_err, pkcs11_strerror(prov_rv));
2N/A (void) dlclose(dldesc);
2N/A goto contparse;
2N/A }
2N/A
2N/A /* Initialize this provider */
2N/A prov_rv = prov_funcs->C_Initialize(pInitArgs);
2N/A
2N/A /*
2N/A * If we failed to initialize this provider,
2N/A * skip this provider and continue to the next one.
2N/A */
2N/A if ((prov_rv != CKR_OK) &&
2N/A (prov_rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: Could not initialize %s. "
2N/A "%s Error: %s.",
2N/A fullpath, conf_err, pkcs11_strerror(prov_rv));
2N/A (void) dlclose(dldesc);
2N/A goto contparse;
2N/A }
2N/A
2N/A /*
2N/A * Make sure this provider is implementing the same
2N/A * major version, and at least the same minor version
2N/A * that we are.
2N/A */
2N/A prov_rv = prov_funcs->C_GetInfo(&prov_info);
2N/A
2N/A /*
2N/A * If we can't verify that we are implementing the
2N/A * same major version, or if it is definitely not the same
2N/A * version, we need to skip this provider.
2N/A */
2N/A if ((prov_rv != CKR_OK) ||
2N/A (prov_info.cryptokiVersion.major !=
2N/A CRYPTOKI_VERSION_MAJOR)) {
2N/A if (prov_rv != CKR_OK) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: Could not verify version of "
2N/A "%s. %s Error: %s.", fullpath,
2N/A conf_err, pkcs11_strerror(prov_rv));
2N/A } else {
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: Only CRYPTOKI major version "
2N/A "%d is supported. %s is major "
2N/A "version %d. %s",
2N/A CRYPTOKI_VERSION_MAJOR, fullpath,
2N/A prov_info.cryptokiVersion.major, conf_err);
2N/A }
2N/A (void) prov_funcs->C_Finalize(NULL);
2N/A (void) dlclose(dldesc);
2N/A goto contparse;
2N/A }
2N/A
2N/A /*
2N/A * Warn the administrator (at debug) that a provider with
2N/A * a significantly older or newer version of
2N/A * CRYPTOKI is being used. It should not cause
2N/A * problems, but logging a warning makes it easier
2N/A * to debug later.
2N/A */
2N/A if ((prov_info.cryptokiVersion.minor <
2N/A CRYPTOKI_VERSION_WARN_MINOR) ||
2N/A (prov_info.cryptokiVersion.minor >
2N/A CRYPTOKI_VERSION_MINOR)) {
2N/A cryptoerror(LOG_DEBUG,
2N/A "libpkcs11: %s CRYPTOKI minor version, %d, may "
2N/A "not be compatible with minor version %d.",
2N/A fullpath, prov_info.cryptokiVersion.minor,
2N/A CRYPTOKI_VERSION_MINOR);
2N/A }
2N/A
2N/A /*
2N/A * Find out how many slots this provider has,
2N/A * call with tokenPresent set to FALSE so all
2N/A * potential slots are returned.
2N/A */
2N/A prov_rv = prov_funcs->C_GetSlotList(FALSE,
2N/A NULL, &prov_slot_count);
2N/A
2N/A /*
2N/A * If the call failed, or if no slots are returned,
2N/A * then skip this provider and continue to next one.
2N/A */
2N/A if (prov_rv != CKR_OK) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpksc11: Could not get slot list from %s. "
2N/A "%s Error: %s.",
2N/A fullpath, conf_err, pkcs11_strerror(prov_rv));
2N/A (void) prov_funcs->C_Finalize(NULL);
2N/A (void) dlclose(dldesc);
2N/A goto contparse;
2N/A }
2N/A
2N/A if (prov_slot_count == 0) {
2N/A cryptodebug("libpkcs11: No slots presented from %s. "
2N/A "Skipping this plug-in at this time.\n",
2N/A fullpath);
2N/A (void) prov_funcs->C_Finalize(NULL);
2N/A (void) dlclose(dldesc);
2N/A goto contparse;
2N/A }
2N/A
2N/A /*
2N/A * Verify that the module is signed correctly.
2N/A *
2N/A * NOTE: there is a potential race condition here,
2N/A * since the module is verified well after we have
2N/A * opened the provider via dlopen(). This could be
2N/A * resolved by a variant of dlopen() that would take a
2N/A * file descriptor as an argument and by changing the
2N/A * kcfd libelfsign door protocol to use and fd instead
2N/A * of a path - but that wouldn't work in the kernel case.
2N/A */
2N/A estatus = kcfd_door_call(fullpath, &rv);
2N/A
2N/A switch (estatus) {
2N/A case ELFSIGN_SUCCESS:
2N/A break;
2N/A case ELFSIGN_NOTSIGNED:
2N/A estatus_str = "not a signed provider.";
2N/A break;
2N/A case ELFSIGN_FAILED:
2N/A estatus_str = "signature verification failed.";
2N/A break;
2N/A case ELFSIGN_UNAVAILABLE:
2N/A estatus_str = "kcfd(1m) is not available for "
2N/A "signature verification. Cannot continue loading "
2N/A "the cryptographic framework.";
2N/A break;
2N/A default:
2N/A estatus_str = "unexpected failure in ELF "
2N/A "signature verification.";
2N/A }
2N/A if (estatus_str != NULL) {
2N/A if (estatus != ELFSIGN_UNAVAILABLE) {
2N/A cryptoerror(LOG_ERR, "libpkcs11: %s %s %s",
2N/A fullpath, estatus_str,
2N/A estatus == ELFSIGN_UNKNOWN ?
2N/A "See cryptoadm (1M). "
2N/A "Cannot continue parsing "
2N/A _PATH_PKCS11_CONF : conf_err);
2N/A } else {
2N/A cryptoerror(LOG_ERR, "libpkcs11: %s",
2N/A estatus_str);
2N/A }
2N/A
2N/A (void) prov_funcs->C_Finalize(NULL);
2N/A (void) dlclose(dldesc);
2N/A estatus_str = NULL;
2N/A if (estatus == ELFSIGN_UNKNOWN ||
2N/A estatus == ELFSIGN_UNAVAILABLE) {
2N/A prov_funcs = NULL;
2N/A dldesc = NULL;
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto conferror;
2N/A }
2N/A goto contparse;
2N/A }
2N/A
2N/A /* Allocate memory for the slot list */
2N/A prov_slots = calloc(prov_slot_count, sizeof (CK_SLOT_ID));
2N/A
2N/A if (prov_slots == NULL) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: Could not allocate memory for "
2N/A "plug-in slots. Cannot continue parsing %s\n",
2N/A _PATH_PKCS11_CONF);
2N/A rv = CKR_HOST_MEMORY;
2N/A goto conferror;
2N/A }
2N/A
2N/A /* Get slot list from provider */
2N/A prov_rv = prov_funcs->C_GetSlotList(FALSE,
2N/A prov_slots, &prov_slot_count);
2N/A
2N/A /* if second call fails, drop this provider */
2N/A if (prov_rv != CKR_OK) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: Second call to C_GetSlotList() for %s "
2N/A "failed. %s Error: %s.",
2N/A fullpath, conf_err, pkcs11_strerror(prov_rv));
2N/A (void) prov_funcs->C_Finalize(NULL);
2N/A (void) dlclose(dldesc);
2N/A goto contparse;
2N/A }
2N/A
2N/A /*
2N/A * Parse the list of disabled or enabled mechanisms, will
2N/A * apply to each of the provider's slots.
2N/A */
2N/A if (phead->puent->count > 0) {
2N/A rv = pkcs11_mech_parse(phead->puent->policylist,
2N/A &prov_pol_mechs, phead->puent->count);
2N/A
2N/A if (rv == CKR_HOST_MEMORY) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: Could not parse configuration,"
2N/A "out of memory. Cannot continue parsing "
2N/A "%s.", _PATH_PKCS11_CONF);
2N/A goto conferror;
2N/A } else if (rv == CKR_MECHANISM_INVALID) {
2N/A /*
2N/A * Configuration file is corrupted for this
2N/A * provider.
2N/A */
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: Policy invalid or corrupted "
2N/A "for %s. Use cryptoadm(1M) to fix "
2N/A "this. Skipping this plug-in.",
2N/A fullpath);
2N/A (void) prov_funcs->C_Finalize(NULL);
2N/A (void) dlclose(dldesc);
2N/A goto contparse;
2N/A }
2N/A }
2N/A
2N/A /* Allocate memory in our slottable for these slots */
2N/A rv = pkcs11_slottable_increase(prov_slot_count);
2N/A
2N/A /*
2N/A * If any error is returned, it will be memory related,
2N/A * so we need to abort the attempt at filling the
2N/A * slottable.
2N/A */
2N/A if (rv != CKR_OK) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: slottable could not increase. "
2N/A "Cannot continue parsing %s.",
2N/A _PATH_PKCS11_CONF);
2N/A goto conferror;
2N/A }
2N/A
2N/A /* Configure information for each new slot */
2N/A for (i = 0; i < prov_slot_count; i++) {
2N/A /* allocate slot in framework */
2N/A rv = pkcs11_slot_allocate(&slot_id);
2N/A if (rv != CKR_OK) {
2N/A cryptoerror(LOG_ERR,
2N/A "libpkcs11: Could not allocate "
2N/A "new slot. Cannot continue parsing %s.",
2N/A _PATH_PKCS11_CONF);
2N/A goto conferror;
2N/A }
2N/A slot_count++;
2N/A cur_slot = slottable->st_slots[slot_id];
2N/A (void) pthread_mutex_lock(&cur_slot->sl_mutex);
2N/A cur_slot->sl_id = prov_slots[i];
2N/A cur_slot->sl_func_list = prov_funcs;
2N/A cur_slot->sl_enabledpol =
2N/A phead->puent->flag_enabledlist;
2N/A cur_slot->sl_pol_mechs = prov_pol_mechs;
2N/A cur_slot->sl_pol_count = phead->puent->count;
2N/A cur_slot->sl_norandom = phead->puent->flag_norandom;
2N/A cur_slot->sl_dldesc = dldesc;
2N/A cur_slot->sl_prov_id = prov_count + 1;
2N/A (void) pthread_mutex_unlock(&cur_slot->sl_mutex);
2N/A }
2N/A
2N/A /*
2N/A * Get the pointer to private interface _SUNW_GetThreshold()
2N/A * in pkcs11_kernel.
2N/A */
2N/A
2N/A if (Tmp_GetThreshold == NULL) {
2N/A Tmp_GetThreshold =
2N/A (void(*)())dlsym(dldesc, "_SUNW_GetThreshold");
2N/A
2N/A /* Get the threshold values for the supported mechs */
2N/A if (Tmp_GetThreshold != NULL) {
2N/A (void) memset(meta_mechs_threshold, 0,
2N/A sizeof (meta_mechs_threshold));
2N/A Tmp_GetThreshold(meta_mechs_threshold);
2N/A }
2N/A }
2N/A
2N/A /* Set and reset values to process next provider */
2N/A prov_count++;
2N/Acontparse:
2N/A prov_slot_count = 0;
2N/A Tmp_C_GetFunctionList = NULL;
2N/A prov_funcs = NULL;
2N/A dldesc = NULL;
2N/A if (fullpath != NULL) {
2N/A free(fullpath);
2N/A fullpath = NULL;
2N/A }
2N/A if (prov_slots != NULL) {
2N/A free(prov_slots);
2N/A prov_slots = NULL;
2N/A }
2N/A phead = phead->next;
2N/A }
2N/A
2N/A if (slot_count == 0) {
2N/A /*
2N/A * there's no other slot in the framework,
2N/A * there is nothing to do
2N/A */
2N/A goto config_complete;
2N/A }
2N/A
2N/A /* determine if metaslot should be enabled */
2N/A
2N/A /*
2N/A * Check to see if any environment variable is defined
2N/A * by the user for configuring metaslot. Users'
2N/A * setting always take precedence over the system wide
2N/A * setting. So, we will first check for any user's
2N/A * defined env variables before looking at the system-wide
2N/A * configuration.
2N/A */
2N/A get_user_metaslot_config();
2N/A
2N/A /* no metaslot entry in /etc/crypto/pkcs11.conf */
2N/A if (!metaslot_entry) {
2N/A /*
2N/A * If user env variable indicates metaslot should be enabled,
2N/A * but there's no entry in /etc/crypto/pkcs11.conf for
2N/A * metaslot at all, will respect the user's defined value
2N/A */
2N/A if ((metaslot_config.enabled_specified) &&
2N/A (metaslot_config.enabled)) {
2N/A metaslot_enabled = B_TRUE;
2N/A }
2N/A } else {
2N/A if (!metaslot_config.enabled_specified) {
2N/A /*
2N/A * take system wide value if
2N/A * it is not specified by user
2N/A */
2N/A metaslot_enabled
2N/A = metaslot_entry->flag_metaslot_enabled;
2N/A } else {
2N/A metaslot_enabled = metaslot_config.enabled;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A *
2N/A * As long as the user or system configuration file does not
2N/A * disable metaslot, it will be enabled regardless of the
2N/A * number of slots plugged into the framework. Therefore,
2N/A * metaslot is enabled even when there's only one slot
2N/A * plugged into the framework. This is necessary for
2N/A * presenting a consistent token label view to applications.
2N/A *
2N/A * However, for the case where there is only 1 slot plugged into
2N/A * the framework, we can use "fastpath".
2N/A *
2N/A * "fastpath" will pass all of the application's requests
2N/A * directly to the underlying provider. Only when policy is in
2N/A * effect will we need to keep slotID around.
2N/A *
2N/A * When metaslot is enabled, and fastpath is enabled,
2N/A * all the metaslot processing will be skipped.
2N/A * When there is only 1 slot, there's
2N/A * really not much metaslot can do in terms of combining functionality
2N/A * of different slots, and object migration.
2N/A *
2N/A */
2N/A
2N/A /* check to see if fastpath can be used */
2N/A if (slottable->st_last == slottable->st_first) {
2N/A
2N/A cur_slot = slottable->st_slots[slottable->st_first];
2N/A
2N/A (void) pthread_mutex_lock(&cur_slot->sl_mutex);
2N/A
2N/A if ((cur_slot->sl_pol_count == 0) &&
2N/A (!cur_slot->sl_enabledpol) && (!cur_slot->sl_norandom)) {
2N/A /* No policy is in effect, don't need slotid */
2N/A fast_funcs = cur_slot->sl_func_list;
2N/A purefastpath = B_TRUE;
2N/A } else {
2N/A fast_funcs = cur_slot->sl_func_list;
2N/A fast_slot = slottable->st_first;
2N/A policyfastpath = B_TRUE;
2N/A }
2N/A
2N/A (void) pthread_mutex_unlock(&cur_slot->sl_mutex);
2N/A }
2N/A
2N/A if ((purefastpath || policyfastpath) && (!metaslot_enabled)) {
2N/A goto config_complete;
2N/A }
2N/A
2N/A /*
2N/A * If we get here, there are more than 2 slots in the framework,
2N/A * we need to set up metaslot if it is enabled
2N/A */
2N/A if (metaslot_enabled) {
2N/A rv = setup_metaslot(metaslot_entry);
2N/A if (rv != CKR_OK) {
2N/A goto conferror;
2N/A }
2N/A }
2N/A
2N/A
2N/Aconfig_complete:
2N/A
2N/A return (CKR_OK);
2N/A
2N/Aconferror:
2N/A /*
2N/A * This cleanup code is only exercised when a major,
2N/A * unrecoverable error like "out of memory" or
2N/A * kcfd is not reachable occurs.
2N/A */
2N/A if (prov_funcs != NULL) {
2N/A (void) prov_funcs->C_Finalize(NULL);
2N/A }
2N/A if (dldesc != NULL) {
2N/A (void) dlclose(dldesc);
2N/A }
2N/A if (fullpath != NULL) {
2N/A free(fullpath);
2N/A fullpath = NULL;
2N/A }
2N/A if (prov_slots != NULL) {
2N/A free(prov_slots);
2N/A prov_slots = NULL;
2N/A }
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * pkcs11_mech_parse will take hex mechanism ids, as a list of
2N/A * strings, and convert them to CK_MECHANISM_TYPE_PTR.
2N/A */
2N/ACK_RV
2N/Apkcs11_mech_parse(umechlist_t *str_list, CK_MECHANISM_TYPE_PTR *mech_list,
2N/A int mech_count)
2N/A{
2N/A CK_MECHANISM_TYPE_PTR tmp_list;
2N/A umechlist_t *shead = str_list;
2N/A
2N/A tmp_list = malloc(mech_count * sizeof (CK_MECHANISM_TYPE));
2N/A
2N/A if (tmp_list == NULL) {
2N/A cryptoerror(LOG_ERR, "libpkcs11: parsing %s, out of memory. "
2N/A "Cannot continue.",
2N/A _PATH_PKCS11_CONF);
2N/A return (CKR_HOST_MEMORY);
2N/A }
2N/A
2N/A *mech_list = tmp_list;
2N/A
2N/A /*
2N/A * The following will loop mech_count times, as there are
2N/A * exactly mech_count items in the str_list.
2N/A */
2N/A while (shead != NULL) {
2N/A CK_MECHANISM_TYPE cur_mech;
2N/A
2N/A errno = 0;
2N/A
2N/A /*
2N/A * "name" is a hexadecimal number, preceded by 0x.
2N/A */
2N/A cur_mech = strtoul(shead->name, NULL, 16);
2N/A
2N/A if ((cur_mech == 0) &&
2N/A ((errno == EINVAL) || (errno == ERANGE))) {
2N/A free(mech_list);
2N/A return (CKR_MECHANISM_INVALID);
2N/A }
2N/A *tmp_list = (CK_MECHANISM_TYPE)cur_mech;
2N/A tmp_list++;
2N/A shead = shead->next;
2N/A }
2N/A
2N/A return (CKR_OK);
2N/A}
2N/A
2N/A/*
2N/A * pkcs11_is_dismech is provided a slotid and a mechanism.
2N/A * If mech is not disabled, then return B_FALSE.
2N/A */
2N/Aboolean_t
2N/Apkcs11_is_dismech(CK_SLOT_ID slotid, CK_MECHANISM_TYPE mech)
2N/A{
2N/A ulong_t i;
2N/A boolean_t enabled_pol;
2N/A CK_MECHANISM_TYPE_PTR pol_mechs;
2N/A ulong_t pol_count;
2N/A
2N/A /* Find the associated slot and get the mech policy info */
2N/A (void) pthread_mutex_lock(&slottable->st_slots[slotid]->sl_mutex);
2N/A enabled_pol = slottable->st_slots[slotid]->sl_enabledpol;
2N/A pol_mechs = slottable->st_slots[slotid]->sl_pol_mechs;
2N/A pol_count = slottable->st_slots[slotid]->sl_pol_count;
2N/A (void) pthread_mutex_unlock(&slottable->st_slots[slotid]->sl_mutex);
2N/A
2N/A /* If there is a mech list, check it based on the policy in effect */
2N/A if (pol_mechs != NULL) {
2N/A for (i = 0; i < pol_count; i++) {
2N/A if (pol_mechs[i] == mech) {
2N/A /*
2N/A * mech found in metaslot's enabledlist=...
2N/A * doesn't ensure it is also enabled by at
2N/A * least one other underlying provider
2N/A */
2N/A if (slotid == METASLOT_FRAMEWORK_ID &&
2N/A enabled_pol)
2N/A /* stop and check providers */
2N/A goto need_search;
2N/A
2N/A return (enabled_pol ? B_FALSE : B_TRUE);
2N/A }
2N/A }
2N/A
2N/A if (slotid == METASLOT_FRAMEWORK_ID && enabled_pol)
2N/A return (B_TRUE);
2N/A }
2N/A
2N/A /* mech was not found in list */
2N/A if (slotid != METASLOT_FRAMEWORK_ID)
2N/A return (enabled_pol ? B_TRUE : B_FALSE);
2N/A
2N/Aneed_search:
2N/A /*
2N/A * ASSERT(slotid == METASLOT_FRAMEWORK_ID);
2N/A *
2N/A * One of these conditions should be true:
2N/A * a. metaslot has no explicit enabledlist=... nor disabledlist=...
2N/A * b. mech is explicitly listed in metaslot's enabledlist=...
2N/A * c. mech is explicitly omitted from metaslot's disabledlist=...
2N/A * It is still possible for the mech to be disabled or unavailable
2N/A * at the underlying provider level, thus not usable by Metaslot.
2N/A * If even one mech instance is enabled, return FALSE immediately.
2N/A */
2N/A for (i = slottable->st_first; i <= slottable->st_last; i++) {
2N/A if (pkcs11_is_valid_slot(i) != CKR_OK ||
2N/A i == METASLOT_FRAMEWORK_ID)
2N/A continue;
2N/A
2N/A if (pkcs11_is_dismech(i, mech) == B_FALSE)
2N/A return (B_FALSE);
2N/A }
2N/A
2N/A return (B_TRUE);
2N/A}