17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54468f880Sdarrenm  * Common Development and Distribution License (the "License").
64468f880Sdarrenm  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*fb99bed9SValerie Bubb Fenwick  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <sys/types.h>
267c478bd9Sstevel@tonic-gate #include <sys/stat.h>
277c478bd9Sstevel@tonic-gate #include <dlfcn.h>
287c478bd9Sstevel@tonic-gate #include <fcntl.h>
297c478bd9Sstevel@tonic-gate #include <link.h>
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <strings.h>
337c478bd9Sstevel@tonic-gate #include <errno.h>
347c478bd9Sstevel@tonic-gate #include <door.h>
357c478bd9Sstevel@tonic-gate #include <pthread.h>
367c478bd9Sstevel@tonic-gate #include <sys/mman.h>
37a3840491SPeter Shoults #include <libscf.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #include <sys/crypto/elfsign.h>
407c478bd9Sstevel@tonic-gate #include <cryptoutil.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
437c478bd9Sstevel@tonic-gate #include "pkcs11Global.h"
447c478bd9Sstevel@tonic-gate #include "pkcs11Conf.h"
457c478bd9Sstevel@tonic-gate #include "pkcs11Slot.h"
467c478bd9Sstevel@tonic-gate #include "metaGlobal.h"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate  * Fastpath is used when there is only one slot available from a single provider
507c478bd9Sstevel@tonic-gate  * plugged into the framework this is the common case.
517c478bd9Sstevel@tonic-gate  * These globals are used to track the function pointers and policy when
527c478bd9Sstevel@tonic-gate  * the fast-path is activated.
537c478bd9Sstevel@tonic-gate  * This will need to be revisted if per-slot policy is ever
547c478bd9Sstevel@tonic-gate  * implemented.
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate boolean_t purefastpath = B_FALSE;
577c478bd9Sstevel@tonic-gate boolean_t policyfastpath = B_FALSE;
587c478bd9Sstevel@tonic-gate CK_FUNCTION_LIST_PTR fast_funcs = NULL;
597c478bd9Sstevel@tonic-gate CK_SLOT_ID fast_slot = 0;
607c478bd9Sstevel@tonic-gate boolean_t metaslot_enabled = B_FALSE;
617c478bd9Sstevel@tonic-gate boolean_t metaslot_auto_key_migrate = B_FALSE;
627c478bd9Sstevel@tonic-gate metaslot_config_t metaslot_config;
63a039cd31Shaimay void (*Tmp_GetThreshold)(void *) = NULL;
64a039cd31Shaimay cipher_mechs_threshold_t meta_mechs_threshold[MAX_NUM_THRESHOLD];
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate static const char *conf_err = "See cryptoadm(1M). Skipping this plug-in.";
677c478bd9Sstevel@tonic-gate 
68a3840491SPeter Shoults #define	CRYPTOSVC_DEFAULT_INSTANCE_FMRI "svc:/system/cryptosvc:default"
69a3840491SPeter Shoults #define	MAX_CRYPTOSVC_ONLINE_TRIES 5
70a3840491SPeter Shoults 
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate  * Set up metaslot for the framework using either user configuration
737c478bd9Sstevel@tonic-gate  * or system wide configuration options
747c478bd9Sstevel@tonic-gate  *
757c478bd9Sstevel@tonic-gate  * Also sets up the global "slottable" to have the first slot be metaslot.
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate static CK_RV
787c478bd9Sstevel@tonic-gate setup_metaslot(uentry_t *metaslot_entry) {
797c478bd9Sstevel@tonic-gate 	CK_RV rv;
807c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE_PTR prov_pol_mechs = NULL;
817c478bd9Sstevel@tonic-gate 	pkcs11_slot_t *cur_slot;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	/* process policies for mechanisms */
847c478bd9Sstevel@tonic-gate 	if ((metaslot_entry) && (metaslot_entry->count > 0)) {
857c478bd9Sstevel@tonic-gate 		rv = pkcs11_mech_parse(metaslot_entry->policylist,
867c478bd9Sstevel@tonic-gate 		    &prov_pol_mechs, metaslot_entry->count);
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 		if (rv == CKR_HOST_MEMORY) {
897c478bd9Sstevel@tonic-gate 			cryptoerror(LOG_ERR,
907c478bd9Sstevel@tonic-gate 			    "libpkcs11: Could not parse configuration,"
917c478bd9Sstevel@tonic-gate 			    "out of memory. Cannot continue parsing "
927c478bd9Sstevel@tonic-gate 			    "%s.\n", _PATH_PKCS11_CONF);
937c478bd9Sstevel@tonic-gate 			return (rv);
947c478bd9Sstevel@tonic-gate 		} else if (rv == CKR_MECHANISM_INVALID) {
957c478bd9Sstevel@tonic-gate 			/*
967c478bd9Sstevel@tonic-gate 			 * Configuration file is corrupted for metaslot
977c478bd9Sstevel@tonic-gate 			 */
987c478bd9Sstevel@tonic-gate 			cryptoerror(LOG_ERR,
997c478bd9Sstevel@tonic-gate 			    "libpkcs11: Policy invalid or corrupted "
1007c478bd9Sstevel@tonic-gate 			    "for metaslot. Use cryptoadm(1M) to fix "
1017c478bd9Sstevel@tonic-gate 			    "this. Disabling metaslot functionality.\n");
1027c478bd9Sstevel@tonic-gate 			metaslot_enabled = B_FALSE;
1037c478bd9Sstevel@tonic-gate 			return (rv);
1047c478bd9Sstevel@tonic-gate 		}
1057c478bd9Sstevel@tonic-gate 	}
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	/*
1087c478bd9Sstevel@tonic-gate 	 * Check for metaslot policy.  If all mechanisms are
1097c478bd9Sstevel@tonic-gate 	 * disabled, disable metaslot since there is nothing
1107c478bd9Sstevel@tonic-gate 	 * interesting for it to do
1117c478bd9Sstevel@tonic-gate 	 */
1127c478bd9Sstevel@tonic-gate 	if ((metaslot_entry) && (metaslot_entry->flag_enabledlist) &&
1137c478bd9Sstevel@tonic-gate 	    (prov_pol_mechs == NULL)) {
1147c478bd9Sstevel@tonic-gate 		metaslot_enabled = B_FALSE;
1157c478bd9Sstevel@tonic-gate 		return (rv);
1167c478bd9Sstevel@tonic-gate 	}
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	/*
1197c478bd9Sstevel@tonic-gate 	 * save system wide value for metaslot's keystore.
1207c478bd9Sstevel@tonic-gate 	 * If either slot description or token label is specified by
1217c478bd9Sstevel@tonic-gate 	 * the user, the system wide value for both is ignored.
1227c478bd9Sstevel@tonic-gate 	 */
1237c478bd9Sstevel@tonic-gate 	if ((metaslot_entry) &&
1247c478bd9Sstevel@tonic-gate 	    (!metaslot_config.keystore_token_specified) &&
1257c478bd9Sstevel@tonic-gate 	    (!metaslot_config.keystore_slot_specified)) {
1267c478bd9Sstevel@tonic-gate 		/*
1277c478bd9Sstevel@tonic-gate 		 * blank_str is used for comparing with token label,
1287c478bd9Sstevel@tonic-gate 		 * and slot description, make sure it is better than
1297c478bd9Sstevel@tonic-gate 		 * the larger of both
1307c478bd9Sstevel@tonic-gate 		 */
1317c478bd9Sstevel@tonic-gate 		char blank_str[TOKEN_LABEL_SIZE + SLOT_DESCRIPTION_SIZE];
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 		bzero(blank_str, sizeof (blank_str));
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 		if (memcmp(metaslot_entry->metaslot_ks_token,
1367c478bd9Sstevel@tonic-gate 		    blank_str, TOKEN_LABEL_SIZE) != 0) {
1377c478bd9Sstevel@tonic-gate 			metaslot_config.keystore_token_specified = B_TRUE;
1387c478bd9Sstevel@tonic-gate 			(void) strlcpy(
1397c478bd9Sstevel@tonic-gate 			    (char *)metaslot_config.keystore_token,
1407c478bd9Sstevel@tonic-gate 			    (const char *)metaslot_entry->metaslot_ks_token,
1417c478bd9Sstevel@tonic-gate 			    TOKEN_LABEL_SIZE);
1427c478bd9Sstevel@tonic-gate 		}
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 		if (memcmp(metaslot_entry->metaslot_ks_slot,
1457c478bd9Sstevel@tonic-gate 		    blank_str, SLOT_DESCRIPTION_SIZE) != 0) {
1467c478bd9Sstevel@tonic-gate 			metaslot_config.keystore_slot_specified = B_TRUE;
1477c478bd9Sstevel@tonic-gate 			(void) strlcpy(
1487c478bd9Sstevel@tonic-gate 			    (char *)metaslot_config.keystore_slot,
1497c478bd9Sstevel@tonic-gate 			    (const char *)metaslot_entry->metaslot_ks_slot,
1507c478bd9Sstevel@tonic-gate 			    SLOT_DESCRIPTION_SIZE);
1517c478bd9Sstevel@tonic-gate 		}
1527c478bd9Sstevel@tonic-gate 	}
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	/* check system-wide value for auto_key_migrate */
1557c478bd9Sstevel@tonic-gate 	if (metaslot_config.auto_key_migrate_specified) {
1567c478bd9Sstevel@tonic-gate 		/* take user's specified value */
1577c478bd9Sstevel@tonic-gate 		metaslot_auto_key_migrate = metaslot_config.auto_key_migrate;
1587c478bd9Sstevel@tonic-gate 	} else {
1597c478bd9Sstevel@tonic-gate 		if (metaslot_entry) {
1607c478bd9Sstevel@tonic-gate 			/* use system-wide default */
1617c478bd9Sstevel@tonic-gate 			metaslot_auto_key_migrate =
1627c478bd9Sstevel@tonic-gate 			    metaslot_entry->flag_metaslot_auto_key_migrate;
1637c478bd9Sstevel@tonic-gate 		} else {
1647c478bd9Sstevel@tonic-gate 			/*
1657c478bd9Sstevel@tonic-gate 			 * there's no system wide metaslot entry,
1667c478bd9Sstevel@tonic-gate 			 * default auto_key_migrate to true
1677c478bd9Sstevel@tonic-gate 			 */
1687c478bd9Sstevel@tonic-gate 			metaslot_auto_key_migrate = B_TRUE;
1697c478bd9Sstevel@tonic-gate 		}
1707c478bd9Sstevel@tonic-gate 	}
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	/* Make first slotID be 0, for metaslot. */
1747c478bd9Sstevel@tonic-gate 	slottable->st_first = 0;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	/* Set up the slottable entry for metaslot */
1777c478bd9Sstevel@tonic-gate 	slottable->st_slots[0] = NULL;
1787c478bd9Sstevel@tonic-gate 	cur_slot = calloc(1, sizeof (pkcs11_slot_t));
1797c478bd9Sstevel@tonic-gate 	if (cur_slot == NULL) {
1807c478bd9Sstevel@tonic-gate 		rv = CKR_HOST_MEMORY;
1817c478bd9Sstevel@tonic-gate 		return (rv);
1827c478bd9Sstevel@tonic-gate 	}
1837c478bd9Sstevel@tonic-gate 	cur_slot->sl_wfse_state = WFSE_CLEAR;
1847c478bd9Sstevel@tonic-gate 	cur_slot->sl_enabledpol = B_FALSE;
1857c478bd9Sstevel@tonic-gate 	cur_slot->sl_no_wfse = B_FALSE;
1867c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&cur_slot->sl_mutex, NULL);
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	/*
1897c478bd9Sstevel@tonic-gate 	 * The metaslot entry was prealloc'd by
1907c478bd9Sstevel@tonic-gate 	 * pkcs11_slottable_increase()
1917c478bd9Sstevel@tonic-gate 	 */
1927c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->st_mutex);
1937c478bd9Sstevel@tonic-gate 	slottable->st_slots[0] = cur_slot;
1947c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&slottable->st_mutex);
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&cur_slot->sl_mutex);
1977c478bd9Sstevel@tonic-gate 	cur_slot->sl_id = METASLOT_SLOTID;
1987c478bd9Sstevel@tonic-gate 	cur_slot->sl_func_list = &metaslot_functionList;
1997c478bd9Sstevel@tonic-gate 	if (metaslot_entry) {
2007c478bd9Sstevel@tonic-gate 		cur_slot->sl_enabledpol = metaslot_entry->flag_enabledlist;
2017c478bd9Sstevel@tonic-gate 		cur_slot->sl_pol_count = metaslot_entry->count;
2027c478bd9Sstevel@tonic-gate 	} else {
2037c478bd9Sstevel@tonic-gate 		/* if no metaslot entry, assume all mechs are enabled */
2047c478bd9Sstevel@tonic-gate 		cur_slot->sl_enabledpol = B_FALSE;
2057c478bd9Sstevel@tonic-gate 		cur_slot->sl_pol_count = 0;
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate 	cur_slot->sl_pol_mechs = prov_pol_mechs;
2087c478bd9Sstevel@tonic-gate 	cur_slot->sl_dldesc = NULL; /* not applicable */
2097c478bd9Sstevel@tonic-gate 	cur_slot->sl_prov_id = 0;
2107c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	/* Call the meta_Initialize() to initialize metaslot */
2137c478bd9Sstevel@tonic-gate 	rv = meta_Initialize(NULL);
2147c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
2157c478bd9Sstevel@tonic-gate 		cryptoerror(LOG_ERR,
2167c478bd9Sstevel@tonic-gate 		    "libpkcs11: Can't initialize metaslot (%s)",
2177c478bd9Sstevel@tonic-gate 		    pkcs11_strerror(rv));
2187c478bd9Sstevel@tonic-gate 		goto cleanup;
2197c478bd9Sstevel@tonic-gate 	}
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	return (CKR_OK);
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate cleanup:
2247c478bd9Sstevel@tonic-gate 	metaslot_enabled = B_FALSE;
2257c478bd9Sstevel@tonic-gate 	slottable->st_slots[0] = NULL;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	if (cur_slot) {
2287c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_destroy(&cur_slot->sl_mutex);
2297c478bd9Sstevel@tonic-gate 		free(cur_slot);
2307c478bd9Sstevel@tonic-gate 	}
2317c478bd9Sstevel@tonic-gate 	return (rv);
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate 
234a3840491SPeter Shoults /*
235a3840491SPeter Shoults  * cryptosvc_is_online()
236a3840491SPeter Shoults  *
237a3840491SPeter Shoults  * Determine if the SMF service instance is in the online state or
238a3840491SPeter Shoults  * not. A number of operations depend on this state.
239a3840491SPeter Shoults  */
240a3840491SPeter Shoults static boolean_t
241a3840491SPeter Shoults cryptosvc_is_online(void)
242a3840491SPeter Shoults {
243a3840491SPeter Shoults 	char *str;
244a3840491SPeter Shoults 	boolean_t ret = B_FALSE;
245a3840491SPeter Shoults 
246a3840491SPeter Shoults 	if ((str = smf_get_state(CRYPTOSVC_DEFAULT_INSTANCE_FMRI)) != NULL) {
247a3840491SPeter Shoults 		ret = (strcmp(str, SCF_STATE_STRING_ONLINE) == 0);
248a3840491SPeter Shoults 		free(str);
249a3840491SPeter Shoults 	}
250a3840491SPeter Shoults 	return (ret);
251a3840491SPeter Shoults }
252a3840491SPeter Shoults 
253a3840491SPeter Shoults /*
254a3840491SPeter Shoults  * cryptosvc_is_down()
255a3840491SPeter Shoults  *
256a3840491SPeter Shoults  * Determine if the SMF service instance is in the disabled state or
257a3840491SPeter Shoults  * maintenance state. A number of operations depend on this state.
258a3840491SPeter Shoults  */
259a3840491SPeter Shoults static boolean_t
260a3840491SPeter Shoults cryptosvc_is_down(void)
261a3840491SPeter Shoults {
262a3840491SPeter Shoults 	char *str;
263a3840491SPeter Shoults 	boolean_t ret = B_FALSE;
264a3840491SPeter Shoults 
265a3840491SPeter Shoults 	if ((str = smf_get_state(CRYPTOSVC_DEFAULT_INSTANCE_FMRI)) != NULL) {
266a3840491SPeter Shoults 		ret = ((strcmp(str, SCF_STATE_STRING_DISABLED) == 0) ||
267a3840491SPeter Shoults 		    (strcmp(str, SCF_STATE_STRING_MAINT) == 0));
268a3840491SPeter Shoults 		free(str);
269a3840491SPeter Shoults 	}
270a3840491SPeter Shoults 	return (ret);
271a3840491SPeter Shoults }
272a3840491SPeter Shoults 
27373556491SAnthony Scarpino 
27473556491SAnthony Scarpino /* Generic function for all door calls to kcfd. */
27573556491SAnthony Scarpino ELFsign_status_t
27673556491SAnthony Scarpino kcfd_door_call(char *fullpath, boolean_t fips140, CK_RV *rv)
27773556491SAnthony Scarpino {
27873556491SAnthony Scarpino 	boolean_t	try_door_open_again = B_FALSE;
27973556491SAnthony Scarpino 	int		 kcfdfd = -1;
28073556491SAnthony Scarpino 	door_arg_t	darg;
28173556491SAnthony Scarpino 	kcf_door_arg_t *kda = NULL;
28273556491SAnthony Scarpino 	kcf_door_arg_t *rkda = NULL;
28373556491SAnthony Scarpino 	int		r;
28473556491SAnthony Scarpino 	int		is_cryptosvc_up_count = 0;
28573556491SAnthony Scarpino 	int		door_errno = 0;
28673556491SAnthony Scarpino 	ELFsign_status_t estatus = ELFSIGN_UNKNOWN;
28773556491SAnthony Scarpino 
28873556491SAnthony Scarpino open_door_file:
28973556491SAnthony Scarpino 	while ((kcfdfd = open(_PATH_KCFD_DOOR, O_RDONLY)) == -1) {
29073556491SAnthony Scarpino 		/* save errno and test for EINTR or EAGAIN */
29173556491SAnthony Scarpino 		door_errno = errno;
29273556491SAnthony Scarpino 		if (door_errno == EINTR ||
29373556491SAnthony Scarpino 		    door_errno == EAGAIN)
29473556491SAnthony Scarpino 			continue;
29573556491SAnthony Scarpino 		/* if disabled or maintenance mode - bail */
29673556491SAnthony Scarpino 		if (cryptosvc_is_down())
29773556491SAnthony Scarpino 			break;
29873556491SAnthony Scarpino 		/* exceeded our number of tries? */
29973556491SAnthony Scarpino 		if (is_cryptosvc_up_count > MAX_CRYPTOSVC_ONLINE_TRIES)
30073556491SAnthony Scarpino 			break;
30173556491SAnthony Scarpino 		/* any other state, try again up to 1/2 minute */
30273556491SAnthony Scarpino 		(void) sleep(5);
30373556491SAnthony Scarpino 		is_cryptosvc_up_count++;
30473556491SAnthony Scarpino 	}
30573556491SAnthony Scarpino 	if (kcfdfd == -1) {
30673556491SAnthony Scarpino 		if (!cryptosvc_is_online()) {
3074ff712c4SValerie Bubb Fenwick 			cryptoerror(LOG_ERR, "libpkcs11: unable to communicate"
3084ff712c4SValerie Bubb Fenwick 			    " with kcfd, door_file %s: %s.  %s is not online."
30973556491SAnthony Scarpino 			    " (see svcs -xv for details).",
31073556491SAnthony Scarpino 			    _PATH_KCFD_DOOR, strerror(door_errno),
31173556491SAnthony Scarpino 			    CRYPTOSVC_DEFAULT_INSTANCE_FMRI);
31273556491SAnthony Scarpino 		} else {
31373556491SAnthony Scarpino 			cryptoerror(LOG_ERR, "libpkcs11: unable to open"
31473556491SAnthony Scarpino 			    " kcfd door_file %s: %s.", _PATH_KCFD_DOOR,
31573556491SAnthony Scarpino 			    strerror(door_errno));
31673556491SAnthony Scarpino 		}
31773556491SAnthony Scarpino 		*rv = CKR_CRYPTOKI_NOT_INITIALIZED;
3184ff712c4SValerie Bubb Fenwick 		estatus = ELFSIGN_UNAVAILABLE;
31973556491SAnthony Scarpino 		goto verifycleanup;
32073556491SAnthony Scarpino 	}
32173556491SAnthony Scarpino 
32273556491SAnthony Scarpino 	/* Mark the door "close on exec" */
32373556491SAnthony Scarpino 	(void) fcntl(kcfdfd, F_SETFD, FD_CLOEXEC);
32473556491SAnthony Scarpino 
32573556491SAnthony Scarpino 	if ((kda = malloc(sizeof (kcf_door_arg_t))) == NULL) {
32673556491SAnthony Scarpino 		cryptoerror(LOG_ERR, "libpkcs11: malloc of kda "
32773556491SAnthony Scarpino 		    "failed: %s", strerror(errno));
32873556491SAnthony Scarpino 		goto verifycleanup;
32973556491SAnthony Scarpino 	}
33073556491SAnthony Scarpino 
33173556491SAnthony Scarpino 	if (fips140 == B_TRUE)
33273556491SAnthony Scarpino 		kda->da_version = KCFD_FIPS140_INTCHECK;
33373556491SAnthony Scarpino 	else {
33473556491SAnthony Scarpino 		kda->da_version = KCF_KCFD_VERSION1;
33573556491SAnthony Scarpino 		(void) strlcpy(kda->da_u.filename, fullpath,
33673556491SAnthony Scarpino 		    strlen(fullpath) + 1);
33773556491SAnthony Scarpino 	}
33873556491SAnthony Scarpino 
33973556491SAnthony Scarpino 	kda->da_iskernel = B_FALSE;
34073556491SAnthony Scarpino 
34173556491SAnthony Scarpino 	darg.data_ptr = (char *)kda;
34273556491SAnthony Scarpino 	darg.data_size = sizeof (kcf_door_arg_t);
34373556491SAnthony Scarpino 	darg.desc_ptr = NULL;
34473556491SAnthony Scarpino 	darg.desc_num = 0;
34573556491SAnthony Scarpino 	darg.rbuf = (char *)kda;
34673556491SAnthony Scarpino 	darg.rsize = sizeof (kcf_door_arg_t);
34773556491SAnthony Scarpino 
34873556491SAnthony Scarpino 	while ((r = door_call(kcfdfd, &darg)) != 0) {
34973556491SAnthony Scarpino 		/* save errno and test for certain errors */
35073556491SAnthony Scarpino 		door_errno = errno;
35173556491SAnthony Scarpino 		if (door_errno == EINTR || door_errno == EAGAIN)
35273556491SAnthony Scarpino 			continue;
35373556491SAnthony Scarpino 		/* if disabled or maintenance mode - bail */
35473556491SAnthony Scarpino 		if (cryptosvc_is_down())
35573556491SAnthony Scarpino 			break;
35673556491SAnthony Scarpino 		/* exceeded our number of tries? */
35773556491SAnthony Scarpino 		if (is_cryptosvc_up_count > MAX_CRYPTOSVC_ONLINE_TRIES)
35873556491SAnthony Scarpino 			break;
35973556491SAnthony Scarpino 			/* if stale door_handle, retry the open */
36073556491SAnthony Scarpino 		if (door_errno == EBADF) {
36173556491SAnthony Scarpino 			try_door_open_again = B_TRUE;
36273556491SAnthony Scarpino 			is_cryptosvc_up_count++;
36373556491SAnthony Scarpino 			(void) sleep(5);
36473556491SAnthony Scarpino 			goto verifycleanup;
36573556491SAnthony Scarpino 		} else
36673556491SAnthony Scarpino 			break;
36773556491SAnthony Scarpino 		}
36873556491SAnthony Scarpino 
36973556491SAnthony Scarpino 	if (r != 0) {
37073556491SAnthony Scarpino 		if (!cryptosvc_is_online()) {
37173556491SAnthony Scarpino 			cryptoerror(LOG_ERR, "%s is not online "
37273556491SAnthony Scarpino 			    " - unable to utilize cryptographic "
37373556491SAnthony Scarpino 			    "services.  (see svcs -xv for details).",
37473556491SAnthony Scarpino 			    CRYPTOSVC_DEFAULT_INSTANCE_FMRI);
37573556491SAnthony Scarpino 		} else {
37673556491SAnthony Scarpino 			cryptoerror(LOG_ERR, "libpkcs11: door_call "
37773556491SAnthony Scarpino 			    "of door_file %s failed with error %s.",
37873556491SAnthony Scarpino 			    _PATH_KCFD_DOOR, strerror(door_errno));
37973556491SAnthony Scarpino 		}
38073556491SAnthony Scarpino 		*rv = CKR_CRYPTOKI_NOT_INITIALIZED;
3814ff712c4SValerie Bubb Fenwick 		estatus = ELFSIGN_UNAVAILABLE;
38273556491SAnthony Scarpino 		goto verifycleanup;
38373556491SAnthony Scarpino 	}
38473556491SAnthony Scarpino 
38573556491SAnthony Scarpino 	/*LINTED*/
38673556491SAnthony Scarpino 	rkda = (kcf_door_arg_t *)darg.rbuf;
38773556491SAnthony Scarpino 	if ((fips140 == B_FALSE && rkda->da_version != KCF_KCFD_VERSION1) ||
38873556491SAnthony Scarpino 	    (fips140 == B_TRUE && rkda->da_version != KCFD_FIPS140_INTCHECK)) {
38973556491SAnthony Scarpino 		cryptoerror(LOG_ERR,
39073556491SAnthony Scarpino 		    "libpkcs11: kcfd and libelfsign versions "
39173556491SAnthony Scarpino 		    "don't match: got %d expected %d", rkda->da_version,
39273556491SAnthony Scarpino 		    (fips140) ? KCFD_FIPS140_INTCHECK : KCF_KCFD_VERSION1);
39373556491SAnthony Scarpino 		goto verifycleanup;
39473556491SAnthony Scarpino 	}
39573556491SAnthony Scarpino 	estatus = rkda->da_u.result.status;
39673556491SAnthony Scarpino verifycleanup:
39773556491SAnthony Scarpino 	if (kcfdfd != -1) {
39873556491SAnthony Scarpino 		(void) close(kcfdfd);
39973556491SAnthony Scarpino 	}
40073556491SAnthony Scarpino 	if (rkda != NULL && rkda != kda)
40173556491SAnthony Scarpino 		(void) munmap((char *)rkda, darg.rsize);
40273556491SAnthony Scarpino 	if (kda != NULL) {
40373556491SAnthony Scarpino 		bzero(kda, sizeof (kda));
40473556491SAnthony Scarpino 		free(kda);
40573556491SAnthony Scarpino 		kda = NULL;
40673556491SAnthony Scarpino 		rkda = NULL;	/* rkda is an alias of kda */
40773556491SAnthony Scarpino 	}
40873556491SAnthony Scarpino 	if (try_door_open_again) {
40973556491SAnthony Scarpino 		try_door_open_again = B_FALSE;
41073556491SAnthony Scarpino 		goto open_door_file;
41173556491SAnthony Scarpino 	}
41273556491SAnthony Scarpino 
41373556491SAnthony Scarpino 	return (estatus);
41473556491SAnthony Scarpino }
41573556491SAnthony Scarpino 
41673556491SAnthony Scarpino 
4177c478bd9Sstevel@tonic-gate /*
4187c478bd9Sstevel@tonic-gate  * For each provider found in pkcs11.conf: expand $ISA if necessary,
4197c478bd9Sstevel@tonic-gate  * verify the module is signed, load the provider, find all of its
4207c478bd9Sstevel@tonic-gate  * slots, and store the function list and disabled policy.
4217c478bd9Sstevel@tonic-gate  *
4227c478bd9Sstevel@tonic-gate  * This function requires that the uentrylist_t and pkcs11_slottable_t
4237c478bd9Sstevel@tonic-gate  * already have memory allocated, and that the uentrylist_t is already
4247c478bd9Sstevel@tonic-gate  * populated with provider and policy information.
4257c478bd9Sstevel@tonic-gate  *
4267c478bd9Sstevel@tonic-gate  * pInitArgs can be set to NULL, but is normally the same value
4277c478bd9Sstevel@tonic-gate  * the framework's C_Initialize() was called with.
4287c478bd9Sstevel@tonic-gate  *
4297c478bd9Sstevel@tonic-gate  * Unless metaslot is explicitly disabled, it is setup when all other
4307c478bd9Sstevel@tonic-gate  * providers are loaded.
4317c478bd9Sstevel@tonic-gate  */
4327c478bd9Sstevel@tonic-gate CK_RV
4337c478bd9Sstevel@tonic-gate pkcs11_slot_mapping(uentrylist_t *pplist, CK_VOID_PTR pInitArgs)
4347c478bd9Sstevel@tonic-gate {
4357c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
4367c478bd9Sstevel@tonic-gate 	CK_RV prov_rv;			/* Provider's return code */
4377c478bd9Sstevel@tonic-gate 	CK_INFO prov_info;
4387c478bd9Sstevel@tonic-gate 	CK_RV (*Tmp_C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR);
4397c478bd9Sstevel@tonic-gate 	CK_FUNCTION_LIST_PTR prov_funcs = NULL; /* Provider's function list */
4407c478bd9Sstevel@tonic-gate 	CK_ULONG prov_slot_count; 		/* Number of slots */
4417c478bd9Sstevel@tonic-gate 	CK_SLOT_ID slot_id; 		/* slotID assigned for framework */
4427c478bd9Sstevel@tonic-gate 	CK_SLOT_ID_PTR prov_slots = NULL; 	/* Provider's slot list */
4437c478bd9Sstevel@tonic-gate 					/* Enabled or Disabled policy */
4447c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE_PTR prov_pol_mechs = NULL;
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	void *dldesc = NULL;
4477c478bd9Sstevel@tonic-gate 	char *isa, *fullpath = NULL, *dl_error;
4487c478bd9Sstevel@tonic-gate 	uentrylist_t *phead;
4497c478bd9Sstevel@tonic-gate 	uint_t prov_count = 0;
4507c478bd9Sstevel@tonic-gate 	pkcs11_slot_t *cur_slot;
4517c478bd9Sstevel@tonic-gate 	CK_ULONG i;
4527c478bd9Sstevel@tonic-gate 	size_t len;
4537c478bd9Sstevel@tonic-gate 	uentry_t *metaslot_entry = NULL;
4547c478bd9Sstevel@tonic-gate 	/* number of slots in the framework, not including metaslot */
4557c478bd9Sstevel@tonic-gate 	uint_t slot_count = 0;
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	ELFsign_status_t estatus = ELFSIGN_UNKNOWN;
4587c478bd9Sstevel@tonic-gate 	char *estatus_str = NULL;
45973556491SAnthony Scarpino 	int fips140_mode = CRYPTO_FIPS_MODE_DISABLED;
46073556491SAnthony Scarpino 
46173556491SAnthony Scarpino 	/* Check FIPS 140 configuration and execute check if enabled */
46273556491SAnthony Scarpino 	(void) get_fips_mode(&fips140_mode);
46373556491SAnthony Scarpino 	if (fips140_mode) {
46473556491SAnthony Scarpino 		estatus = kcfd_door_call(NULL, B_TRUE, &rv);
46573556491SAnthony Scarpino 		if (estatus != ELFSIGN_SUCCESS) {
46673556491SAnthony Scarpino 			cryptoerror(LOG_ERR, "libpkcs11: failed FIPS 140 "
46773556491SAnthony Scarpino 			    "integrity check.");
46873556491SAnthony Scarpino 			return (CKR_GENERAL_ERROR);
46973556491SAnthony Scarpino 		}
47073556491SAnthony Scarpino 	}
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	phead = pplist;
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	/* Loop through all of the provider listed in pkcs11.conf */
4757c478bd9Sstevel@tonic-gate 	while (phead != NULL) {
4767c478bd9Sstevel@tonic-gate 		if (!strcasecmp(phead->puent->name, "metaslot")) {
4777c478bd9Sstevel@tonic-gate 			/*
4787c478bd9Sstevel@tonic-gate 			 * Skip standard processing for metaslot
4797c478bd9Sstevel@tonic-gate 			 * entry since it is not an actual library
4807c478bd9Sstevel@tonic-gate 			 * that can be dlopened.
4817c478bd9Sstevel@tonic-gate 			 * It will be initialized later.
4827c478bd9Sstevel@tonic-gate 			 */
4837c478bd9Sstevel@tonic-gate 			if (metaslot_entry != NULL) {
4847c478bd9Sstevel@tonic-gate 				cryptoerror(LOG_ERR,
4857c478bd9Sstevel@tonic-gate 				    "libpkcs11: multiple entries for metaslot "
4867c478bd9Sstevel@tonic-gate 				    "detected.  All but the first entry will "
4877c478bd9Sstevel@tonic-gate 				    "be ignored");
4887c478bd9Sstevel@tonic-gate 			} else {
4897c478bd9Sstevel@tonic-gate 				metaslot_entry = phead->puent;
4907c478bd9Sstevel@tonic-gate 			}
4917c478bd9Sstevel@tonic-gate 			goto contparse;
4927c478bd9Sstevel@tonic-gate 		}
4937c478bd9Sstevel@tonic-gate 
494d616ad8eSHai-May Chao 		if (!strcasecmp(phead->puent->name, FIPS_KEYWORD)) {
495d616ad8eSHai-May Chao 			/*
496d616ad8eSHai-May Chao 			 * Skip standard processing for fips-140
497d616ad8eSHai-May Chao 			 * entry since it is not an actual library
498d616ad8eSHai-May Chao 			 * that can be dlopened.
499d616ad8eSHai-May Chao 			 */
500d616ad8eSHai-May Chao 			goto contparse;
501d616ad8eSHai-May Chao 		}
502d616ad8eSHai-May Chao 
5037c478bd9Sstevel@tonic-gate 		/* Check for Instruction Set Architecture indicator */
5047c478bd9Sstevel@tonic-gate 		if ((isa = strstr(phead->puent->name, PKCS11_ISA)) != NULL) {
5057c478bd9Sstevel@tonic-gate 			/* Substitute the architecture dependent path */
5067c478bd9Sstevel@tonic-gate 			len = strlen(phead->puent->name) -
5077c478bd9Sstevel@tonic-gate 			    strlen(PKCS11_ISA) +
5087c478bd9Sstevel@tonic-gate 			    strlen(PKCS11_ISA_DIR) + 1;
5097c478bd9Sstevel@tonic-gate 			if ((fullpath = (char *)malloc(len)) == NULL) {
5107c478bd9Sstevel@tonic-gate 				cryptoerror(LOG_ERR,
5117c478bd9Sstevel@tonic-gate 				    "libpksc11: parsing %s, out of memory. "
5127c478bd9Sstevel@tonic-gate 				    "Cannot continue parsing.",
5137c478bd9Sstevel@tonic-gate 				    _PATH_PKCS11_CONF);
5147c478bd9Sstevel@tonic-gate 				rv = CKR_HOST_MEMORY;
5157c478bd9Sstevel@tonic-gate 				goto conferror;
5167c478bd9Sstevel@tonic-gate 			}
5177c478bd9Sstevel@tonic-gate 			*isa = '\000';
5187c478bd9Sstevel@tonic-gate 			isa += strlen(PKCS11_ISA);
5197c478bd9Sstevel@tonic-gate 			(void) snprintf(fullpath, len, "%s%s%s",
5207c478bd9Sstevel@tonic-gate 			    phead->puent->name, PKCS11_ISA_DIR, isa);
5217c478bd9Sstevel@tonic-gate 		} else if ((fullpath = strdup(phead->puent->name)) == 0) {
5227c478bd9Sstevel@tonic-gate 			cryptoerror(LOG_ERR,
5237c478bd9Sstevel@tonic-gate 			    "libpkcs11: parsing %s, out of memory. "
5247c478bd9Sstevel@tonic-gate 			    "Cannot continue parsing.",
5257c478bd9Sstevel@tonic-gate 			    _PATH_PKCS11_CONF);
5267c478bd9Sstevel@tonic-gate 			rv = CKR_HOST_MEMORY;
5277c478bd9Sstevel@tonic-gate 			goto conferror;
5287c478bd9Sstevel@tonic-gate 		}
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 		/*
5317c478bd9Sstevel@tonic-gate 		 * Open the provider. Use RTLD_NOW to make sure we
5327c478bd9Sstevel@tonic-gate 		 * will not encounter symbol referencing errors later.
5337c478bd9Sstevel@tonic-gate 		 * Use RTLD_GROUP to limit the provider to it's own
5347c478bd9Sstevel@tonic-gate 		 * symbols, which prevents it from mistakenly accessing
5357c478bd9Sstevel@tonic-gate 		 * the framework's C_* functions.
5367c478bd9Sstevel@tonic-gate 		 */
5377c478bd9Sstevel@tonic-gate 		dldesc = dlopen(fullpath, RTLD_NOW|RTLD_GROUP);
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 		/*
5407c478bd9Sstevel@tonic-gate 		 * If we failed to load it, we will just skip this
5417c478bd9Sstevel@tonic-gate 		 * provider and move on to the next one.
5427c478bd9Sstevel@tonic-gate 		 */
5437c478bd9Sstevel@tonic-gate 		if (dldesc == NULL) {
5447c478bd9Sstevel@tonic-gate 			dl_error = dlerror();
5457c478bd9Sstevel@tonic-gate 			cryptoerror(LOG_ERR,
5467c478bd9Sstevel@tonic-gate 			    "libpkcs11: Cannot load PKCS#11 library %s.  "
5477c478bd9Sstevel@tonic-gate 			    "dlerror: %s. %s",
5487c478bd9Sstevel@tonic-gate 			    fullpath, dl_error != NULL ? dl_error : "Unknown",
5497c478bd9Sstevel@tonic-gate 			    conf_err);
5507c478bd9Sstevel@tonic-gate 			goto contparse;
5517c478bd9Sstevel@tonic-gate 		}
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 		/* Get the pointer to provider's C_GetFunctionList() */
5547c478bd9Sstevel@tonic-gate 		Tmp_C_GetFunctionList =
5557c478bd9Sstevel@tonic-gate 		    (CK_RV(*)())dlsym(dldesc, "C_GetFunctionList");
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 		/*
5587c478bd9Sstevel@tonic-gate 		 * If we failed to get the pointer to C_GetFunctionList(),
5597c478bd9Sstevel@tonic-gate 		 * skip this provider and continue to the next one.
5607c478bd9Sstevel@tonic-gate 		 */
5617c478bd9Sstevel@tonic-gate 		if (Tmp_C_GetFunctionList == NULL) {
5627c478bd9Sstevel@tonic-gate 			cryptoerror(LOG_ERR,
5637c478bd9Sstevel@tonic-gate 			    "libpkcs11: Could not dlsym() C_GetFunctionList() "
5647c478bd9Sstevel@tonic-gate 			    "for %s. May not be a PKCS#11 library. %s",
5657c478bd9Sstevel@tonic-gate 			    fullpath, conf_err);
5667c478bd9Sstevel@tonic-gate 			(void) dlclose(dldesc);
5677c478bd9Sstevel@tonic-gate 			goto contparse;
5687c478bd9Sstevel@tonic-gate 		}
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 		/* Get the provider's function list */
5727c478bd9Sstevel@tonic-gate 		prov_rv = Tmp_C_GetFunctionList(&prov_funcs);
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 		/*
5757c478bd9Sstevel@tonic-gate 		 * If we failed to get the provider's function list,
5767c478bd9Sstevel@tonic-gate 		 * skip this provider and continue to the next one.
5777c478bd9Sstevel@tonic-gate 		 */
5787c478bd9Sstevel@tonic-gate 		if (prov_rv != CKR_OK) {
5797c478bd9Sstevel@tonic-gate 			cryptoerror(LOG_ERR,
5807c478bd9Sstevel@tonic-gate 			    "libpkcs11: Could not get function list for %s. "
5817c478bd9Sstevel@tonic-gate 			    "%s Error: %s.",
5827c478bd9Sstevel@tonic-gate 			    fullpath, conf_err, pkcs11_strerror(prov_rv));
5837c478bd9Sstevel@tonic-gate 			(void) dlclose(dldesc);
5847c478bd9Sstevel@tonic-gate 			goto contparse;
5857c478bd9Sstevel@tonic-gate 		}
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 		/* Initialize this provider */
5887c478bd9Sstevel@tonic-gate 		prov_rv = prov_funcs->C_Initialize(pInitArgs);
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 		/*
5917c478bd9Sstevel@tonic-gate 		 * If we failed to initialize this provider,
5927c478bd9Sstevel@tonic-gate 		 * skip this provider and continue to the next one.
5937c478bd9Sstevel@tonic-gate 		 */
5947c478bd9Sstevel@tonic-gate 		if ((prov_rv != CKR_OK) &&
5957c478bd9Sstevel@tonic-gate 		    (prov_rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) {
5967c478bd9Sstevel@tonic-gate 			cryptoerror(LOG_ERR,
5977c478bd9Sstevel@tonic-gate 			    "libpkcs11: Could not initialize %s. "
5987c478bd9Sstevel@tonic-gate 			    "%s Error: %s.",
5997c478bd9Sstevel@tonic-gate 			    fullpath, conf_err, pkcs11_strerror(prov_rv));
6007c478bd9Sstevel@tonic-gate 			(void) dlclose(dldesc);
6017c478bd9Sstevel@tonic-gate 			goto contparse;
6027c478bd9Sstevel@tonic-gate 		}
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 		/*
6057c478bd9Sstevel@tonic-gate 		 * Make sure this provider is implementing the same
6067c478bd9Sstevel@tonic-gate 		 * major version, and at least the same minor version
6077c478bd9Sstevel@tonic-gate 		 * that we are.
6087c478bd9Sstevel@tonic-gate 		 */
6097c478bd9Sstevel@tonic-gate 		prov_rv = prov_funcs->C_GetInfo(&prov_info);
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 		/*
6127c478bd9Sstevel@tonic-gate 		 * If we can't verify that we are implementing the
6137c478bd9Sstevel@tonic-gate 		 * same major version, or if it is definitely not the same
6147c478bd9Sstevel@tonic-gate 		 * version, we need to skip this provider.
6157c478bd9Sstevel@tonic-gate 		 */
6167c478bd9Sstevel@tonic-gate 		if ((prov_rv != CKR_OK) ||
6177c478bd9Sstevel@tonic-gate 		    (prov_info.cryptokiVersion.major !=
6184a5b2e70Shaimay 		    CRYPTOKI_VERSION_MAJOR))  {
6197c478bd9Sstevel@tonic-gate 			if (prov_rv != CKR_OK) {
6207c478bd9Sstevel@tonic-gate 				cryptoerror(LOG_ERR,
6217c478bd9Sstevel@tonic-gate 				    "libpkcs11: Could not verify version of "
6227c478bd9Sstevel@tonic-gate 				    "%s. %s Error: %s.", fullpath,
6237c478bd9Sstevel@tonic-gate 				    conf_err, pkcs11_strerror(prov_rv));
6247c478bd9Sstevel@tonic-gate 			} else {
6257c478bd9Sstevel@tonic-gate 				cryptoerror(LOG_ERR,
6267c478bd9Sstevel@tonic-gate 				    "libpkcs11: Only CRYPTOKI major version "
6277c478bd9Sstevel@tonic-gate 				    "%d is supported.  %s is major "
6287c478bd9Sstevel@tonic-gate 				    "version %d. %s",
6297c478bd9Sstevel@tonic-gate 				    CRYPTOKI_VERSION_MAJOR, fullpath,
6307c478bd9Sstevel@tonic-gate 				    prov_info.cryptokiVersion.major, conf_err);
6317c478bd9Sstevel@tonic-gate 			}
6327c478bd9Sstevel@tonic-gate 			(void) prov_funcs->C_Finalize(NULL);
6337c478bd9Sstevel@tonic-gate 			(void) dlclose(dldesc);
6347c478bd9Sstevel@tonic-gate 			goto contparse;
6357c478bd9Sstevel@tonic-gate 		}
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 		/*
638e39dcb66Sdarrenm 		 * Warn the administrator (at debug) that a provider with
6397c478bd9Sstevel@tonic-gate 		 * a significantly older or newer version of
6407c478bd9Sstevel@tonic-gate 		 * CRYPTOKI is being used.  It should not cause
6417c478bd9Sstevel@tonic-gate 		 * problems, but logging a warning makes it easier
6427c478bd9Sstevel@tonic-gate 		 * to debug later.
6437c478bd9Sstevel@tonic-gate 		 */
6447c478bd9Sstevel@tonic-gate 		if ((prov_info.cryptokiVersion.minor <
6454a5b2e70Shaimay 		    CRYPTOKI_VERSION_WARN_MINOR) ||
6467c478bd9Sstevel@tonic-gate 		    (prov_info.cryptokiVersion.minor >
6474a5b2e70Shaimay 		    CRYPTOKI_VERSION_MINOR)) {
648e39dcb66Sdarrenm 			cryptoerror(LOG_DEBUG,
6497c478bd9Sstevel@tonic-gate 			    "libpkcs11: %s CRYPTOKI minor version, %d, may "
6507c478bd9Sstevel@tonic-gate 			    "not be compatible with minor version %d.",
6517c478bd9Sstevel@tonic-gate 			    fullpath, prov_info.cryptokiVersion.minor,
6527c478bd9Sstevel@tonic-gate 			    CRYPTOKI_VERSION_MINOR);
6537c478bd9Sstevel@tonic-gate 		}
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 		/*
6567c478bd9Sstevel@tonic-gate 		 * Find out how many slots this provider has,
6577c478bd9Sstevel@tonic-gate 		 * call with tokenPresent set to FALSE so all
6587c478bd9Sstevel@tonic-gate 		 * potential slots are returned.
6597c478bd9Sstevel@tonic-gate 		 */
6607c478bd9Sstevel@tonic-gate 		prov_rv = prov_funcs->C_GetSlotList(FALSE,
6617c478bd9Sstevel@tonic-gate 		    NULL, &prov_slot_count);
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 		/*
6647c478bd9Sstevel@tonic-gate 		 * If the call failed, or if no slots are returned,
6657c478bd9Sstevel@tonic-gate 		 * then skip this provider and continue to next one.
6667c478bd9Sstevel@tonic-gate 		 */
6677c478bd9Sstevel@tonic-gate 		if (prov_rv != CKR_OK) {
6687c478bd9Sstevel@tonic-gate 			cryptoerror(LOG_ERR,
6697c478bd9Sstevel@tonic-gate 			    "libpksc11: Could not get slot list from %s. "
6707c478bd9Sstevel@tonic-gate 			    "%s Error: %s.",
6717c478bd9Sstevel@tonic-gate 			    fullpath, conf_err, pkcs11_strerror(prov_rv));
6727c478bd9Sstevel@tonic-gate 			(void) prov_funcs->C_Finalize(NULL);
6737c478bd9Sstevel@tonic-gate 			(void) dlclose(dldesc);
6747c478bd9Sstevel@tonic-gate 			goto contparse;
6757c478bd9Sstevel@tonic-gate 		}
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 		if (prov_slot_count == 0) {
6787c478bd9Sstevel@tonic-gate 			cryptodebug("libpkcs11: No slots presented from %s. "
6797c478bd9Sstevel@tonic-gate 			    "Skipping this plug-in at this time.\n",
6807c478bd9Sstevel@tonic-gate 			    fullpath);
6817c478bd9Sstevel@tonic-gate 			(void) prov_funcs->C_Finalize(NULL);
6827c478bd9Sstevel@tonic-gate 			(void) dlclose(dldesc);
6837c478bd9Sstevel@tonic-gate 			goto contparse;
6847c478bd9Sstevel@tonic-gate 		}
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 		/*
6877c478bd9Sstevel@tonic-gate 		 * Verify that the module is signed correctly.
6887c478bd9Sstevel@tonic-gate 		 *
6897c478bd9Sstevel@tonic-gate 		 * NOTE: there is a potential race condition here,
6907c478bd9Sstevel@tonic-gate 		 * since the module is verified well after we have
6917c478bd9Sstevel@tonic-gate 		 * opened the provider via dlopen().  This could be
6927c478bd9Sstevel@tonic-gate 		 * resolved by a variant of dlopen() that would take a
6937c478bd9Sstevel@tonic-gate 		 * file descriptor as an argument and by changing the
6947c478bd9Sstevel@tonic-gate 		 * kcfd libelfsign door protocol to use and fd instead
6957c478bd9Sstevel@tonic-gate 		 * of a path - but that wouldn't work in the kernel case.
6967c478bd9Sstevel@tonic-gate 		 */
69773556491SAnthony Scarpino 		estatus = kcfd_door_call(fullpath, B_FALSE, &rv);
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 		switch (estatus) {
7007c478bd9Sstevel@tonic-gate 		case ELFSIGN_SUCCESS:
7017c478bd9Sstevel@tonic-gate 		case ELFSIGN_RESTRICTED:
7027c478bd9Sstevel@tonic-gate 			break;
7037c478bd9Sstevel@tonic-gate 		case ELFSIGN_NOTSIGNED:
704*fb99bed9SValerie Bubb Fenwick 			estatus_str = "not a signed provider.";
7057c478bd9Sstevel@tonic-gate 			break;
7067c478bd9Sstevel@tonic-gate 		case ELFSIGN_FAILED:
707*fb99bed9SValerie Bubb Fenwick 			estatus_str = "signature verification failed.";
7087c478bd9Sstevel@tonic-gate 			break;
7094ff712c4SValerie Bubb Fenwick 		case ELFSIGN_UNAVAILABLE:
710*fb99bed9SValerie Bubb Fenwick 			estatus_str = "kcfd(1m) is not available for "
7114ff712c4SValerie Bubb Fenwick 			    "signature verification. Cannot continue loading "
712*fb99bed9SValerie Bubb Fenwick 			    "the cryptographic framework.";
7134ff712c4SValerie Bubb Fenwick 			break;
7147c478bd9Sstevel@tonic-gate 		default:
715*fb99bed9SValerie Bubb Fenwick 			estatus_str = "unexpected failure in ELF "
716*fb99bed9SValerie Bubb Fenwick 			    "signature verification.";
7177c478bd9Sstevel@tonic-gate 		}
7187c478bd9Sstevel@tonic-gate 		if (estatus_str != NULL) {
719*fb99bed9SValerie Bubb Fenwick 			if (estatus != ELFSIGN_UNAVAILABLE) {
720*fb99bed9SValerie Bubb Fenwick 				cryptoerror(LOG_ERR, "libpkcs11: %s %s %s",
721*fb99bed9SValerie Bubb Fenwick 				    fullpath, estatus_str,
722*fb99bed9SValerie Bubb Fenwick 				    estatus == ELFSIGN_UNKNOWN ?
723*fb99bed9SValerie Bubb Fenwick 				    "See cryptoadm (1M). "
724*fb99bed9SValerie Bubb Fenwick 				    "Cannot continue parsing "
725*fb99bed9SValerie Bubb Fenwick 				    _PATH_PKCS11_CONF : conf_err);
726*fb99bed9SValerie Bubb Fenwick 			} else {
727*fb99bed9SValerie Bubb Fenwick 				cryptoerror(LOG_ERR, "libpkcs11: %s",
728*fb99bed9SValerie Bubb Fenwick 				    estatus_str);
729*fb99bed9SValerie Bubb Fenwick 			}
730*fb99bed9SValerie Bubb Fenwick 
7317c478bd9Sstevel@tonic-gate 			(void) prov_funcs->C_Finalize(NULL);
7327c478bd9Sstevel@tonic-gate 			(void) dlclose(dldesc);
7337c478bd9Sstevel@tonic-gate 			estatus_str = NULL;
7344ff712c4SValerie Bubb Fenwick 			if (estatus == ELFSIGN_UNKNOWN ||
7354ff712c4SValerie Bubb Fenwick 			    estatus == ELFSIGN_UNAVAILABLE) {
7367c478bd9Sstevel@tonic-gate 				prov_funcs = NULL;
7377c478bd9Sstevel@tonic-gate 				dldesc = NULL;
7387c478bd9Sstevel@tonic-gate 				rv = CKR_GENERAL_ERROR;
7397c478bd9Sstevel@tonic-gate 				goto conferror;
7407c478bd9Sstevel@tonic-gate 			}
7417c478bd9Sstevel@tonic-gate 			goto contparse;
7427c478bd9Sstevel@tonic-gate 		}
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 		/* Allocate memory for the slot list */
7457c478bd9Sstevel@tonic-gate 		prov_slots = calloc(prov_slot_count, sizeof (CK_SLOT_ID));
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 		if (prov_slots == NULL) {
7487c478bd9Sstevel@tonic-gate 			cryptoerror(LOG_ERR,
7497c478bd9Sstevel@tonic-gate 			    "libpkcs11: Could not allocate memory for "
7507c478bd9Sstevel@tonic-gate 			    "plug-in slots. Cannot continue parsing %s\n",
7517c478bd9Sstevel@tonic-gate 			    _PATH_PKCS11_CONF);
7527c478bd9Sstevel@tonic-gate 			rv = CKR_HOST_MEMORY;
7537c478bd9Sstevel@tonic-gate 			goto conferror;
7547c478bd9Sstevel@tonic-gate 		}
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 		/* Get slot list from provider */
7577c478bd9Sstevel@tonic-gate 		prov_rv = prov_funcs->C_GetSlotList(FALSE,
7587c478bd9Sstevel@tonic-gate 		    prov_slots, &prov_slot_count);
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 		/* if second call fails, drop this provider */
7617c478bd9Sstevel@tonic-gate 		if (prov_rv != CKR_OK) {
7627c478bd9Sstevel@tonic-gate 			cryptoerror(LOG_ERR,
7637c478bd9Sstevel@tonic-gate 			    "libpkcs11: Second call to C_GetSlotList() for %s "
7647c478bd9Sstevel@tonic-gate 			    "failed. %s Error: %s.",
7657c478bd9Sstevel@tonic-gate 			    fullpath, conf_err, pkcs11_strerror(prov_rv));
7667c478bd9Sstevel@tonic-gate 			(void) prov_funcs->C_Finalize(NULL);
7677c478bd9Sstevel@tonic-gate 			(void) dlclose(dldesc);
7687c478bd9Sstevel@tonic-gate 			goto contparse;
7697c478bd9Sstevel@tonic-gate 		}
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 		/*
7727c478bd9Sstevel@tonic-gate 		 * Parse the list of disabled or enabled mechanisms, will
7737c478bd9Sstevel@tonic-gate 		 * apply to each of the provider's slots.
7747c478bd9Sstevel@tonic-gate 		 */
7757c478bd9Sstevel@tonic-gate 		if (phead->puent->count > 0) {
7767c478bd9Sstevel@tonic-gate 			rv = pkcs11_mech_parse(phead->puent->policylist,
7777c478bd9Sstevel@tonic-gate 			    &prov_pol_mechs, phead->puent->count);
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 			if (rv == CKR_HOST_MEMORY) {
7807c478bd9Sstevel@tonic-gate 				cryptoerror(LOG_ERR,
7817c478bd9Sstevel@tonic-gate 				    "libpkcs11: Could not parse configuration,"
7827c478bd9Sstevel@tonic-gate 				    "out of memory. Cannot continue parsing "
7837c478bd9Sstevel@tonic-gate 				    "%s.", _PATH_PKCS11_CONF);
7847c478bd9Sstevel@tonic-gate 				goto conferror;
7857c478bd9Sstevel@tonic-gate 			} else if (rv == CKR_MECHANISM_INVALID) {
7867c478bd9Sstevel@tonic-gate 				/*
7877c478bd9Sstevel@tonic-gate 				 * Configuration file is corrupted for this
7887c478bd9Sstevel@tonic-gate 				 * provider.
7897c478bd9Sstevel@tonic-gate 				 */
7907c478bd9Sstevel@tonic-gate 				cryptoerror(LOG_ERR,
7917c478bd9Sstevel@tonic-gate 				    "libpkcs11: Policy invalid or corrupted "
7927c478bd9Sstevel@tonic-gate 				    "for %s. Use cryptoadm(1M) to fix "
7937c478bd9Sstevel@tonic-gate 				    "this. Skipping this plug-in.",
7947c478bd9Sstevel@tonic-gate 				    fullpath);
7957c478bd9Sstevel@tonic-gate 				(void) prov_funcs->C_Finalize(NULL);
7967c478bd9Sstevel@tonic-gate 				(void) dlclose(dldesc);
7977c478bd9Sstevel@tonic-gate 				goto contparse;
7987c478bd9Sstevel@tonic-gate 			}
7997c478bd9Sstevel@tonic-gate 		}
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 		/* Allocate memory in our slottable for these slots */
8027c478bd9Sstevel@tonic-gate 		rv = pkcs11_slottable_increase(prov_slot_count);
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 		/*
8057c478bd9Sstevel@tonic-gate 		 * If any error is returned, it will be memory related,
8067c478bd9Sstevel@tonic-gate 		 * so we need to abort the attempt at filling the
8077c478bd9Sstevel@tonic-gate 		 * slottable.
8087c478bd9Sstevel@tonic-gate 		 */
8097c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
8107c478bd9Sstevel@tonic-gate 			cryptoerror(LOG_ERR,
8117c478bd9Sstevel@tonic-gate 			    "libpkcs11: slottable could not increase. "
8127c478bd9Sstevel@tonic-gate 			    "Cannot continue parsing %s.",
8137c478bd9Sstevel@tonic-gate 			    _PATH_PKCS11_CONF);
8147c478bd9Sstevel@tonic-gate 			goto conferror;
8157c478bd9Sstevel@tonic-gate 		}
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 		/* Configure information for each new slot */
8187c478bd9Sstevel@tonic-gate 		for (i = 0; i < prov_slot_count; i++) {
8197c478bd9Sstevel@tonic-gate 			/* allocate slot in framework */
8207c478bd9Sstevel@tonic-gate 			rv = pkcs11_slot_allocate(&slot_id);
8217c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
8227c478bd9Sstevel@tonic-gate 				cryptoerror(LOG_ERR,
8237c478bd9Sstevel@tonic-gate 				    "libpkcs11: Could not allocate "
8247c478bd9Sstevel@tonic-gate 				    "new slot.  Cannot continue parsing %s.",
8257c478bd9Sstevel@tonic-gate 				    _PATH_PKCS11_CONF);
8267c478bd9Sstevel@tonic-gate 				goto conferror;
8277c478bd9Sstevel@tonic-gate 			}
8287c478bd9Sstevel@tonic-gate 			slot_count++;
8297c478bd9Sstevel@tonic-gate 			cur_slot = slottable->st_slots[slot_id];
8307c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_lock(&cur_slot->sl_mutex);
8317c478bd9Sstevel@tonic-gate 			cur_slot->sl_id = prov_slots[i];
8327c478bd9Sstevel@tonic-gate 			cur_slot->sl_func_list = prov_funcs;
8337c478bd9Sstevel@tonic-gate 			cur_slot->sl_enabledpol =
8347c478bd9Sstevel@tonic-gate 			    phead->puent->flag_enabledlist;
8357c478bd9Sstevel@tonic-gate 			cur_slot->sl_pol_mechs = prov_pol_mechs;
8367c478bd9Sstevel@tonic-gate 			cur_slot->sl_pol_count = phead->puent->count;
8377c478bd9Sstevel@tonic-gate 			cur_slot->sl_norandom = phead->puent->flag_norandom;
8387c478bd9Sstevel@tonic-gate 			cur_slot->sl_dldesc = dldesc;
8397c478bd9Sstevel@tonic-gate 			cur_slot->sl_prov_id = prov_count + 1;
8407c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
8417c478bd9Sstevel@tonic-gate 		}
8427c478bd9Sstevel@tonic-gate 
8434a5b2e70Shaimay 		/*
8444a5b2e70Shaimay 		 * Get the pointer to private interface _SUNW_GetThreshold()
8454a5b2e70Shaimay 		 * in pkcs11_kernel.
8464a5b2e70Shaimay 		 */
8474a5b2e70Shaimay 
8484a5b2e70Shaimay 		if (Tmp_GetThreshold == NULL) {
8494a5b2e70Shaimay 			Tmp_GetThreshold =
850a039cd31Shaimay 			    (void(*)())dlsym(dldesc, "_SUNW_GetThreshold");
851a039cd31Shaimay 
852a039cd31Shaimay 			/* Get the threshold values for the supported mechs */
853a039cd31Shaimay 			if (Tmp_GetThreshold != NULL) {
854a039cd31Shaimay 				(void) memset(meta_mechs_threshold, 0,
855a039cd31Shaimay 				    sizeof (meta_mechs_threshold));
856a039cd31Shaimay 				Tmp_GetThreshold(meta_mechs_threshold);
857a039cd31Shaimay 			}
8584a5b2e70Shaimay 		}
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 		/* Set and reset values to process next provider */
8617c478bd9Sstevel@tonic-gate 		prov_count++;
8627c478bd9Sstevel@tonic-gate contparse:
8637c478bd9Sstevel@tonic-gate 		prov_slot_count = 0;
8647c478bd9Sstevel@tonic-gate 		Tmp_C_GetFunctionList = NULL;
8657c478bd9Sstevel@tonic-gate 		prov_funcs = NULL;
8667c478bd9Sstevel@tonic-gate 		dldesc = NULL;
8677c478bd9Sstevel@tonic-gate 		if (fullpath != NULL) {
8687c478bd9Sstevel@tonic-gate 			free(fullpath);
8697c478bd9Sstevel@tonic-gate 			fullpath = NULL;
8707c478bd9Sstevel@tonic-gate 		}
8717c478bd9Sstevel@tonic-gate 		if (prov_slots != NULL) {
8727c478bd9Sstevel@tonic-gate 			free(prov_slots);
8737c478bd9Sstevel@tonic-gate 			prov_slots = NULL;
8747c478bd9Sstevel@tonic-gate 		}
8757c478bd9Sstevel@tonic-gate 		phead = phead->next;
8767c478bd9Sstevel@tonic-gate 	}
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	if (slot_count == 0) {
8797c478bd9Sstevel@tonic-gate 		/*
8807c478bd9Sstevel@tonic-gate 		 * there's no other slot in the framework,
8817c478bd9Sstevel@tonic-gate 		 * there is nothing to do
8827c478bd9Sstevel@tonic-gate 		 */
8837c478bd9Sstevel@tonic-gate 		goto config_complete;
8847c478bd9Sstevel@tonic-gate 	}
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 	/* determine if metaslot should be enabled */
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	/*
8897c478bd9Sstevel@tonic-gate 	 * Check to see if any environment variable is defined
8907c478bd9Sstevel@tonic-gate 	 * by the user for configuring metaslot.  Users'
8917c478bd9Sstevel@tonic-gate 	 * setting always take precedence over the system wide
8927c478bd9Sstevel@tonic-gate 	 * setting.  So, we will first check for any user's
8937c478bd9Sstevel@tonic-gate 	 * defined env variables before looking at the system-wide
8947c478bd9Sstevel@tonic-gate 	 * configuration.
8957c478bd9Sstevel@tonic-gate 	 */
8967c478bd9Sstevel@tonic-gate 	get_user_metaslot_config();
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	/* no metaslot entry in /etc/crypto/pkcs11.conf */
8997c478bd9Sstevel@tonic-gate 	if (!metaslot_entry) {
9007c478bd9Sstevel@tonic-gate 		/*
9017c478bd9Sstevel@tonic-gate 		 * If user env variable indicates metaslot should be enabled,
9027c478bd9Sstevel@tonic-gate 		 * but there's no entry in /etc/crypto/pkcs11.conf for
9037c478bd9Sstevel@tonic-gate 		 * metaslot at all, will respect the user's defined value
9047c478bd9Sstevel@tonic-gate 		 */
9057c478bd9Sstevel@tonic-gate 		if ((metaslot_config.enabled_specified) &&
9067c478bd9Sstevel@tonic-gate 		    (metaslot_config.enabled)) {
9077c478bd9Sstevel@tonic-gate 			metaslot_enabled = B_TRUE;
9087c478bd9Sstevel@tonic-gate 		}
9097c478bd9Sstevel@tonic-gate 	} else {
9107c478bd9Sstevel@tonic-gate 		if (!metaslot_config.enabled_specified) {
9117c478bd9Sstevel@tonic-gate 			/*
9127c478bd9Sstevel@tonic-gate 			 * take system wide value if
9137c478bd9Sstevel@tonic-gate 			 * it is not specified by user
9147c478bd9Sstevel@tonic-gate 			 */
9157c478bd9Sstevel@tonic-gate 			metaslot_enabled
9167c478bd9Sstevel@tonic-gate 			    = metaslot_entry->flag_metaslot_enabled;
9177c478bd9Sstevel@tonic-gate 		} else {
9187c478bd9Sstevel@tonic-gate 			metaslot_enabled = metaslot_config.enabled;
9197c478bd9Sstevel@tonic-gate 		}
9207c478bd9Sstevel@tonic-gate 	}
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	/*
9237c478bd9Sstevel@tonic-gate 	 *
9247c478bd9Sstevel@tonic-gate 	 * As long as the user or system configuration file does not
9257c478bd9Sstevel@tonic-gate 	 * disable metaslot, it will be enabled regardless of the
9267c478bd9Sstevel@tonic-gate 	 * number of slots plugged into the framework.  Therefore,
9277c478bd9Sstevel@tonic-gate 	 * metaslot is enabled even when there's only one slot
9287c478bd9Sstevel@tonic-gate 	 * plugged into the framework.  This is necessary for
9297c478bd9Sstevel@tonic-gate 	 * presenting a consistent token label view to applications.
9307c478bd9Sstevel@tonic-gate 	 *
9317c478bd9Sstevel@tonic-gate 	 * However, for the case where there is only 1 slot plugged into
9327c478bd9Sstevel@tonic-gate 	 * the framework, we can use "fastpath".
9337c478bd9Sstevel@tonic-gate 	 *
9347c478bd9Sstevel@tonic-gate 	 * "fastpath" will pass all of the application's requests
9357c478bd9Sstevel@tonic-gate 	 * directly to the underlying provider.  Only when policy is in
9367c478bd9Sstevel@tonic-gate 	 * effect will we need to keep slotID around.
9377c478bd9Sstevel@tonic-gate 	 *
9387c478bd9Sstevel@tonic-gate 	 * When metaslot is enabled, and fastpath is enabled,
9397c478bd9Sstevel@tonic-gate 	 * all the metaslot processing will be skipped.
9407c478bd9Sstevel@tonic-gate 	 * When there is only 1 slot, there's
9417c478bd9Sstevel@tonic-gate 	 * really not much metaslot can do in terms of combining functionality
9427c478bd9Sstevel@tonic-gate 	 * of different slots, and object migration.
9437c478bd9Sstevel@tonic-gate 	 *
9447c478bd9Sstevel@tonic-gate 	 */
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 	/* check to see if fastpath can be used */
9477c478bd9Sstevel@tonic-gate 	if (slottable->st_last == slottable->st_first) {
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 		cur_slot = slottable->st_slots[slottable->st_first];
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&cur_slot->sl_mutex);
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 		if ((cur_slot->sl_pol_count == 0) &&
9547c478bd9Sstevel@tonic-gate 		    (!cur_slot->sl_enabledpol) && (!cur_slot->sl_norandom)) {
9557c478bd9Sstevel@tonic-gate 			/* No policy is in effect, don't need slotid */
9567c478bd9Sstevel@tonic-gate 			fast_funcs = cur_slot->sl_func_list;
9577c478bd9Sstevel@tonic-gate 			purefastpath = B_TRUE;
9587c478bd9Sstevel@tonic-gate 		} else {
9597c478bd9Sstevel@tonic-gate 			fast_funcs = cur_slot->sl_func_list;
9607c478bd9Sstevel@tonic-gate 			fast_slot = slottable->st_first;
9617c478bd9Sstevel@tonic-gate 			policyfastpath = B_TRUE;
9627c478bd9Sstevel@tonic-gate 		}
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
9657c478bd9Sstevel@tonic-gate 	}
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	if ((purefastpath || policyfastpath) && (!metaslot_enabled)) {
9687c478bd9Sstevel@tonic-gate 		goto config_complete;
9697c478bd9Sstevel@tonic-gate 	}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	/*
9727c478bd9Sstevel@tonic-gate 	 * If we get here, there are more than 2 slots in the framework,
9737c478bd9Sstevel@tonic-gate 	 * we need to set up metaslot if it is enabled
9747c478bd9Sstevel@tonic-gate 	 */
9757c478bd9Sstevel@tonic-gate 	if (metaslot_enabled) {
9767c478bd9Sstevel@tonic-gate 		rv = setup_metaslot(metaslot_entry);
9777c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
9787c478bd9Sstevel@tonic-gate 			goto conferror;
9797c478bd9Sstevel@tonic-gate 		}
9807c478bd9Sstevel@tonic-gate 	}
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate config_complete:
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	return (CKR_OK);
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate conferror:
9887c478bd9Sstevel@tonic-gate 	/*
9897c478bd9Sstevel@tonic-gate 	 * This cleanup code is only exercised when a major,
990*fb99bed9SValerie Bubb Fenwick 	 * unrecoverable error like "out of memory" or
991*fb99bed9SValerie Bubb Fenwick 	 * kcfd is not reachable occurs.
9927c478bd9Sstevel@tonic-gate 	 */
9937c478bd9Sstevel@tonic-gate 	if (prov_funcs != NULL) {
9947c478bd9Sstevel@tonic-gate 		(void) prov_funcs->C_Finalize(NULL);
9957c478bd9Sstevel@tonic-gate 	}
9967c478bd9Sstevel@tonic-gate 	if (dldesc != NULL) {
9977c478bd9Sstevel@tonic-gate 		(void) dlclose(dldesc);
9987c478bd9Sstevel@tonic-gate 	}
9997c478bd9Sstevel@tonic-gate 	if (fullpath != NULL) {
10007c478bd9Sstevel@tonic-gate 		free(fullpath);
10017c478bd9Sstevel@tonic-gate 		fullpath = NULL;
10027c478bd9Sstevel@tonic-gate 	}
10037c478bd9Sstevel@tonic-gate 	if (prov_slots != NULL) {
10047c478bd9Sstevel@tonic-gate 		free(prov_slots);
10057c478bd9Sstevel@tonic-gate 		prov_slots = NULL;
10067c478bd9Sstevel@tonic-gate 	}
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 	return (rv);
10097c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate /*
10127c478bd9Sstevel@tonic-gate  * pkcs11_mech_parse will take hex mechanism ids, as a list of
10137c478bd9Sstevel@tonic-gate  * strings, and convert them to CK_MECHANISM_TYPE_PTR.
10147c478bd9Sstevel@tonic-gate  */
10157c478bd9Sstevel@tonic-gate CK_RV
10167c478bd9Sstevel@tonic-gate pkcs11_mech_parse(umechlist_t *str_list, CK_MECHANISM_TYPE_PTR *mech_list,
10177c478bd9Sstevel@tonic-gate     int mech_count)
10187c478bd9Sstevel@tonic-gate {
10197c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE_PTR tmp_list;
10207c478bd9Sstevel@tonic-gate 	umechlist_t *shead = str_list;
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	tmp_list = malloc(mech_count * sizeof (CK_MECHANISM_TYPE));
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	if (tmp_list == NULL) {
10257c478bd9Sstevel@tonic-gate 		cryptoerror(LOG_ERR, "libpkcs11: parsing %s, out of memory. "
10267c478bd9Sstevel@tonic-gate 		    "Cannot continue.",
10277c478bd9Sstevel@tonic-gate 		    _PATH_PKCS11_CONF);
10287c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
10297c478bd9Sstevel@tonic-gate 	}
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 	*mech_list = tmp_list;
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	/*
10347c478bd9Sstevel@tonic-gate 	 * The following will loop mech_count times, as there are
10357c478bd9Sstevel@tonic-gate 	 * exactly mech_count items in the str_list.
10367c478bd9Sstevel@tonic-gate 	 */
10377c478bd9Sstevel@tonic-gate 	while (shead != NULL) {
10387c478bd9Sstevel@tonic-gate 		CK_MECHANISM_TYPE cur_mech;
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 		errno = 0;
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 		/*
10437c478bd9Sstevel@tonic-gate 		 * "name" is a hexadecimal number, preceded by 0x.
10447c478bd9Sstevel@tonic-gate 		 */
10457c478bd9Sstevel@tonic-gate 		cur_mech = strtoul(shead->name, NULL, 16);
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 		if ((cur_mech == 0) &&
10487c478bd9Sstevel@tonic-gate 		    ((errno == EINVAL) || (errno == ERANGE))) {
10497c478bd9Sstevel@tonic-gate 			free(mech_list);
10507c478bd9Sstevel@tonic-gate 			return (CKR_MECHANISM_INVALID);
10517c478bd9Sstevel@tonic-gate 		}
10527c478bd9Sstevel@tonic-gate 		*tmp_list = (CK_MECHANISM_TYPE)cur_mech;
10537c478bd9Sstevel@tonic-gate 		tmp_list++;
10547c478bd9Sstevel@tonic-gate 		shead = shead->next;
10557c478bd9Sstevel@tonic-gate 	}
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	return (CKR_OK);
10587c478bd9Sstevel@tonic-gate }
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate /*
10617c478bd9Sstevel@tonic-gate  * pkcs11_is_dismech is provided a slotid and a mechanism.
10627c478bd9Sstevel@tonic-gate  * If mech is not disabled, then return B_FALSE.
10637c478bd9Sstevel@tonic-gate  */
10647c478bd9Sstevel@tonic-gate boolean_t
10657c478bd9Sstevel@tonic-gate pkcs11_is_dismech(CK_SLOT_ID slotid, CK_MECHANISM_TYPE mech)
10667c478bd9Sstevel@tonic-gate {
10677c478bd9Sstevel@tonic-gate 	ulong_t i;
10687c478bd9Sstevel@tonic-gate 	boolean_t enabled_pol;
10697c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE_PTR pol_mechs;
10707c478bd9Sstevel@tonic-gate 	ulong_t pol_count;
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	/* Find the associated slot and get the mech policy info */
10737c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->st_slots[slotid]->sl_mutex);
10747c478bd9Sstevel@tonic-gate 	enabled_pol = slottable->st_slots[slotid]->sl_enabledpol;
10757c478bd9Sstevel@tonic-gate 	pol_mechs = slottable->st_slots[slotid]->sl_pol_mechs;
10767c478bd9Sstevel@tonic-gate 	pol_count = slottable->st_slots[slotid]->sl_pol_count;
10777c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&slottable->st_slots[slotid]->sl_mutex);
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	/* Check for policy */
10807c478bd9Sstevel@tonic-gate 	if ((!enabled_pol) && (pol_mechs == NULL)) {
10817c478bd9Sstevel@tonic-gate 		/* no policy */
10827c478bd9Sstevel@tonic-gate 		return (B_FALSE);
10837c478bd9Sstevel@tonic-gate 	} else if (pol_mechs == NULL) {
10847c478bd9Sstevel@tonic-gate 		/*
10857c478bd9Sstevel@tonic-gate 		 * We have an empty enabled list, which means no
10867c478bd9Sstevel@tonic-gate 		 * mechanisms are exempted from this policy: all
10877c478bd9Sstevel@tonic-gate 		 * are disabled.
10887c478bd9Sstevel@tonic-gate 		 */
10897c478bd9Sstevel@tonic-gate 		return (B_TRUE);
10907c478bd9Sstevel@tonic-gate 	}
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	for (i = 0; i < pol_count; i++) {
10937c478bd9Sstevel@tonic-gate 		/*
10947c478bd9Sstevel@tonic-gate 		 * If it matches, return status based on this
10957c478bd9Sstevel@tonic-gate 		 * being and enabled or a disabled list of mechs.
10967c478bd9Sstevel@tonic-gate 		 */
10977c478bd9Sstevel@tonic-gate 		if (pol_mechs[i] == mech) {
10987c478bd9Sstevel@tonic-gate 			return (enabled_pol ? B_FALSE : B_TRUE);
10997c478bd9Sstevel@tonic-gate 		}
11007c478bd9Sstevel@tonic-gate 	}
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 	/* mech was not found in list */
11037c478bd9Sstevel@tonic-gate 	return (enabled_pol ? B_TRUE : B_FALSE);
11047c478bd9Sstevel@tonic-gate }
1105