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
56a1073f8Skrishna  * Common Development and Distribution License (the "License").
66a1073f8Skrishna  * 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 /*
2295014fbbSDan OpenSolaris Anderson  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * This file is part of the core Kernel Cryptographic Framework.
287c478bd9Sstevel@tonic-gate  * It implements the management of tables of Providers. Entries to
297c478bd9Sstevel@tonic-gate  * added and removed when cryptographic providers register with
307c478bd9Sstevel@tonic-gate  * and unregister from the framework, respectively. The KCF scheduler
317c478bd9Sstevel@tonic-gate  * and ioctl pseudo driver call this function to obtain the list
327c478bd9Sstevel@tonic-gate  * of available providers.
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * The provider table is indexed by crypto_provider_id_t. Each
357c478bd9Sstevel@tonic-gate  * element of the table contains a pointer to a provider descriptor,
367c478bd9Sstevel@tonic-gate  * or NULL if the entry is free.
377c478bd9Sstevel@tonic-gate  *
387c478bd9Sstevel@tonic-gate  * This file also implements helper functions to allocate and free
397c478bd9Sstevel@tonic-gate  * provider descriptors.
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include <sys/types.h>
437c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
447c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
457c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
467c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
477c478bd9Sstevel@tonic-gate #include <sys/ksynch.h>
487c478bd9Sstevel@tonic-gate #include <sys/crypto/common.h>
497c478bd9Sstevel@tonic-gate #include <sys/crypto/impl.h>
507c478bd9Sstevel@tonic-gate #include <sys/crypto/sched_impl.h>
517c478bd9Sstevel@tonic-gate #include <sys/crypto/spi.h>
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #define	KCF_MAX_PROVIDERS	512	/* max number of providers */
547c478bd9Sstevel@tonic-gate 
551b22764fSDaniel OpenSolaris Anderson /*
561b22764fSDaniel OpenSolaris Anderson  * Prov_tab is an array of providers which is updated when
571b22764fSDaniel OpenSolaris Anderson  * a crypto provider registers with kcf. The provider calls the
581b22764fSDaniel OpenSolaris Anderson  * SPI routine, crypto_register_provider(), which in turn calls
591b22764fSDaniel OpenSolaris Anderson  * kcf_prov_tab_add_provider().
601b22764fSDaniel OpenSolaris Anderson  *
611b22764fSDaniel OpenSolaris Anderson  * A provider unregisters by calling crypto_unregister_provider()
621b22764fSDaniel OpenSolaris Anderson  * which triggers the removal of the prov_tab entry.
631b22764fSDaniel OpenSolaris Anderson  * It also calls kcf_remove_mech_provider().
641b22764fSDaniel OpenSolaris Anderson  *
65*bbf21555SRichard Lowe  * prov_tab entries are not updated from kcf.conf or by cryptoadm(8).
661b22764fSDaniel OpenSolaris Anderson  */
677c478bd9Sstevel@tonic-gate static kcf_provider_desc_t **prov_tab = NULL;
68ef56a3c5SKrishna Yenduri kmutex_t prov_tab_mutex; /* ensure exclusive access to the table */
697c478bd9Sstevel@tonic-gate static uint_t prov_tab_num = 0; /* number of providers in table */
707c478bd9Sstevel@tonic-gate static uint_t prov_tab_max = KCF_MAX_PROVIDERS;
717c478bd9Sstevel@tonic-gate 
727623016fSKrishna Yenduri static void kcf_free_unregistered_provs();
737c478bd9Sstevel@tonic-gate #if DEBUG
747c478bd9Sstevel@tonic-gate extern int kcf_frmwrk_debug;
751b22764fSDaniel OpenSolaris Anderson static void kcf_prov_tab_dump(char *message);
767c478bd9Sstevel@tonic-gate #endif /* DEBUG */
777c478bd9Sstevel@tonic-gate 
781b22764fSDaniel OpenSolaris Anderson 
797c478bd9Sstevel@tonic-gate /*
801b22764fSDaniel OpenSolaris Anderson  * Initialize a mutex and the KCF providers table, prov_tab.
811b22764fSDaniel OpenSolaris Anderson  * The providers table is dynamically allocated with prov_tab_max entries.
821b22764fSDaniel OpenSolaris Anderson  * Called from kcf module _init().
837c478bd9Sstevel@tonic-gate  */
847c478bd9Sstevel@tonic-gate void
kcf_prov_tab_init(void)857c478bd9Sstevel@tonic-gate kcf_prov_tab_init(void)
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate 	mutex_init(&prov_tab_mutex, NULL, MUTEX_DRIVER, NULL);
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	prov_tab = kmem_zalloc(prov_tab_max * sizeof (kcf_provider_desc_t *),
907c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate  * Add a provider to the provider table. If no free entry can be found
957c478bd9Sstevel@tonic-gate  * for the new provider, returns CRYPTO_HOST_MEMORY. Otherwise, add
967c478bd9Sstevel@tonic-gate  * the provider to the table, initialize the pd_prov_id field
977c478bd9Sstevel@tonic-gate  * of the specified provider descriptor to the index in that table,
987c478bd9Sstevel@tonic-gate  * and return CRYPTO_SUCCESS. Note that a REFHOLD is done on the
997c478bd9Sstevel@tonic-gate  * provider when pointed to by a table entry.
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate int
kcf_prov_tab_add_provider(kcf_provider_desc_t * prov_desc)1027c478bd9Sstevel@tonic-gate kcf_prov_tab_add_provider(kcf_provider_desc_t *prov_desc)
1037c478bd9Sstevel@tonic-gate {
1047c478bd9Sstevel@tonic-gate 	uint_t i;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	ASSERT(prov_tab != NULL);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	mutex_enter(&prov_tab_mutex);
1097c478bd9Sstevel@tonic-gate 
1107623016fSKrishna Yenduri 	/* see if any slots can be freed */
1117623016fSKrishna Yenduri 	if (kcf_need_provtab_walk)
1127623016fSKrishna Yenduri 		kcf_free_unregistered_provs();
1137623016fSKrishna Yenduri 
1147c478bd9Sstevel@tonic-gate 	/* find free slot in providers table */
115fe2f7468Skrishna 	for (i = 0; i < KCF_MAX_PROVIDERS && prov_tab[i] != NULL; i++)
116fe2f7468Skrishna 		;
1177c478bd9Sstevel@tonic-gate 	if (i == KCF_MAX_PROVIDERS) {
1187c478bd9Sstevel@tonic-gate 		/* ran out of providers entries */
1197c478bd9Sstevel@tonic-gate 		mutex_exit(&prov_tab_mutex);
1207c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "out of providers entries");
1217c478bd9Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
1227c478bd9Sstevel@tonic-gate 	}
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	/* initialize entry */
1257c478bd9Sstevel@tonic-gate 	prov_tab[i] = prov_desc;
1267c478bd9Sstevel@tonic-gate 	KCF_PROV_REFHOLD(prov_desc);
1277c478bd9Sstevel@tonic-gate 	prov_tab_num++;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	mutex_exit(&prov_tab_mutex);
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	/* update provider descriptor */
1327c478bd9Sstevel@tonic-gate 	prov_desc->pd_prov_id = i;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	/*
1357c478bd9Sstevel@tonic-gate 	 * The KCF-private provider handle is defined as the internal
1367c478bd9Sstevel@tonic-gate 	 * provider id.
1377c478bd9Sstevel@tonic-gate 	 */
1387c478bd9Sstevel@tonic-gate 	prov_desc->pd_kcf_prov_handle =
139fe2f7468Skrishna 	    (crypto_kcf_provider_handle_t)prov_desc->pd_prov_id;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate #if DEBUG
1427c478bd9Sstevel@tonic-gate 	if (kcf_frmwrk_debug >= 1)
1431b22764fSDaniel OpenSolaris Anderson 		kcf_prov_tab_dump("kcf_prov_tab_add_provider");
1447c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * Remove the provider specified by its id. A REFRELE is done on the
1517c478bd9Sstevel@tonic-gate  * corresponding provider descriptor before this function returns.
1527c478bd9Sstevel@tonic-gate  * Returns CRYPTO_UNKNOWN_PROVIDER if the provider id is not valid.
1537c478bd9Sstevel@tonic-gate  */
1547c478bd9Sstevel@tonic-gate int
kcf_prov_tab_rem_provider(crypto_provider_id_t prov_id)1557c478bd9Sstevel@tonic-gate kcf_prov_tab_rem_provider(crypto_provider_id_t prov_id)
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *prov_desc;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	ASSERT(prov_tab != NULL);
16095014fbbSDan OpenSolaris Anderson 	ASSERT(prov_tab_num != (uint_t)-1); /* underflow */
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	/*
1637c478bd9Sstevel@tonic-gate 	 * Validate provider id, since it can be specified by a 3rd-party
1647c478bd9Sstevel@tonic-gate 	 * provider.
1657c478bd9Sstevel@tonic-gate 	 */
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	mutex_enter(&prov_tab_mutex);
1687c478bd9Sstevel@tonic-gate 	if (prov_id >= KCF_MAX_PROVIDERS ||
1697c478bd9Sstevel@tonic-gate 	    ((prov_desc = prov_tab[prov_id]) == NULL)) {
1707c478bd9Sstevel@tonic-gate 		mutex_exit(&prov_tab_mutex);
1717c478bd9Sstevel@tonic-gate 		return (CRYPTO_INVALID_PROVIDER_ID);
1727c478bd9Sstevel@tonic-gate 	}
1737623016fSKrishna Yenduri 
1747623016fSKrishna Yenduri 	if (kcf_need_provtab_walk)
1757623016fSKrishna Yenduri 		kcf_free_unregistered_provs();
1767c478bd9Sstevel@tonic-gate 	mutex_exit(&prov_tab_mutex);
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	/*
1797c478bd9Sstevel@tonic-gate 	 * The provider id must remain valid until the associated provider
1807c478bd9Sstevel@tonic-gate 	 * descriptor is freed. For this reason, we simply release our
1817c478bd9Sstevel@tonic-gate 	 * reference to the descriptor here. When the reference count
1827c478bd9Sstevel@tonic-gate 	 * reaches zero, kcf_free_provider_desc() will be invoked and
1837c478bd9Sstevel@tonic-gate 	 * the associated entry in the providers table will be released
1847c478bd9Sstevel@tonic-gate 	 * at that time.
1857c478bd9Sstevel@tonic-gate 	 */
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	KCF_PROV_REFRELE(prov_desc);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate #if DEBUG
1907c478bd9Sstevel@tonic-gate 	if (kcf_frmwrk_debug >= 1)
1911b22764fSDaniel OpenSolaris Anderson 		kcf_prov_tab_dump("kcf_prov_tab_rem_provider");
1927c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /*
1987c478bd9Sstevel@tonic-gate  * Returns the provider descriptor corresponding to the specified
1997c478bd9Sstevel@tonic-gate  * provider id. A REFHOLD is done on the descriptor before it is
2007c478bd9Sstevel@tonic-gate  * returned to the caller. It is the responsibility of the caller
2017c478bd9Sstevel@tonic-gate  * to do a REFRELE once it is done with the provider descriptor.
2027c478bd9Sstevel@tonic-gate  */
2037c478bd9Sstevel@tonic-gate kcf_provider_desc_t *
kcf_prov_tab_lookup(crypto_provider_id_t prov_id)2047c478bd9Sstevel@tonic-gate kcf_prov_tab_lookup(crypto_provider_id_t prov_id)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *prov_desc;
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	mutex_enter(&prov_tab_mutex);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	prov_desc = prov_tab[prov_id];
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	if (prov_desc == NULL) {
2137c478bd9Sstevel@tonic-gate 		mutex_exit(&prov_tab_mutex);
2147c478bd9Sstevel@tonic-gate 		return (NULL);
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	KCF_PROV_REFHOLD(prov_desc);
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	mutex_exit(&prov_tab_mutex);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	return (prov_desc);
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
224894b2776Smcpowers static void
allocate_ops_v1(crypto_ops_t * src,crypto_ops_t * dst,uint_t * mech_list_count)225894b2776Smcpowers allocate_ops_v1(crypto_ops_t *src, crypto_ops_t *dst, uint_t *mech_list_count)
226894b2776Smcpowers {
227894b2776Smcpowers 	if (src->co_control_ops != NULL)
228894b2776Smcpowers 		dst->co_control_ops = kmem_alloc(sizeof (crypto_control_ops_t),
229894b2776Smcpowers 		    KM_SLEEP);
230894b2776Smcpowers 
231894b2776Smcpowers 	if (src->co_digest_ops != NULL)
232894b2776Smcpowers 		dst->co_digest_ops = kmem_alloc(sizeof (crypto_digest_ops_t),
233894b2776Smcpowers 		    KM_SLEEP);
234894b2776Smcpowers 
235894b2776Smcpowers 	if (src->co_cipher_ops != NULL)
236894b2776Smcpowers 		dst->co_cipher_ops = kmem_alloc(sizeof (crypto_cipher_ops_t),
237894b2776Smcpowers 		    KM_SLEEP);
238894b2776Smcpowers 
239894b2776Smcpowers 	if (src->co_mac_ops != NULL)
240894b2776Smcpowers 		dst->co_mac_ops = kmem_alloc(sizeof (crypto_mac_ops_t),
241894b2776Smcpowers 		    KM_SLEEP);
242894b2776Smcpowers 
243894b2776Smcpowers 	if (src->co_sign_ops != NULL)
244894b2776Smcpowers 		dst->co_sign_ops = kmem_alloc(sizeof (crypto_sign_ops_t),
245894b2776Smcpowers 		    KM_SLEEP);
246894b2776Smcpowers 
247894b2776Smcpowers 	if (src->co_verify_ops != NULL)
248894b2776Smcpowers 		dst->co_verify_ops = kmem_alloc(sizeof (crypto_verify_ops_t),
249894b2776Smcpowers 		    KM_SLEEP);
250894b2776Smcpowers 
251894b2776Smcpowers 	if (src->co_dual_ops != NULL)
252894b2776Smcpowers 		dst->co_dual_ops = kmem_alloc(sizeof (crypto_dual_ops_t),
253894b2776Smcpowers 		    KM_SLEEP);
254894b2776Smcpowers 
255894b2776Smcpowers 	if (src->co_dual_cipher_mac_ops != NULL)
256894b2776Smcpowers 		dst->co_dual_cipher_mac_ops = kmem_alloc(
257894b2776Smcpowers 		    sizeof (crypto_dual_cipher_mac_ops_t), KM_SLEEP);
258894b2776Smcpowers 
259894b2776Smcpowers 	if (src->co_random_ops != NULL) {
260894b2776Smcpowers 		dst->co_random_ops = kmem_alloc(
261894b2776Smcpowers 		    sizeof (crypto_random_number_ops_t), KM_SLEEP);
262894b2776Smcpowers 
263894b2776Smcpowers 		/*
264894b2776Smcpowers 		 * Allocate storage to store the array of supported mechanisms
265894b2776Smcpowers 		 * specified by provider. We allocate extra mechanism storage
266894b2776Smcpowers 		 * if the provider has random_ops since we keep an internal
267894b2776Smcpowers 		 * mechanism, SUN_RANDOM, in this case.
268894b2776Smcpowers 		 */
269894b2776Smcpowers 		(*mech_list_count)++;
270894b2776Smcpowers 	}
271894b2776Smcpowers 
272894b2776Smcpowers 	if (src->co_session_ops != NULL)
273894b2776Smcpowers 		dst->co_session_ops = kmem_alloc(sizeof (crypto_session_ops_t),
274894b2776Smcpowers 		    KM_SLEEP);
275894b2776Smcpowers 
276894b2776Smcpowers 	if (src->co_object_ops != NULL)
277894b2776Smcpowers 		dst->co_object_ops = kmem_alloc(sizeof (crypto_object_ops_t),
278894b2776Smcpowers 		    KM_SLEEP);
279894b2776Smcpowers 
280894b2776Smcpowers 	if (src->co_key_ops != NULL)
281894b2776Smcpowers 		dst->co_key_ops = kmem_alloc(sizeof (crypto_key_ops_t),
282894b2776Smcpowers 		    KM_SLEEP);
283894b2776Smcpowers 
284894b2776Smcpowers 	if (src->co_provider_ops != NULL)
285894b2776Smcpowers 		dst->co_provider_ops = kmem_alloc(
286894b2776Smcpowers 		    sizeof (crypto_provider_management_ops_t), KM_SLEEP);
287894b2776Smcpowers 
288894b2776Smcpowers 	if (src->co_ctx_ops != NULL)
289894b2776Smcpowers 		dst->co_ctx_ops = kmem_alloc(sizeof (crypto_ctx_ops_t),
290894b2776Smcpowers 		    KM_SLEEP);
291894b2776Smcpowers }
292894b2776Smcpowers 
293894b2776Smcpowers static void
allocate_ops_v2(crypto_ops_t * src,crypto_ops_t * dst)294894b2776Smcpowers allocate_ops_v2(crypto_ops_t *src, crypto_ops_t *dst)
295894b2776Smcpowers {
296894b2776Smcpowers 	if (src->co_mech_ops != NULL)
297894b2776Smcpowers 		dst->co_mech_ops = kmem_alloc(sizeof (crypto_mech_ops_t),
298894b2776Smcpowers 		    KM_SLEEP);
299894b2776Smcpowers }
300894b2776Smcpowers 
301034448feSmcpowers static void
allocate_ops_v3(crypto_ops_t * src,crypto_ops_t * dst)302034448feSmcpowers allocate_ops_v3(crypto_ops_t *src, crypto_ops_t *dst)
303034448feSmcpowers {
304034448feSmcpowers 	if (src->co_nostore_key_ops != NULL)
305034448feSmcpowers 		dst->co_nostore_key_ops =
306034448feSmcpowers 		    kmem_alloc(sizeof (crypto_nostore_key_ops_t), KM_SLEEP);
307034448feSmcpowers }
308034448feSmcpowers 
30973556491SAnthony Scarpino static void
allocate_ops_v4(crypto_ops_t * src,crypto_ops_t * dst)31073556491SAnthony Scarpino allocate_ops_v4(crypto_ops_t *src, crypto_ops_t *dst)
31173556491SAnthony Scarpino {
31273556491SAnthony Scarpino 	if (src->co_fips140_ops != NULL)
31373556491SAnthony Scarpino 		dst->co_fips140_ops =
31473556491SAnthony Scarpino 		    kmem_alloc(sizeof (crypto_fips140_ops_t), KM_SLEEP);
31573556491SAnthony Scarpino }
31673556491SAnthony Scarpino 
3177c478bd9Sstevel@tonic-gate /*
3187c478bd9Sstevel@tonic-gate  * Allocate a provider descriptor. mech_list_count specifies the
3197c478bd9Sstevel@tonic-gate  * number of mechanisms supported by the providers, and is used
3207c478bd9Sstevel@tonic-gate  * to allocate storage for the mechanism table.
3217c478bd9Sstevel@tonic-gate  * This function may sleep while allocating memory, which is OK
3227c478bd9Sstevel@tonic-gate  * since it is invoked from user context during provider registration.
3237c478bd9Sstevel@tonic-gate  */
3247c478bd9Sstevel@tonic-gate kcf_provider_desc_t *
kcf_alloc_provider_desc(crypto_provider_info_t * info)3257c478bd9Sstevel@tonic-gate kcf_alloc_provider_desc(crypto_provider_info_t *info)
3267c478bd9Sstevel@tonic-gate {
3276a1073f8Skrishna 	int i, j;
3287c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *desc;
3297c478bd9Sstevel@tonic-gate 	uint_t mech_list_count = info->pi_mech_list_count;
3307c478bd9Sstevel@tonic-gate 	crypto_ops_t *src_ops = info->pi_ops_vector;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	desc = kmem_zalloc(sizeof (kcf_provider_desc_t), KM_SLEEP);
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	/*
3357c478bd9Sstevel@tonic-gate 	 * pd_description serves two purposes
3367c478bd9Sstevel@tonic-gate 	 * - Appears as a blank padded PKCS#11 style string, that will be
3377c478bd9Sstevel@tonic-gate 	 *   returned to applications in CK_SLOT_INFO.slotDescription.
3387c478bd9Sstevel@tonic-gate 	 *   This means that we should not have a null character in the
3397c478bd9Sstevel@tonic-gate 	 *   first CRYPTO_PROVIDER_DESCR_MAX_LEN bytes.
3407c478bd9Sstevel@tonic-gate 	 * - Appears as a null-terminated string that can be used by
3417c478bd9Sstevel@tonic-gate 	 *   other kcf routines.
3427c478bd9Sstevel@tonic-gate 	 *
3437c478bd9Sstevel@tonic-gate 	 * So, we allocate enough room for one extra null terminator
3447c478bd9Sstevel@tonic-gate 	 * which keeps every one happy.
3457c478bd9Sstevel@tonic-gate 	 */
3467c478bd9Sstevel@tonic-gate 	desc->pd_description = kmem_alloc(CRYPTO_PROVIDER_DESCR_MAX_LEN + 1,
3477c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
3487c478bd9Sstevel@tonic-gate 	(void) memset(desc->pd_description, ' ',
3497c478bd9Sstevel@tonic-gate 	    CRYPTO_PROVIDER_DESCR_MAX_LEN);
3507c478bd9Sstevel@tonic-gate 	desc->pd_description[CRYPTO_PROVIDER_DESCR_MAX_LEN] = '\0';
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	/*
3537c478bd9Sstevel@tonic-gate 	 * Since the framework does not require the ops vector specified
3547c478bd9Sstevel@tonic-gate 	 * by the providers during registration to be persistent,
3557c478bd9Sstevel@tonic-gate 	 * KCF needs to allocate storage where copies of the ops
3567c478bd9Sstevel@tonic-gate 	 * vectors are copied.
3577c478bd9Sstevel@tonic-gate 	 */
3587c478bd9Sstevel@tonic-gate 	desc->pd_ops_vector = kmem_zalloc(sizeof (crypto_ops_t), KM_SLEEP);
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
361894b2776Smcpowers 		allocate_ops_v1(src_ops, desc->pd_ops_vector, &mech_list_count);
362034448feSmcpowers 		if (info->pi_interface_version >= CRYPTO_SPI_VERSION_2)
363894b2776Smcpowers 			allocate_ops_v2(src_ops, desc->pd_ops_vector);
36473556491SAnthony Scarpino 		if (info->pi_interface_version >= CRYPTO_SPI_VERSION_3)
365034448feSmcpowers 			allocate_ops_v3(src_ops, desc->pd_ops_vector);
36673556491SAnthony Scarpino 		if (info->pi_interface_version == CRYPTO_SPI_VERSION_4)
36773556491SAnthony Scarpino 			allocate_ops_v4(src_ops, desc->pd_ops_vector);
3687c478bd9Sstevel@tonic-gate 	}
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	desc->pd_mech_list_count = mech_list_count;
3716a1073f8Skrishna 	desc->pd_mechanisms = kmem_zalloc(sizeof (crypto_mech_info_t) *
3727c478bd9Sstevel@tonic-gate 	    mech_list_count, KM_SLEEP);
3736a1073f8Skrishna 	for (i = 0; i < KCF_OPS_CLASSSIZE; i++)
3746a1073f8Skrishna 		for (j = 0; j < KCF_MAXMECHTAB; j++)
3756a1073f8Skrishna 			desc->pd_mech_indx[i][j] = KCF_INVALID_INDX;
3766a1073f8Skrishna 
3777c478bd9Sstevel@tonic-gate 	desc->pd_prov_id = KCF_PROVID_INVALID;
3787c478bd9Sstevel@tonic-gate 	desc->pd_state = KCF_PROV_ALLOCATED;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	mutex_init(&desc->pd_lock, NULL, MUTEX_DEFAULT, NULL);
3817c478bd9Sstevel@tonic-gate 	cv_init(&desc->pd_resume_cv, NULL, CV_DEFAULT, NULL);
3827c478bd9Sstevel@tonic-gate 
383ef56a3c5SKrishna Yenduri 	desc->pd_nbins = max_ncpus;
384ef56a3c5SKrishna Yenduri 	desc->pd_percpu_bins =
385ef56a3c5SKrishna Yenduri 	    kmem_zalloc(desc->pd_nbins * sizeof (kcf_prov_cpu_t), KM_SLEEP);
3867c478bd9Sstevel@tonic-gate 
387ef56a3c5SKrishna Yenduri 	return (desc);
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate /*
3917623016fSKrishna Yenduri  * Free a provider descriptor. Caller must hold prov_tab_mutex.
3927623016fSKrishna Yenduri  *
3937623016fSKrishna Yenduri  * Caution: This routine drops prov_tab_mutex.
3947c478bd9Sstevel@tonic-gate  */
3957c478bd9Sstevel@tonic-gate void
kcf_free_provider_desc(kcf_provider_desc_t * desc)3967c478bd9Sstevel@tonic-gate kcf_free_provider_desc(kcf_provider_desc_t *desc)
3977c478bd9Sstevel@tonic-gate {
3987c478bd9Sstevel@tonic-gate 	if (desc == NULL)
3997c478bd9Sstevel@tonic-gate 		return;
4007c478bd9Sstevel@tonic-gate 
4017623016fSKrishna Yenduri 	ASSERT(MUTEX_HELD(&prov_tab_mutex));
4027c478bd9Sstevel@tonic-gate 	if (desc->pd_prov_id != KCF_PROVID_INVALID) {
4037c478bd9Sstevel@tonic-gate 		/* release the associated providers table entry */
4047c478bd9Sstevel@tonic-gate 		ASSERT(prov_tab[desc->pd_prov_id] != NULL);
4057c478bd9Sstevel@tonic-gate 		prov_tab[desc->pd_prov_id] = NULL;
4067c478bd9Sstevel@tonic-gate 		prov_tab_num--;
4077c478bd9Sstevel@tonic-gate 	}
4087c478bd9Sstevel@tonic-gate 	mutex_exit(&prov_tab_mutex);
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	/* free the kernel memory associated with the provider descriptor */
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	if (desc->pd_description != NULL)
4137c478bd9Sstevel@tonic-gate 		kmem_free(desc->pd_description,
4147c478bd9Sstevel@tonic-gate 		    CRYPTO_PROVIDER_DESCR_MAX_LEN + 1);
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	if (desc->pd_ops_vector != NULL) {
4177c478bd9Sstevel@tonic-gate 
418894b2776Smcpowers 		if (desc->pd_ops_vector->co_control_ops != NULL)
419894b2776Smcpowers 			kmem_free(desc->pd_ops_vector->co_control_ops,
4207c478bd9Sstevel@tonic-gate 			    sizeof (crypto_control_ops_t));
4217c478bd9Sstevel@tonic-gate 
422894b2776Smcpowers 		if (desc->pd_ops_vector->co_digest_ops != NULL)
423894b2776Smcpowers 			kmem_free(desc->pd_ops_vector->co_digest_ops,
4247c478bd9Sstevel@tonic-gate 			    sizeof (crypto_digest_ops_t));
4257c478bd9Sstevel@tonic-gate 
426894b2776Smcpowers 		if (desc->pd_ops_vector->co_cipher_ops != NULL)
427894b2776Smcpowers 			kmem_free(desc->pd_ops_vector->co_cipher_ops,
4287c478bd9Sstevel@tonic-gate 			    sizeof (crypto_cipher_ops_t));
4297c478bd9Sstevel@tonic-gate 
430894b2776Smcpowers 		if (desc->pd_ops_vector->co_mac_ops != NULL)
431894b2776Smcpowers 			kmem_free(desc->pd_ops_vector->co_mac_ops,
4327c478bd9Sstevel@tonic-gate 			    sizeof (crypto_mac_ops_t));
4337c478bd9Sstevel@tonic-gate 
434894b2776Smcpowers 		if (desc->pd_ops_vector->co_sign_ops != NULL)
435894b2776Smcpowers 			kmem_free(desc->pd_ops_vector->co_sign_ops,
4367c478bd9Sstevel@tonic-gate 			    sizeof (crypto_sign_ops_t));
4377c478bd9Sstevel@tonic-gate 
438894b2776Smcpowers 		if (desc->pd_ops_vector->co_verify_ops != NULL)
439894b2776Smcpowers 			kmem_free(desc->pd_ops_vector->co_verify_ops,
4407c478bd9Sstevel@tonic-gate 			    sizeof (crypto_verify_ops_t));
4417c478bd9Sstevel@tonic-gate 
442894b2776Smcpowers 		if (desc->pd_ops_vector->co_dual_ops != NULL)
443894b2776Smcpowers 			kmem_free(desc->pd_ops_vector->co_dual_ops,
4447c478bd9Sstevel@tonic-gate 			    sizeof (crypto_dual_ops_t));
4457c478bd9Sstevel@tonic-gate 
446894b2776Smcpowers 		if (desc->pd_ops_vector->co_dual_cipher_mac_ops != NULL)
447894b2776Smcpowers 			kmem_free(desc->pd_ops_vector->co_dual_cipher_mac_ops,
4487c478bd9Sstevel@tonic-gate 			    sizeof (crypto_dual_cipher_mac_ops_t));
4497c478bd9Sstevel@tonic-gate 
450894b2776Smcpowers 		if (desc->pd_ops_vector->co_random_ops != NULL)
451894b2776Smcpowers 			kmem_free(desc->pd_ops_vector->co_random_ops,
4527c478bd9Sstevel@tonic-gate 			    sizeof (crypto_random_number_ops_t));
4537c478bd9Sstevel@tonic-gate 
454894b2776Smcpowers 		if (desc->pd_ops_vector->co_session_ops != NULL)
455894b2776Smcpowers 			kmem_free(desc->pd_ops_vector->co_session_ops,
4567c478bd9Sstevel@tonic-gate 			    sizeof (crypto_session_ops_t));
4577c478bd9Sstevel@tonic-gate 
458894b2776Smcpowers 		if (desc->pd_ops_vector->co_object_ops != NULL)
459894b2776Smcpowers 			kmem_free(desc->pd_ops_vector->co_object_ops,
4607c478bd9Sstevel@tonic-gate 			    sizeof (crypto_object_ops_t));
4617c478bd9Sstevel@tonic-gate 
462894b2776Smcpowers 		if (desc->pd_ops_vector->co_key_ops != NULL)
463894b2776Smcpowers 			kmem_free(desc->pd_ops_vector->co_key_ops,
4647c478bd9Sstevel@tonic-gate 			    sizeof (crypto_key_ops_t));
4657c478bd9Sstevel@tonic-gate 
466894b2776Smcpowers 		if (desc->pd_ops_vector->co_provider_ops != NULL)
467894b2776Smcpowers 			kmem_free(desc->pd_ops_vector->co_provider_ops,
4687c478bd9Sstevel@tonic-gate 			    sizeof (crypto_provider_management_ops_t));
4697c478bd9Sstevel@tonic-gate 
470894b2776Smcpowers 		if (desc->pd_ops_vector->co_ctx_ops != NULL)
471894b2776Smcpowers 			kmem_free(desc->pd_ops_vector->co_ctx_ops,
4727c478bd9Sstevel@tonic-gate 			    sizeof (crypto_ctx_ops_t));
4737c478bd9Sstevel@tonic-gate 
474894b2776Smcpowers 		if (desc->pd_ops_vector->co_mech_ops != NULL)
475894b2776Smcpowers 			kmem_free(desc->pd_ops_vector->co_mech_ops,
476894b2776Smcpowers 			    sizeof (crypto_mech_ops_t));
477894b2776Smcpowers 
478034448feSmcpowers 		if (desc->pd_ops_vector->co_nostore_key_ops != NULL)
479034448feSmcpowers 			kmem_free(desc->pd_ops_vector->co_nostore_key_ops,
480034448feSmcpowers 			    sizeof (crypto_nostore_key_ops_t));
481034448feSmcpowers 
48273556491SAnthony Scarpino 		if (desc->pd_ops_vector->co_fips140_ops != NULL)
48373556491SAnthony Scarpino 			kmem_free(desc->pd_ops_vector->co_fips140_ops,
48473556491SAnthony Scarpino 			    sizeof (crypto_fips140_ops_t));
48573556491SAnthony Scarpino 
4867c478bd9Sstevel@tonic-gate 		kmem_free(desc->pd_ops_vector, sizeof (crypto_ops_t));
4877c478bd9Sstevel@tonic-gate 	}
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	if (desc->pd_mechanisms != NULL)
4907c478bd9Sstevel@tonic-gate 		/* free the memory associated with the mechanism info's */
4917c478bd9Sstevel@tonic-gate 		kmem_free(desc->pd_mechanisms, sizeof (crypto_mech_info_t) *
4927c478bd9Sstevel@tonic-gate 		    desc->pd_mech_list_count);
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	if (desc->pd_name != NULL) {
4957c478bd9Sstevel@tonic-gate 		kmem_free(desc->pd_name, strlen(desc->pd_name) + 1);
4967c478bd9Sstevel@tonic-gate 	}
4977c478bd9Sstevel@tonic-gate 
498ef56a3c5SKrishna Yenduri 	if (desc->pd_taskq != NULL)
499ef56a3c5SKrishna Yenduri 		taskq_destroy(desc->pd_taskq);
500ef56a3c5SKrishna Yenduri 
501ef56a3c5SKrishna Yenduri 	if (desc->pd_percpu_bins != NULL) {
502ef56a3c5SKrishna Yenduri 		kmem_free(desc->pd_percpu_bins,
503ef56a3c5SKrishna Yenduri 		    desc->pd_nbins * sizeof (kcf_prov_cpu_t));
504ef56a3c5SKrishna Yenduri 	}
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	kmem_free(desc, sizeof (kcf_provider_desc_t));
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate /*
5107c478bd9Sstevel@tonic-gate  * Returns the provider descriptor corresponding to the specified
5117c478bd9Sstevel@tonic-gate  * module name. A REFHOLD is done on the descriptor before it is
5127c478bd9Sstevel@tonic-gate  * returned to the caller. It is the responsibility of the caller
5137c478bd9Sstevel@tonic-gate  * to do a REFRELE once it is done with the provider descriptor.
5147c478bd9Sstevel@tonic-gate  * Only software providers are returned by this function.
5157c478bd9Sstevel@tonic-gate  */
5167c478bd9Sstevel@tonic-gate kcf_provider_desc_t *
kcf_prov_tab_lookup_by_name(char * module_name)5177c478bd9Sstevel@tonic-gate kcf_prov_tab_lookup_by_name(char *module_name)
5187c478bd9Sstevel@tonic-gate {
5197c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *prov_desc;
5207c478bd9Sstevel@tonic-gate 	uint_t i;
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	mutex_enter(&prov_tab_mutex);
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
5257c478bd9Sstevel@tonic-gate 		if ((prov_desc = prov_tab[i]) != NULL &&
5267c478bd9Sstevel@tonic-gate 		    (!KCF_IS_PROV_REMOVED(prov_desc)) &&
5277c478bd9Sstevel@tonic-gate 		    prov_desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
5287c478bd9Sstevel@tonic-gate 			ASSERT(prov_desc->pd_name != NULL);
5297c478bd9Sstevel@tonic-gate 			if (strncmp(module_name, prov_desc->pd_name,
5307c478bd9Sstevel@tonic-gate 			    MAXNAMELEN) == 0) {
5317c478bd9Sstevel@tonic-gate 				KCF_PROV_REFHOLD(prov_desc);
5327c478bd9Sstevel@tonic-gate 				mutex_exit(&prov_tab_mutex);
5337c478bd9Sstevel@tonic-gate 				return (prov_desc);
5347c478bd9Sstevel@tonic-gate 			}
5357c478bd9Sstevel@tonic-gate 		}
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	mutex_exit(&prov_tab_mutex);
5397c478bd9Sstevel@tonic-gate 	return (NULL);
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate /*
5437c478bd9Sstevel@tonic-gate  * Returns the provider descriptor corresponding to the specified
5447c478bd9Sstevel@tonic-gate  * device name and instance. A REFHOLD is done on the descriptor
5457c478bd9Sstevel@tonic-gate  * before it is returned to the caller. It is the responsibility
5467c478bd9Sstevel@tonic-gate  * of the caller to do a REFRELE once it is done with the provider
5477c478bd9Sstevel@tonic-gate  * descriptor. Only hardware providers are returned by this function.
5487c478bd9Sstevel@tonic-gate  */
5497c478bd9Sstevel@tonic-gate kcf_provider_desc_t *
kcf_prov_tab_lookup_by_dev(char * name,uint_t instance)5507c478bd9Sstevel@tonic-gate kcf_prov_tab_lookup_by_dev(char *name, uint_t instance)
5517c478bd9Sstevel@tonic-gate {
5527c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *prov_desc;
5537c478bd9Sstevel@tonic-gate 	uint_t i;
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	mutex_enter(&prov_tab_mutex);
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
5587c478bd9Sstevel@tonic-gate 		if ((prov_desc = prov_tab[i]) != NULL &&
5597c478bd9Sstevel@tonic-gate 		    (!KCF_IS_PROV_REMOVED(prov_desc)) &&
5607c478bd9Sstevel@tonic-gate 		    prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER) {
5617c478bd9Sstevel@tonic-gate 			ASSERT(prov_desc->pd_name != NULL);
5627c478bd9Sstevel@tonic-gate 			if (strncmp(prov_desc->pd_name, name,
5637c478bd9Sstevel@tonic-gate 			    MAXNAMELEN) == 0 &&
5647c478bd9Sstevel@tonic-gate 			    prov_desc->pd_instance == instance) {
5657c478bd9Sstevel@tonic-gate 				KCF_PROV_REFHOLD(prov_desc);
5667c478bd9Sstevel@tonic-gate 				mutex_exit(&prov_tab_mutex);
5677c478bd9Sstevel@tonic-gate 				return (prov_desc);
5687c478bd9Sstevel@tonic-gate 			}
5697c478bd9Sstevel@tonic-gate 		}
5707c478bd9Sstevel@tonic-gate 	}
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	mutex_exit(&prov_tab_mutex);
5737c478bd9Sstevel@tonic-gate 	return (NULL);
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate /*
5777c478bd9Sstevel@tonic-gate  * Returns an array of hardware and logical provider descriptors,
5787c478bd9Sstevel@tonic-gate  * a.k.a the PKCS#11 slot list. A REFHOLD is done on each descriptor
5797c478bd9Sstevel@tonic-gate  * before the array is returned. The entire table can be freed by
5807c478bd9Sstevel@tonic-gate  * calling kcf_free_provider_tab().
5817c478bd9Sstevel@tonic-gate  */
5827c478bd9Sstevel@tonic-gate int
kcf_get_slot_list(uint_t * count,kcf_provider_desc_t *** array,boolean_t unverified)5837c478bd9Sstevel@tonic-gate kcf_get_slot_list(uint_t *count, kcf_provider_desc_t ***array,
5847c478bd9Sstevel@tonic-gate     boolean_t unverified)
5857c478bd9Sstevel@tonic-gate {
5867c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *prov_desc;
5877c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t **p = NULL;
5887c478bd9Sstevel@tonic-gate 	char *last;
5897c478bd9Sstevel@tonic-gate 	uint_t cnt = 0;
5907c478bd9Sstevel@tonic-gate 	uint_t i, j;
5917c478bd9Sstevel@tonic-gate 	int rval = CRYPTO_SUCCESS;
5927c478bd9Sstevel@tonic-gate 	size_t n, final_size;
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	/* count the providers */
5957c478bd9Sstevel@tonic-gate 	mutex_enter(&prov_tab_mutex);
5967c478bd9Sstevel@tonic-gate 	for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
5977c478bd9Sstevel@tonic-gate 		if ((prov_desc = prov_tab[i]) != NULL &&
598894b2776Smcpowers 		    ((prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER &&
599894b2776Smcpowers 		    (prov_desc->pd_flags & CRYPTO_HIDE_PROVIDER) == 0) ||
6007c478bd9Sstevel@tonic-gate 		    prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)) {
6017c478bd9Sstevel@tonic-gate 			if (KCF_IS_PROV_USABLE(prov_desc) ||
6027c478bd9Sstevel@tonic-gate 			    (unverified && KCF_IS_PROV_UNVERIFIED(prov_desc))) {
6037c478bd9Sstevel@tonic-gate 				cnt++;
6047c478bd9Sstevel@tonic-gate 			}
6057c478bd9Sstevel@tonic-gate 		}
6067c478bd9Sstevel@tonic-gate 	}
6077c478bd9Sstevel@tonic-gate 	mutex_exit(&prov_tab_mutex);
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	if (cnt == 0)
6107c478bd9Sstevel@tonic-gate 		goto out;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	n = cnt * sizeof (kcf_provider_desc_t *);
6137c478bd9Sstevel@tonic-gate again:
6147c478bd9Sstevel@tonic-gate 	p = kmem_zalloc(n, KM_SLEEP);
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	/* pointer to last entry in the array */
6177c478bd9Sstevel@tonic-gate 	last = (char *)&p[cnt-1];
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	mutex_enter(&prov_tab_mutex);
6207c478bd9Sstevel@tonic-gate 	/* fill the slot list */
6217c478bd9Sstevel@tonic-gate 	for (i = 0, j = 0; i < KCF_MAX_PROVIDERS; i++) {
6227c478bd9Sstevel@tonic-gate 		if ((prov_desc = prov_tab[i]) != NULL &&
623894b2776Smcpowers 		    ((prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER &&
624894b2776Smcpowers 		    (prov_desc->pd_flags & CRYPTO_HIDE_PROVIDER) == 0) ||
6257c478bd9Sstevel@tonic-gate 		    prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)) {
6267c478bd9Sstevel@tonic-gate 			if (KCF_IS_PROV_USABLE(prov_desc) ||
6277c478bd9Sstevel@tonic-gate 			    (unverified && KCF_IS_PROV_UNVERIFIED(prov_desc))) {
6287c478bd9Sstevel@tonic-gate 				if ((char *)&p[j] > last) {
6297c478bd9Sstevel@tonic-gate 					mutex_exit(&prov_tab_mutex);
6307c478bd9Sstevel@tonic-gate 					kcf_free_provider_tab(cnt, p);
6317c478bd9Sstevel@tonic-gate 					n = n << 1;
6327c478bd9Sstevel@tonic-gate 					cnt = cnt << 1;
6337c478bd9Sstevel@tonic-gate 					goto again;
6347c478bd9Sstevel@tonic-gate 				}
6357c478bd9Sstevel@tonic-gate 				p[j++] = prov_desc;
6367c478bd9Sstevel@tonic-gate 				KCF_PROV_REFHOLD(prov_desc);
6377c478bd9Sstevel@tonic-gate 			}
6387c478bd9Sstevel@tonic-gate 		}
6397c478bd9Sstevel@tonic-gate 	}
6407c478bd9Sstevel@tonic-gate 	mutex_exit(&prov_tab_mutex);
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	final_size = j * sizeof (kcf_provider_desc_t *);
6437c478bd9Sstevel@tonic-gate 	cnt = j;
6447c478bd9Sstevel@tonic-gate 	ASSERT(final_size <= n);
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	/* check if buffer we allocated is too large */
6477c478bd9Sstevel@tonic-gate 	if (final_size < n) {
6487c478bd9Sstevel@tonic-gate 		char *final_buffer = NULL;
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 		if (final_size > 0) {
6517c478bd9Sstevel@tonic-gate 			final_buffer = kmem_alloc(final_size, KM_SLEEP);
6527c478bd9Sstevel@tonic-gate 			bcopy(p, final_buffer, final_size);
6537c478bd9Sstevel@tonic-gate 		}
6547c478bd9Sstevel@tonic-gate 		kmem_free(p, n);
65595014fbbSDan OpenSolaris Anderson 		p = (kcf_provider_desc_t **)(void *)final_buffer;
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate out:
6587c478bd9Sstevel@tonic-gate 	*count = cnt;
6597c478bd9Sstevel@tonic-gate 	*array = p;
6607c478bd9Sstevel@tonic-gate 	return (rval);
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate /*
6647c478bd9Sstevel@tonic-gate  * Returns an array of hardware provider descriptors. This routine
665*bbf21555SRichard Lowe  * used by cryptoadm(8). A REFHOLD is done on each descriptor before
6667c478bd9Sstevel@tonic-gate  * the array is returned. The entire table can be freed by calling
6677c478bd9Sstevel@tonic-gate  * kcf_free_provider_tab().
6687c478bd9Sstevel@tonic-gate  *
6697c478bd9Sstevel@tonic-gate  * A NULL name argument puts all hardware providers in the array.
6707c478bd9Sstevel@tonic-gate  * A non-NULL name argument puts only those providers in the array
6717c478bd9Sstevel@tonic-gate  * which match the name and instance arguments.
6727c478bd9Sstevel@tonic-gate  */
6737c478bd9Sstevel@tonic-gate int
kcf_get_hw_prov_tab(uint_t * count,kcf_provider_desc_t *** array,int kmflag,char * name,uint_t instance,boolean_t unverified)6747c478bd9Sstevel@tonic-gate kcf_get_hw_prov_tab(uint_t *count, kcf_provider_desc_t ***array,  int kmflag,
6757c478bd9Sstevel@tonic-gate     char *name, uint_t instance, boolean_t unverified)
6767c478bd9Sstevel@tonic-gate {
6777c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *prov_desc;
6787c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t **p = NULL;
6797c478bd9Sstevel@tonic-gate 	char *last;
6807c478bd9Sstevel@tonic-gate 	uint_t cnt = 0;
6817c478bd9Sstevel@tonic-gate 	uint_t i, j;
6827c478bd9Sstevel@tonic-gate 	int rval = CRYPTO_SUCCESS;
6837c478bd9Sstevel@tonic-gate 	size_t n, final_size;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	/* count the providers */
6867c478bd9Sstevel@tonic-gate 	mutex_enter(&prov_tab_mutex);
6877c478bd9Sstevel@tonic-gate 	for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
6887c478bd9Sstevel@tonic-gate 		if ((prov_desc = prov_tab[i]) != NULL &&
6897c478bd9Sstevel@tonic-gate 		    prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER) {
6907c478bd9Sstevel@tonic-gate 			if (KCF_IS_PROV_USABLE(prov_desc) ||
6917c478bd9Sstevel@tonic-gate 			    (unverified && KCF_IS_PROV_UNVERIFIED(prov_desc))) {
6927c478bd9Sstevel@tonic-gate 				if (name == NULL ||
6937c478bd9Sstevel@tonic-gate 				    (strncmp(prov_desc->pd_name, name,
6947c478bd9Sstevel@tonic-gate 				    MAXNAMELEN) == 0 &&
6957c478bd9Sstevel@tonic-gate 				    prov_desc->pd_instance == instance)) {
6967c478bd9Sstevel@tonic-gate 					cnt++;
6977c478bd9Sstevel@tonic-gate 				}
6987c478bd9Sstevel@tonic-gate 			}
6997c478bd9Sstevel@tonic-gate 		}
7007c478bd9Sstevel@tonic-gate 	}
7017c478bd9Sstevel@tonic-gate 	mutex_exit(&prov_tab_mutex);
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	if (cnt == 0)
7047c478bd9Sstevel@tonic-gate 		goto out;
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	n = cnt * sizeof (kcf_provider_desc_t *);
7077c478bd9Sstevel@tonic-gate again:
7087c478bd9Sstevel@tonic-gate 	p = kmem_zalloc(n, kmflag);
7097c478bd9Sstevel@tonic-gate 	if (p == NULL) {
7107c478bd9Sstevel@tonic-gate 		rval = CRYPTO_HOST_MEMORY;
7117c478bd9Sstevel@tonic-gate 		goto out;
7127c478bd9Sstevel@tonic-gate 	}
7137c478bd9Sstevel@tonic-gate 	/* pointer to last entry in the array */
7147c478bd9Sstevel@tonic-gate 	last = (char *)&p[cnt-1];
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	mutex_enter(&prov_tab_mutex);
7177c478bd9Sstevel@tonic-gate 	for (i = 0, j = 0; i < KCF_MAX_PROVIDERS; i++) {
7187c478bd9Sstevel@tonic-gate 		if ((prov_desc = prov_tab[i]) != NULL &&
7197c478bd9Sstevel@tonic-gate 		    prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER) {
7207c478bd9Sstevel@tonic-gate 			if (KCF_IS_PROV_USABLE(prov_desc) ||
7217c478bd9Sstevel@tonic-gate 			    (unverified && KCF_IS_PROV_UNVERIFIED(prov_desc))) {
7227c478bd9Sstevel@tonic-gate 				if (name == NULL ||
7237c478bd9Sstevel@tonic-gate 				    (strncmp(prov_desc->pd_name, name,
7247c478bd9Sstevel@tonic-gate 				    MAXNAMELEN) == 0 &&
7257c478bd9Sstevel@tonic-gate 				    prov_desc->pd_instance == instance)) {
7267c478bd9Sstevel@tonic-gate 					if ((char *)&p[j] > last) {
7277c478bd9Sstevel@tonic-gate 						mutex_exit(&prov_tab_mutex);
7287c478bd9Sstevel@tonic-gate 						kcf_free_provider_tab(cnt, p);
7297c478bd9Sstevel@tonic-gate 						n = n << 1;
7307c478bd9Sstevel@tonic-gate 						cnt = cnt << 1;
7317c478bd9Sstevel@tonic-gate 						goto again;
7327c478bd9Sstevel@tonic-gate 					}
7337c478bd9Sstevel@tonic-gate 					p[j++] = prov_desc;
7347c478bd9Sstevel@tonic-gate 					KCF_PROV_REFHOLD(prov_desc);
7357c478bd9Sstevel@tonic-gate 				}
7367c478bd9Sstevel@tonic-gate 			}
7377c478bd9Sstevel@tonic-gate 		}
7387c478bd9Sstevel@tonic-gate 	}
7397c478bd9Sstevel@tonic-gate 	mutex_exit(&prov_tab_mutex);
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	final_size = j * sizeof (kcf_provider_desc_t *);
7427c478bd9Sstevel@tonic-gate 	ASSERT(final_size <= n);
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	/* check if buffer we allocated is too large */
7457c478bd9Sstevel@tonic-gate 	if (final_size < n) {
7467c478bd9Sstevel@tonic-gate 		char *final_buffer = NULL;
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 		if (final_size > 0) {
7497c478bd9Sstevel@tonic-gate 			final_buffer = kmem_alloc(final_size, kmflag);
7507c478bd9Sstevel@tonic-gate 			if (final_buffer == NULL) {
7517c478bd9Sstevel@tonic-gate 				kcf_free_provider_tab(cnt, p);
7527c478bd9Sstevel@tonic-gate 				cnt = 0;
7537c478bd9Sstevel@tonic-gate 				p = NULL;
7547c478bd9Sstevel@tonic-gate 				rval = CRYPTO_HOST_MEMORY;
7557c478bd9Sstevel@tonic-gate 				goto out;
7567c478bd9Sstevel@tonic-gate 			}
7577c478bd9Sstevel@tonic-gate 			bcopy(p, final_buffer, final_size);
7587c478bd9Sstevel@tonic-gate 		}
7597c478bd9Sstevel@tonic-gate 		kmem_free(p, n);
76095014fbbSDan OpenSolaris Anderson 		p = (kcf_provider_desc_t **)(void *)final_buffer;
7617c478bd9Sstevel@tonic-gate 	}
7627c478bd9Sstevel@tonic-gate 	cnt = j;
7637c478bd9Sstevel@tonic-gate out:
7647c478bd9Sstevel@tonic-gate 	*count = cnt;
7657c478bd9Sstevel@tonic-gate 	*array = p;
7667c478bd9Sstevel@tonic-gate 	return (rval);
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate /*
7707c478bd9Sstevel@tonic-gate  * Free an array of hardware provider descriptors.  A REFRELE
7717c478bd9Sstevel@tonic-gate  * is done on each descriptor before the table is freed.
7727c478bd9Sstevel@tonic-gate  */
7737c478bd9Sstevel@tonic-gate void
kcf_free_provider_tab(uint_t count,kcf_provider_desc_t ** array)7747c478bd9Sstevel@tonic-gate kcf_free_provider_tab(uint_t count, kcf_provider_desc_t **array)
7757c478bd9Sstevel@tonic-gate {
7767c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *prov_desc;
7777c478bd9Sstevel@tonic-gate 	int i;
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
7807c478bd9Sstevel@tonic-gate 		if ((prov_desc = array[i]) != NULL) {
7817c478bd9Sstevel@tonic-gate 			KCF_PROV_REFRELE(prov_desc);
7827c478bd9Sstevel@tonic-gate 		}
7837c478bd9Sstevel@tonic-gate 	}
7847c478bd9Sstevel@tonic-gate 	kmem_free(array, count * sizeof (kcf_provider_desc_t *));
7857c478bd9Sstevel@tonic-gate }
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate /*
7887c478bd9Sstevel@tonic-gate  * Returns in the location pointed to by pd a pointer to the descriptor
7897c478bd9Sstevel@tonic-gate  * for the software provider for the specified mechanism.
7907c478bd9Sstevel@tonic-gate  * The provider descriptor is returned held and it is the caller's
7916a1073f8Skrishna  * responsibility to release it when done. The mechanism entry
7926a1073f8Skrishna  * is returned if the optional argument mep is non NULL.
7937c478bd9Sstevel@tonic-gate  *
7947c478bd9Sstevel@tonic-gate  * Returns one of the CRYPTO_ * error codes on failure, and
7957c478bd9Sstevel@tonic-gate  * CRYPTO_SUCCESS on success.
7967c478bd9Sstevel@tonic-gate  */
7977c478bd9Sstevel@tonic-gate int
kcf_get_sw_prov(crypto_mech_type_t mech_type,kcf_provider_desc_t ** pd,kcf_mech_entry_t ** mep,boolean_t log_warn)7987c478bd9Sstevel@tonic-gate kcf_get_sw_prov(crypto_mech_type_t mech_type, kcf_provider_desc_t **pd,
7996a1073f8Skrishna     kcf_mech_entry_t **mep, boolean_t log_warn)
8007c478bd9Sstevel@tonic-gate {
8017c478bd9Sstevel@tonic-gate 	kcf_mech_entry_t *me;
802ef56a3c5SKrishna Yenduri 	kcf_lock_withpad_t *mp;
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	/* get the mechanism entry for this mechanism */
8057c478bd9Sstevel@tonic-gate 	if (kcf_get_mech_entry(mech_type, &me) != KCF_SUCCESS)
8067c478bd9Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
8077c478bd9Sstevel@tonic-gate 
8086a1073f8Skrishna 	/*
8096a1073f8Skrishna 	 * Get the software provider for this mechanism.
8106a1073f8Skrishna 	 * Lock the mech_entry until we grab the 'pd'.
8116a1073f8Skrishna 	 */
812ef56a3c5SKrishna Yenduri 	mp = &me_mutexes[CPU_SEQID];
813ef56a3c5SKrishna Yenduri 	mutex_enter(&mp->kl_lock);
8147c478bd9Sstevel@tonic-gate 
8156a1073f8Skrishna 	if (me->me_sw_prov == NULL ||
8166a1073f8Skrishna 	    (*pd = me->me_sw_prov->pm_prov_desc) == NULL) {
8177c478bd9Sstevel@tonic-gate 		/* no SW provider for this mechanism */
8187c478bd9Sstevel@tonic-gate 		if (log_warn)
8197c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "no SW provider for \"%s\"\n",
8207c478bd9Sstevel@tonic-gate 			    me->me_name);
821ef56a3c5SKrishna Yenduri 		mutex_exit(&mp->kl_lock);
8227c478bd9Sstevel@tonic-gate 		return (CRYPTO_MECH_NOT_SUPPORTED);
8237c478bd9Sstevel@tonic-gate 	}
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	KCF_PROV_REFHOLD(*pd);
826ef56a3c5SKrishna Yenduri 	mutex_exit(&mp->kl_lock);
8277c478bd9Sstevel@tonic-gate 
8286a1073f8Skrishna 	if (mep != NULL)
8296a1073f8Skrishna 		*mep = me;
8306a1073f8Skrishna 
8317c478bd9Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate #if DEBUG
8351b22764fSDaniel OpenSolaris Anderson /*
8361b22764fSDaniel OpenSolaris Anderson  * Dump the Kernel crypto providers table, prov_tab.
8371b22764fSDaniel OpenSolaris Anderson  * If kcf_frmwrk_debug is >=2, also dump the mechanism lists.
8381b22764fSDaniel OpenSolaris Anderson  */
8397c478bd9Sstevel@tonic-gate static void
kcf_prov_tab_dump(char * message)8401b22764fSDaniel OpenSolaris Anderson kcf_prov_tab_dump(char *message)
8417c478bd9Sstevel@tonic-gate {
8421b22764fSDaniel OpenSolaris Anderson 	uint_t i, j;
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	mutex_enter(&prov_tab_mutex);
8451b22764fSDaniel OpenSolaris Anderson 	printf("Providers table prov_tab at %s:\n",
8461b22764fSDaniel OpenSolaris Anderson 	    message != NULL ? message : "");
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
8491b22764fSDaniel OpenSolaris Anderson 		kcf_provider_desc_t *p = prov_tab[i];
8501b22764fSDaniel OpenSolaris Anderson 		if (p != NULL) {
8511b22764fSDaniel OpenSolaris Anderson 			printf("[%d]: (%s) %d mechanisms, %s\n", i,
8521b22764fSDaniel OpenSolaris Anderson 			    (p->pd_prov_type == CRYPTO_HW_PROVIDER) ?
8531b22764fSDaniel OpenSolaris Anderson 			    "HW" : "SW",
8541b22764fSDaniel OpenSolaris Anderson 			    p->pd_mech_list_count, p->pd_description);
8551b22764fSDaniel OpenSolaris Anderson 			if (kcf_frmwrk_debug >= 2) {
8561b22764fSDaniel OpenSolaris Anderson 				printf("\tpd_mechanisms: ");
8571b22764fSDaniel OpenSolaris Anderson 				for (j = 0; j < p->pd_mech_list_count; ++j) {
8581b22764fSDaniel OpenSolaris Anderson 					printf("%s \n",
8591b22764fSDaniel OpenSolaris Anderson 					    p->pd_mechanisms[j].cm_mech_name);
8601b22764fSDaniel OpenSolaris Anderson 				}
8611b22764fSDaniel OpenSolaris Anderson 				printf("\n");
8621b22764fSDaniel OpenSolaris Anderson 			}
8637c478bd9Sstevel@tonic-gate 		}
8647c478bd9Sstevel@tonic-gate 	}
8657c478bd9Sstevel@tonic-gate 	printf("(end of providers table)\n");
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	mutex_exit(&prov_tab_mutex);
8687c478bd9Sstevel@tonic-gate }
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate #endif /* DEBUG */
8717c478bd9Sstevel@tonic-gate 
872ef56a3c5SKrishna Yenduri 
873ef56a3c5SKrishna Yenduri /* protected by prov_tab_mutex */
874ef56a3c5SKrishna Yenduri boolean_t kcf_need_provtab_walk = B_FALSE;
875ef56a3c5SKrishna Yenduri 
8767623016fSKrishna Yenduri /* Caller must hold prov_tab_mutex */
8777623016fSKrishna Yenduri static void
kcf_free_unregistered_provs()878ef56a3c5SKrishna Yenduri kcf_free_unregistered_provs()
879ef56a3c5SKrishna Yenduri {
880ef56a3c5SKrishna Yenduri 	int i;
881ef56a3c5SKrishna Yenduri 	kcf_provider_desc_t *pd;
882ef56a3c5SKrishna Yenduri 	boolean_t walk_again = B_FALSE;
883ef56a3c5SKrishna Yenduri 
8847623016fSKrishna Yenduri 	ASSERT(MUTEX_HELD(&prov_tab_mutex));
885ef56a3c5SKrishna Yenduri 	for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
886ef56a3c5SKrishna Yenduri 		if ((pd = prov_tab[i]) == NULL ||
8877623016fSKrishna Yenduri 		    pd->pd_prov_type == CRYPTO_SW_PROVIDER ||
888ef56a3c5SKrishna Yenduri 		    pd->pd_state != KCF_PROV_UNREGISTERED)
889ef56a3c5SKrishna Yenduri 			continue;
890ef56a3c5SKrishna Yenduri 
891ef56a3c5SKrishna Yenduri 		if (kcf_get_refcnt(pd, B_TRUE) == 0) {
8927623016fSKrishna Yenduri 			/* kcf_free_provider_desc drops prov_tab_mutex */
893ef56a3c5SKrishna Yenduri 			kcf_free_provider_desc(pd);
894ef56a3c5SKrishna Yenduri 			mutex_enter(&prov_tab_mutex);
895ef56a3c5SKrishna Yenduri 		} else
896ef56a3c5SKrishna Yenduri 			walk_again = B_TRUE;
897ef56a3c5SKrishna Yenduri 	}
898ef56a3c5SKrishna Yenduri 
899ef56a3c5SKrishna Yenduri 	kcf_need_provtab_walk = walk_again;
900ef56a3c5SKrishna Yenduri }
901