xref: /titanic_52/usr/src/uts/common/crypto/api/kcf_miscapi.c (revision 9b009fc1b553084f6003dcd46b171890049de0ff)
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
572eff6e2Smcpowers  * Common Development and Distribution License (the "License").
672eff6e2Smcpowers  * 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*9b009fc1SValerie 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/sunddi.h>
277c478bd9Sstevel@tonic-gate #include <sys/disp.h>
287c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
29894b2776Smcpowers #include <sys/sysmacros.h>
307c478bd9Sstevel@tonic-gate #include <sys/crypto/common.h>
317c478bd9Sstevel@tonic-gate #include <sys/crypto/api.h>
327c478bd9Sstevel@tonic-gate #include <sys/crypto/impl.h>
337c478bd9Sstevel@tonic-gate #include <sys/crypto/sched_impl.h>
347c478bd9Sstevel@tonic-gate 
35894b2776Smcpowers #define	isspace(ch)	(((ch) == ' ') || ((ch) == '\r') || ((ch) == '\n') || \
36894b2776Smcpowers 			((ch) == '\t') || ((ch) == '\f'))
37894b2776Smcpowers 
38894b2776Smcpowers #define	CRYPTO_OPS_OFFSET(f)		offsetof(crypto_ops_t, co_##f)
39894b2776Smcpowers #define	CRYPTO_KEY_OFFSET(f)		offsetof(crypto_key_ops_t, f)
40894b2776Smcpowers #define	CRYPTO_PROVIDER_OFFSET(f)	\
41894b2776Smcpowers 	offsetof(crypto_provider_management_ops_t, f)
42894b2776Smcpowers 
437c478bd9Sstevel@tonic-gate /* Miscellaneous exported entry points */
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * All event subscribers are put on a list. kcf_notify_list_lock
477c478bd9Sstevel@tonic-gate  * protects changes to this list.
487c478bd9Sstevel@tonic-gate  *
497c478bd9Sstevel@tonic-gate  * The following locking order is maintained in the code - The
507c478bd9Sstevel@tonic-gate  * global kcf_notify_list_lock followed by the individual lock
517c478bd9Sstevel@tonic-gate  * in a kcf_ntfy_elem structure (kn_lock).
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate kmutex_t		ntfy_list_lock;
547c478bd9Sstevel@tonic-gate kcondvar_t		ntfy_list_cv;   /* cv the service thread waits on */
557c478bd9Sstevel@tonic-gate static kcf_ntfy_elem_t *ntfy_list_head;
567c478bd9Sstevel@tonic-gate static kcf_ntfy_elem_t *ntfy_list_tail;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /* count all the hardware and software providers */
597c478bd9Sstevel@tonic-gate #define	PROV_COUNT(me) \
607c478bd9Sstevel@tonic-gate 	(((me)->me_sw_prov != NULL ? 1 : 0) + (me)->me_num_hwprov)
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * crypto_mech2id()
647c478bd9Sstevel@tonic-gate  *
657c478bd9Sstevel@tonic-gate  * Arguments:
667c478bd9Sstevel@tonic-gate  *	. mechname: A null-terminated string identifying the mechanism name.
677c478bd9Sstevel@tonic-gate  *
687c478bd9Sstevel@tonic-gate  * Description:
697c478bd9Sstevel@tonic-gate  *	Walks the mechanisms tables, looking for an entry that matches the
707c478bd9Sstevel@tonic-gate  *	mechname. Once it find it, it builds the 64-bit mech_type and returns
717c478bd9Sstevel@tonic-gate  *	it.  If there are no hardware or software providers for the mechanism,
727c478bd9Sstevel@tonic-gate  *	but there is an unloaded software provider, this routine will attempt
737c478bd9Sstevel@tonic-gate  *	to load it.
747c478bd9Sstevel@tonic-gate  *
757c478bd9Sstevel@tonic-gate  * Context:
767c478bd9Sstevel@tonic-gate  *	Process and interruption.
777c478bd9Sstevel@tonic-gate  *
787c478bd9Sstevel@tonic-gate  * Returns:
797c478bd9Sstevel@tonic-gate  *	The unique mechanism identified by 'mechname', if found.
807c478bd9Sstevel@tonic-gate  *	CRYPTO_MECH_INVALID otherwise.
817c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate crypto_mech_type_t
837c478bd9Sstevel@tonic-gate crypto_mech2id(char *mechname)
847c478bd9Sstevel@tonic-gate {
857c478bd9Sstevel@tonic-gate 	return (crypto_mech2id_common(mechname, B_TRUE));
867c478bd9Sstevel@tonic-gate }
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate /*
897c478bd9Sstevel@tonic-gate  * crypto_get_mech_list()
907c478bd9Sstevel@tonic-gate  *
917c478bd9Sstevel@tonic-gate  * Arguments:
927c478bd9Sstevel@tonic-gate  *	. countp: pointer to contain the number of mech names returned
937c478bd9Sstevel@tonic-gate  *	. kmflag: memory allocation flag.
947c478bd9Sstevel@tonic-gate  *
957c478bd9Sstevel@tonic-gate  * Description:
967c478bd9Sstevel@tonic-gate  *	Allocates an array of crypto_mech_name_t containing all the mechanisms
977c478bd9Sstevel@tonic-gate  *	currently available on the system. Sets *countp with the number of
987c478bd9Sstevel@tonic-gate  *	mechanism names returned.
997c478bd9Sstevel@tonic-gate  *
1007c478bd9Sstevel@tonic-gate  *	We get a list of mech names which have a hardware provider by walking
1017c478bd9Sstevel@tonic-gate  *	all the mechanism tables. We merge them with mech names obtained from
1027c478bd9Sstevel@tonic-gate  *	the hint list. A mech name in the hint list is considered only if it
1037c478bd9Sstevel@tonic-gate  *	is not disabled for the provider. Note that the hint list contains only
1047c478bd9Sstevel@tonic-gate  *	software providers and the mech names supported by them.
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  * Context:
1077c478bd9Sstevel@tonic-gate  *	Process and interruption. kmflag should be KM_NOSLEEP when called
1087c478bd9Sstevel@tonic-gate  *	from an interruption context.
1097c478bd9Sstevel@tonic-gate  *
1107c478bd9Sstevel@tonic-gate  * Returns:
1117c478bd9Sstevel@tonic-gate  *	The array of the crypto_mech_t allocated.
1127c478bd9Sstevel@tonic-gate  *	NULL otherwise.
1137c478bd9Sstevel@tonic-gate  */
1147c478bd9Sstevel@tonic-gate crypto_mech_name_t *
1157c478bd9Sstevel@tonic-gate crypto_get_mech_list(uint_t *countp, int kmflag)
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate 	uint_t count = 0, me_tab_size, i, j;
1187c478bd9Sstevel@tonic-gate 	kcf_ops_class_t cl;
1197c478bd9Sstevel@tonic-gate 	kcf_mech_entry_t *me, *me_tab;
1207c478bd9Sstevel@tonic-gate 	crypto_mech_name_t *mech_name_tab, *tmp_mech_name_tab;
1217c478bd9Sstevel@tonic-gate 	char *mech_name, *hint_mech, *end;
1227c478bd9Sstevel@tonic-gate 	kcf_soft_conf_entry_t *p;
1237c478bd9Sstevel@tonic-gate 	size_t n;
124ef56a3c5SKrishna Yenduri 	kcf_lock_withpad_t *mp;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	/*
1277c478bd9Sstevel@tonic-gate 	 * Count the maximum possible mechanisms that can come from the
1287c478bd9Sstevel@tonic-gate 	 * hint list.
1297c478bd9Sstevel@tonic-gate 	 */
1307c478bd9Sstevel@tonic-gate 	mutex_enter(&soft_config_mutex);
1317c478bd9Sstevel@tonic-gate 	p = soft_config_list;
1327c478bd9Sstevel@tonic-gate 	while (p != NULL) {
1337c478bd9Sstevel@tonic-gate 		count += p->ce_count;
1347c478bd9Sstevel@tonic-gate 		p = p->ce_next;
1357c478bd9Sstevel@tonic-gate 	}
1367c478bd9Sstevel@tonic-gate 	mutex_exit(&soft_config_mutex);
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	/* First let's count'em, for mem allocation */
1397c478bd9Sstevel@tonic-gate 	for (cl = KCF_FIRST_OPSCLASS; cl <= KCF_LAST_OPSCLASS; cl++) {
1407c478bd9Sstevel@tonic-gate 		me_tab_size = kcf_mech_tabs_tab[cl].met_size;
1417c478bd9Sstevel@tonic-gate 		me_tab = kcf_mech_tabs_tab[cl].met_tab;
1427c478bd9Sstevel@tonic-gate 		for (i = 0; i < me_tab_size; i++) {
1437c478bd9Sstevel@tonic-gate 			me = &me_tab[i];
144ef56a3c5SKrishna Yenduri 			mp = &me_mutexes[CPU_SEQID];
145ef56a3c5SKrishna Yenduri 			mutex_enter(&mp->kl_lock);
1467c478bd9Sstevel@tonic-gate 			if ((me->me_name[0] != 0) && (me->me_num_hwprov >= 1)) {
1477c478bd9Sstevel@tonic-gate 				ASSERT(me->me_hw_prov_chain != NULL);
1487c478bd9Sstevel@tonic-gate 				count++;
1497c478bd9Sstevel@tonic-gate 			}
150ef56a3c5SKrishna Yenduri 			mutex_exit(&mp->kl_lock);
1517c478bd9Sstevel@tonic-gate 		}
1527c478bd9Sstevel@tonic-gate 	}
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	/*
1557c478bd9Sstevel@tonic-gate 	 * Allocate a buffer to hold the mechanisms from
1567c478bd9Sstevel@tonic-gate 	 * mech tabs and mechanisms from the hint list.
1577c478bd9Sstevel@tonic-gate 	 */
1587c478bd9Sstevel@tonic-gate 	n = count * CRYPTO_MAX_MECH_NAME;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate again:
1617c478bd9Sstevel@tonic-gate 	count = 0;
1627c478bd9Sstevel@tonic-gate 	tmp_mech_name_tab = kmem_zalloc(n, kmflag);
1637c478bd9Sstevel@tonic-gate 	if (tmp_mech_name_tab == NULL) {
1647c478bd9Sstevel@tonic-gate 		*countp = 0;
1657c478bd9Sstevel@tonic-gate 		return (NULL);
1667c478bd9Sstevel@tonic-gate 	}
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	/*
1697c478bd9Sstevel@tonic-gate 	 * Second round, fill in the table
1707c478bd9Sstevel@tonic-gate 	 */
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	mech_name = (char *)tmp_mech_name_tab;
1737c478bd9Sstevel@tonic-gate 	end = mech_name + n;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	for (cl = KCF_FIRST_OPSCLASS; cl <= KCF_LAST_OPSCLASS; cl++) {
1767c478bd9Sstevel@tonic-gate 		me_tab_size = kcf_mech_tabs_tab[cl].met_size;
1777c478bd9Sstevel@tonic-gate 		me_tab = kcf_mech_tabs_tab[cl].met_tab;
1787c478bd9Sstevel@tonic-gate 		for (i = 0; i < me_tab_size; i++) {
1797c478bd9Sstevel@tonic-gate 			me = &me_tab[i];
180ef56a3c5SKrishna Yenduri 			mp = &me_mutexes[CPU_SEQID];
181ef56a3c5SKrishna Yenduri 			mutex_enter(&mp->kl_lock);
1827c478bd9Sstevel@tonic-gate 			if ((me->me_name[0] != 0) && (me->me_num_hwprov >= 1)) {
1837c478bd9Sstevel@tonic-gate 				ASSERT(me->me_hw_prov_chain != NULL);
1847c478bd9Sstevel@tonic-gate 				if ((mech_name + CRYPTO_MAX_MECH_NAME) > end) {
185ef56a3c5SKrishna Yenduri 					mutex_exit(&mp->kl_lock);
1867c478bd9Sstevel@tonic-gate 					kmem_free(tmp_mech_name_tab, n);
1877c478bd9Sstevel@tonic-gate 					n = n << 1;
1887c478bd9Sstevel@tonic-gate 					goto again;
1897c478bd9Sstevel@tonic-gate 				}
1907c478bd9Sstevel@tonic-gate 				(void) strncpy(mech_name, me->me_name,
1917c478bd9Sstevel@tonic-gate 				    CRYPTO_MAX_MECH_NAME);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 				mech_name += CRYPTO_MAX_MECH_NAME;
1947c478bd9Sstevel@tonic-gate 				count++;
1957c478bd9Sstevel@tonic-gate 			}
196ef56a3c5SKrishna Yenduri 			mutex_exit(&mp->kl_lock);
1977c478bd9Sstevel@tonic-gate 		}
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	/*
2017c478bd9Sstevel@tonic-gate 	 * Search tmp_mech_name_tab for each mechanism in the hint list. We
2027c478bd9Sstevel@tonic-gate 	 * have to add any new mechanisms found in the hint list. Note that we
2037c478bd9Sstevel@tonic-gate 	 * should not modload the providers here as it will be too early. It
2047c478bd9Sstevel@tonic-gate 	 * may be the case that the caller never uses a provider.
2057c478bd9Sstevel@tonic-gate 	 */
2067c478bd9Sstevel@tonic-gate 	mutex_enter(&soft_config_mutex);
2077c478bd9Sstevel@tonic-gate 	p = soft_config_list;
2087c478bd9Sstevel@tonic-gate 	while (p != NULL) {
2097c478bd9Sstevel@tonic-gate 		for (i = 0; i < p->ce_count; i++) {
2107c478bd9Sstevel@tonic-gate 			hint_mech = p->ce_mechs[i];
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 			/* Do not consider the mechanism if it is disabled. */
2137c478bd9Sstevel@tonic-gate 			if (is_mech_disabled_byname(CRYPTO_SW_PROVIDER,
2147c478bd9Sstevel@tonic-gate 			    p->ce_name, 0, hint_mech))
2157c478bd9Sstevel@tonic-gate 				continue;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 			/*
2187c478bd9Sstevel@tonic-gate 			 * There may be duplicate mechanisms in the hint list.
2197c478bd9Sstevel@tonic-gate 			 * So, we need to search all the entries that have been
2207c478bd9Sstevel@tonic-gate 			 * added so far. That number would be count.
2217c478bd9Sstevel@tonic-gate 			 */
2227c478bd9Sstevel@tonic-gate 			for (j = 0; j < count; j++) {
2237c478bd9Sstevel@tonic-gate 				if (strcmp(hint_mech,
2247c478bd9Sstevel@tonic-gate 				    tmp_mech_name_tab[j]) == 0)
2257c478bd9Sstevel@tonic-gate 					break;
2267c478bd9Sstevel@tonic-gate 			}
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 			if (j == count) {	/* This is a new one. Add it. */
2297c478bd9Sstevel@tonic-gate 				ASSERT((char *)&tmp_mech_name_tab[count] ==
2307c478bd9Sstevel@tonic-gate 				    mech_name);
2317c478bd9Sstevel@tonic-gate 				if ((mech_name + CRYPTO_MAX_MECH_NAME) > end) {
2327c478bd9Sstevel@tonic-gate 					mutex_exit(&soft_config_mutex);
2337c478bd9Sstevel@tonic-gate 					kmem_free(tmp_mech_name_tab, n);
2347c478bd9Sstevel@tonic-gate 					n = n << 1;
2357c478bd9Sstevel@tonic-gate 					goto again;
2367c478bd9Sstevel@tonic-gate 				}
2377c478bd9Sstevel@tonic-gate 				(void) strncpy(tmp_mech_name_tab[count],
2387c478bd9Sstevel@tonic-gate 				    hint_mech, CRYPTO_MAX_MECH_NAME);
2397c478bd9Sstevel@tonic-gate 				mech_name += CRYPTO_MAX_MECH_NAME;
2407c478bd9Sstevel@tonic-gate 				count++;
2417c478bd9Sstevel@tonic-gate 			}
2427c478bd9Sstevel@tonic-gate 		}
2437c478bd9Sstevel@tonic-gate 		p = p->ce_next;
2447c478bd9Sstevel@tonic-gate 	}
2457c478bd9Sstevel@tonic-gate 	mutex_exit(&soft_config_mutex);
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	/*
2487c478bd9Sstevel@tonic-gate 	 * Check if we have consumed all of the space. We are done if
2497c478bd9Sstevel@tonic-gate 	 * this is the case.
2507c478bd9Sstevel@tonic-gate 	 */
2517c478bd9Sstevel@tonic-gate 	ASSERT(mech_name <= end);
2527c478bd9Sstevel@tonic-gate 	if (mech_name == end) {
2537c478bd9Sstevel@tonic-gate 		mech_name_tab = tmp_mech_name_tab;
2547c478bd9Sstevel@tonic-gate 		goto done;
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	/*
2587c478bd9Sstevel@tonic-gate 	 * Allocate a buffer of the right size now that we have the
2597c478bd9Sstevel@tonic-gate 	 * correct count.
2607c478bd9Sstevel@tonic-gate 	 */
2617c478bd9Sstevel@tonic-gate 	mech_name_tab = kmem_zalloc(count * CRYPTO_MAX_MECH_NAME, kmflag);
2627c478bd9Sstevel@tonic-gate 	if (mech_name_tab == NULL) {
2637c478bd9Sstevel@tonic-gate 		kmem_free(tmp_mech_name_tab, n);
2647c478bd9Sstevel@tonic-gate 		*countp = 0;
2657c478bd9Sstevel@tonic-gate 		return (NULL);
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	bcopy(tmp_mech_name_tab, mech_name_tab, count * CRYPTO_MAX_MECH_NAME);
2697c478bd9Sstevel@tonic-gate 	kmem_free(tmp_mech_name_tab, n);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate done:
2727c478bd9Sstevel@tonic-gate 	*countp = count;
2737c478bd9Sstevel@tonic-gate 	return (mech_name_tab);
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate /*
2777c478bd9Sstevel@tonic-gate  * crypto_free_mech_list()
2787c478bd9Sstevel@tonic-gate  *
2797c478bd9Sstevel@tonic-gate  * Arguments:
2807c478bd9Sstevel@tonic-gate  *	. mech_names: An array of crypto_mech_name_t previously allocated by
2817c478bd9Sstevel@tonic-gate  *	  crypto_get_mech_list.
2827c478bd9Sstevel@tonic-gate  *	. count: the number of mech names in mech_names
2837c478bd9Sstevel@tonic-gate  *
2847c478bd9Sstevel@tonic-gate  * Description:
2857c478bd9Sstevel@tonic-gate  *	Frees the the mech_names array.
2867c478bd9Sstevel@tonic-gate  *
2877c478bd9Sstevel@tonic-gate  * Context:
2887c478bd9Sstevel@tonic-gate  *	Process and interruption.
2897c478bd9Sstevel@tonic-gate  */
2907c478bd9Sstevel@tonic-gate void
2917c478bd9Sstevel@tonic-gate crypto_free_mech_list(crypto_mech_name_t *mech_names, uint_t count)
2927c478bd9Sstevel@tonic-gate {
2937c478bd9Sstevel@tonic-gate 	if ((mech_names != NULL) && (count > 0))
2947c478bd9Sstevel@tonic-gate 		kmem_free(mech_names, count * CRYPTO_MAX_MECH_NAME);
2957c478bd9Sstevel@tonic-gate }
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate /*
2987c478bd9Sstevel@tonic-gate  * crypto_notify_events()
2997c478bd9Sstevel@tonic-gate  *
3007c478bd9Sstevel@tonic-gate  * Arguments:
3017c478bd9Sstevel@tonic-gate  *	. nf: Callback function to invoke when event occurs.
3027c478bd9Sstevel@tonic-gate  *	. event_mask: Mask of events.
3037c478bd9Sstevel@tonic-gate  *
3047c478bd9Sstevel@tonic-gate  * Description:
3057c478bd9Sstevel@tonic-gate  *	Allocates a new element and inserts it in to the notification
3067c478bd9Sstevel@tonic-gate  *	list.
3077c478bd9Sstevel@tonic-gate  *
3087c478bd9Sstevel@tonic-gate  * Context:
3097c478bd9Sstevel@tonic-gate  *	Process context.
3107c478bd9Sstevel@tonic-gate  *
3117c478bd9Sstevel@tonic-gate  * Returns:
3127c478bd9Sstevel@tonic-gate  *	A handle is returned if the client is put on the notification list.
3137c478bd9Sstevel@tonic-gate  *	NULL is returned otherwise.
3147c478bd9Sstevel@tonic-gate  */
3157c478bd9Sstevel@tonic-gate crypto_notify_handle_t
3167c478bd9Sstevel@tonic-gate crypto_notify_events(crypto_notify_callback_t nf, uint32_t event_mask)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate 	kcf_ntfy_elem_t *nep;
3197c478bd9Sstevel@tonic-gate 	crypto_notify_handle_t hndl;
3207c478bd9Sstevel@tonic-gate 
321c892ebf1Skrishna 	/* Check the input */
322c892ebf1Skrishna 	if (nf == NULL || !(event_mask & (CRYPTO_EVENT_MECHS_CHANGED |
323c892ebf1Skrishna 	    CRYPTO_EVENT_PROVIDER_REGISTERED |
324c892ebf1Skrishna 	    CRYPTO_EVENT_PROVIDER_UNREGISTERED))) {
3257c478bd9Sstevel@tonic-gate 		return (NULL);
3267c478bd9Sstevel@tonic-gate 	}
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	nep = kmem_zalloc(sizeof (kcf_ntfy_elem_t), KM_SLEEP);
3297c478bd9Sstevel@tonic-gate 	mutex_init(&nep->kn_lock, NULL, MUTEX_DEFAULT, NULL);
3307c478bd9Sstevel@tonic-gate 	cv_init(&nep->kn_cv, NULL, CV_DEFAULT, NULL);
3317c478bd9Sstevel@tonic-gate 	nep->kn_state = NTFY_WAITING;
3327c478bd9Sstevel@tonic-gate 	nep->kn_func = nf;
3337c478bd9Sstevel@tonic-gate 	nep->kn_event_mask = event_mask;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	mutex_enter(&ntfy_list_lock);
3367c478bd9Sstevel@tonic-gate 	if (ntfy_list_head == NULL) {
3377c478bd9Sstevel@tonic-gate 		ntfy_list_head = ntfy_list_tail = nep;
3387c478bd9Sstevel@tonic-gate 	} else {
3397c478bd9Sstevel@tonic-gate 		ntfy_list_tail->kn_next = nep;
3407c478bd9Sstevel@tonic-gate 		nep->kn_prev = ntfy_list_tail;
3417c478bd9Sstevel@tonic-gate 		ntfy_list_tail = nep;
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	hndl = (crypto_notify_handle_t)nep;
3457c478bd9Sstevel@tonic-gate 	mutex_exit(&ntfy_list_lock);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	return (hndl);
3487c478bd9Sstevel@tonic-gate }
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate /*
3517c478bd9Sstevel@tonic-gate  * crypto_unnotify_events()
3527c478bd9Sstevel@tonic-gate  *
3537c478bd9Sstevel@tonic-gate  * Arguments:
3547c478bd9Sstevel@tonic-gate  *	. hndl - Handle returned from an earlier crypto_notify_events().
3557c478bd9Sstevel@tonic-gate  *
3567c478bd9Sstevel@tonic-gate  * Description:
3577c478bd9Sstevel@tonic-gate  *	Removes the element specified by hndl from the notification list.
3587c478bd9Sstevel@tonic-gate  *	We wait for the notification routine to complete, if the routine
3597c478bd9Sstevel@tonic-gate  *	is currently being called. We also free the element.
3607c478bd9Sstevel@tonic-gate  *
3617c478bd9Sstevel@tonic-gate  * Context:
3627c478bd9Sstevel@tonic-gate  *	Process context.
3637c478bd9Sstevel@tonic-gate  */
3647c478bd9Sstevel@tonic-gate void
3657c478bd9Sstevel@tonic-gate crypto_unnotify_events(crypto_notify_handle_t hndl)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 	kcf_ntfy_elem_t *nep = (kcf_ntfy_elem_t *)hndl;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	if (hndl == NULL)
3707c478bd9Sstevel@tonic-gate 		return;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate retry:
3737c478bd9Sstevel@tonic-gate 	mutex_enter(&ntfy_list_lock);
3747c478bd9Sstevel@tonic-gate 	mutex_enter(&nep->kn_lock);
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	if (nep->kn_state == NTFY_WAITING) {
3777c478bd9Sstevel@tonic-gate 		kcf_ntfy_elem_t *nextp = nep->kn_next;
3787c478bd9Sstevel@tonic-gate 		kcf_ntfy_elem_t *prevp = nep->kn_prev;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 		if (nextp != NULL)
3817c478bd9Sstevel@tonic-gate 			nextp->kn_prev = prevp;
3827c478bd9Sstevel@tonic-gate 		else
3837c478bd9Sstevel@tonic-gate 			ntfy_list_tail = prevp;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 		if (prevp != NULL)
3867c478bd9Sstevel@tonic-gate 			prevp->kn_next = nextp;
3877c478bd9Sstevel@tonic-gate 		else
3887c478bd9Sstevel@tonic-gate 			ntfy_list_head = nextp;
3897c478bd9Sstevel@tonic-gate 	} else {
3907c478bd9Sstevel@tonic-gate 		ASSERT(nep->kn_state == NTFY_RUNNING);
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 		/*
3937c478bd9Sstevel@tonic-gate 		 * We have to drop this lock as the client might call
3947c478bd9Sstevel@tonic-gate 		 * crypto_notify_events() in the callback routine resulting
3957c478bd9Sstevel@tonic-gate 		 * in a deadlock.
3967c478bd9Sstevel@tonic-gate 		 */
3977c478bd9Sstevel@tonic-gate 		mutex_exit(&ntfy_list_lock);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 		/*
4007c478bd9Sstevel@tonic-gate 		 * Another thread is working on this element. We will wait
4017c478bd9Sstevel@tonic-gate 		 * for that thread to signal us when done. No other thread
4027c478bd9Sstevel@tonic-gate 		 * will free this element. So, we can be sure it stays valid
4037c478bd9Sstevel@tonic-gate 		 * after the wait.
4047c478bd9Sstevel@tonic-gate 		 */
4057c478bd9Sstevel@tonic-gate 		while (nep->kn_state == NTFY_RUNNING)
4067c478bd9Sstevel@tonic-gate 			cv_wait(&nep->kn_cv, &nep->kn_lock);
4077c478bd9Sstevel@tonic-gate 		mutex_exit(&nep->kn_lock);
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 		/*
4107c478bd9Sstevel@tonic-gate 		 * We have to remove the element from the notification list.
4117c478bd9Sstevel@tonic-gate 		 * So, start over and do the work (acquire locks etc.). This is
4127c478bd9Sstevel@tonic-gate 		 * safe (i.e. We won't be in this routine forever) as the
413c892ebf1Skrishna 		 * events do not happen frequently. We have to revisit this
414c892ebf1Skrishna 		 * code if we add a new event that happens often.
4157c478bd9Sstevel@tonic-gate 		 */
4167c478bd9Sstevel@tonic-gate 		goto retry;
4177c478bd9Sstevel@tonic-gate 	}
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	mutex_exit(&nep->kn_lock);
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	/* Free the element */
4227c478bd9Sstevel@tonic-gate 	mutex_destroy(&nep->kn_lock);
4237c478bd9Sstevel@tonic-gate 	cv_destroy(&nep->kn_cv);
4247c478bd9Sstevel@tonic-gate 	kmem_free(nep, sizeof (kcf_ntfy_elem_t));
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	mutex_exit(&ntfy_list_lock);
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate /*
4307c478bd9Sstevel@tonic-gate  * We walk the notification list and do the callbacks.
4317c478bd9Sstevel@tonic-gate  */
4327c478bd9Sstevel@tonic-gate void
4337c478bd9Sstevel@tonic-gate kcf_walk_ntfylist(uint32_t event, void *event_arg)
4347c478bd9Sstevel@tonic-gate {
4357c478bd9Sstevel@tonic-gate 	kcf_ntfy_elem_t *nep;
4367c478bd9Sstevel@tonic-gate 	int nelem = 0;
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	mutex_enter(&ntfy_list_lock);
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	/*
4417c478bd9Sstevel@tonic-gate 	 * Count how many clients are on the notification list. We need
4427c478bd9Sstevel@tonic-gate 	 * this count to ensure that clients which joined the list after we
4437c478bd9Sstevel@tonic-gate 	 * have started this walk, are not wrongly notified.
4447c478bd9Sstevel@tonic-gate 	 */
4457c478bd9Sstevel@tonic-gate 	for (nep = ntfy_list_head; nep != NULL; nep = nep->kn_next)
4467c478bd9Sstevel@tonic-gate 		nelem++;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	for (nep = ntfy_list_head; (nep != NULL && nelem); nep = nep->kn_next) {
4497c478bd9Sstevel@tonic-gate 		nelem--;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 		/*
4527c478bd9Sstevel@tonic-gate 		 * Check if this client is interested in the
4537c478bd9Sstevel@tonic-gate 		 * event.
4547c478bd9Sstevel@tonic-gate 		 */
4557c478bd9Sstevel@tonic-gate 		if (!(nep->kn_event_mask & event))
4567c478bd9Sstevel@tonic-gate 			continue;
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 		mutex_enter(&nep->kn_lock);
4597c478bd9Sstevel@tonic-gate 		nep->kn_state = NTFY_RUNNING;
4607c478bd9Sstevel@tonic-gate 		mutex_exit(&nep->kn_lock);
4617c478bd9Sstevel@tonic-gate 		mutex_exit(&ntfy_list_lock);
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 		/*
4647c478bd9Sstevel@tonic-gate 		 * We invoke the callback routine with no locks held. Another
4657c478bd9Sstevel@tonic-gate 		 * client could have joined the list meanwhile. This is fine
4667c478bd9Sstevel@tonic-gate 		 * as we maintain nelem as stated above. The NULL check in the
4677c478bd9Sstevel@tonic-gate 		 * for loop guards against shrinkage. Also, any callers of
4687c478bd9Sstevel@tonic-gate 		 * crypto_unnotify_events() at this point cv_wait till kn_state
4697c478bd9Sstevel@tonic-gate 		 * changes to NTFY_WAITING. Hence, nep is assured to be valid.
4707c478bd9Sstevel@tonic-gate 		 */
4717c478bd9Sstevel@tonic-gate 		(*nep->kn_func)(event, event_arg);
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 		mutex_enter(&nep->kn_lock);
4747c478bd9Sstevel@tonic-gate 		nep->kn_state = NTFY_WAITING;
4757c478bd9Sstevel@tonic-gate 		cv_broadcast(&nep->kn_cv);
4767c478bd9Sstevel@tonic-gate 		mutex_exit(&nep->kn_lock);
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 		mutex_enter(&ntfy_list_lock);
4797c478bd9Sstevel@tonic-gate 	}
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	mutex_exit(&ntfy_list_lock);
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate /*
4857c478bd9Sstevel@tonic-gate  * crypto_key_check()
4867c478bd9Sstevel@tonic-gate  *
4877c478bd9Sstevel@tonic-gate  * Arguments:
4887c478bd9Sstevel@tonic-gate  *	. mech: the mechanism to check the key with.
4897c478bd9Sstevel@tonic-gate  *	. key: the key to check for validity and weakness.
4907c478bd9Sstevel@tonic-gate  *
4917c478bd9Sstevel@tonic-gate  * Description:
4927c478bd9Sstevel@tonic-gate  *	Checks the validity and strength of the key for the mechanism.
4937c478bd9Sstevel@tonic-gate  *	CRYPTO_KEY_REFERENCE is not supported for this routine.
4947c478bd9Sstevel@tonic-gate  *	If more than one provider is capable of key checking for the mechanism,
4957c478bd9Sstevel@tonic-gate  *	then run the key through them all.
4967c478bd9Sstevel@tonic-gate  *	A conservative approach is adopted here: New weak keys may be
4977c478bd9Sstevel@tonic-gate  *	discovered with more recent providers. If at least one provider is
4987c478bd9Sstevel@tonic-gate  *	not happy with a key, then it is no good.
4997c478bd9Sstevel@tonic-gate  *
5007c478bd9Sstevel@tonic-gate  * Context:
5017c478bd9Sstevel@tonic-gate  *	Process and interruption.
5027c478bd9Sstevel@tonic-gate  */
5037c478bd9Sstevel@tonic-gate int
5047c478bd9Sstevel@tonic-gate crypto_key_check(crypto_mechanism_t *mech, crypto_key_t *key)
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate 	int error;
5077c478bd9Sstevel@tonic-gate 	kcf_mech_entry_t *me;
5087c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *pd;
5097c478bd9Sstevel@tonic-gate 	kcf_prov_mech_desc_t *prov_chain;
510ef56a3c5SKrishna Yenduri 	kcf_lock_withpad_t *mp;
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	/* when mech is a valid mechanism, me will be its mech_entry */
5137c478bd9Sstevel@tonic-gate 	if ((mech == NULL) || (key == NULL) ||
5147c478bd9Sstevel@tonic-gate 	    (key->ck_format == CRYPTO_KEY_REFERENCE))
5157c478bd9Sstevel@tonic-gate 		return (CRYPTO_ARGUMENTS_BAD);
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	if ((error = kcf_get_mech_entry(mech->cm_type, &me)) != KCF_SUCCESS) {
5187c478bd9Sstevel@tonic-gate 		/* error is one of the KCF_INVALID_MECH_XXX's */
5197c478bd9Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
5207c478bd9Sstevel@tonic-gate 	}
5217c478bd9Sstevel@tonic-gate 
522ef56a3c5SKrishna Yenduri 	mp = &me_mutexes[CPU_SEQID];
523ef56a3c5SKrishna Yenduri 	mutex_enter(&mp->kl_lock);
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	/* First let the software provider check this key */
5267c478bd9Sstevel@tonic-gate 	if (me->me_sw_prov != NULL) {
5277c478bd9Sstevel@tonic-gate 		pd = me->me_sw_prov->pm_prov_desc;
5287c478bd9Sstevel@tonic-gate 		KCF_PROV_REFHOLD(pd);
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 		if ((KCF_PROV_KEY_OPS(pd) != NULL) &&
5317c478bd9Sstevel@tonic-gate 		    (KCF_PROV_KEY_OPS(pd)->key_check != NULL)) {
5327c478bd9Sstevel@tonic-gate 			crypto_mechanism_t lmech;
5337c478bd9Sstevel@tonic-gate 
534ef56a3c5SKrishna Yenduri 			mutex_exit(&mp->kl_lock);
5357c478bd9Sstevel@tonic-gate 			lmech = *mech;
5367c478bd9Sstevel@tonic-gate 			KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
5377c478bd9Sstevel@tonic-gate 			error = KCF_PROV_KEY_CHECK(pd, &lmech, key);
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 			if (error != CRYPTO_SUCCESS) {
5407c478bd9Sstevel@tonic-gate 				KCF_PROV_REFRELE(pd);
5417c478bd9Sstevel@tonic-gate 				return (error);
5427c478bd9Sstevel@tonic-gate 			}
5437c478bd9Sstevel@tonic-gate 
544ef56a3c5SKrishna Yenduri 			mutex_enter(&mp->kl_lock);
5457c478bd9Sstevel@tonic-gate 		}
5467c478bd9Sstevel@tonic-gate 		KCF_PROV_REFRELE(pd);
5477c478bd9Sstevel@tonic-gate 	}
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	prov_chain = me->me_hw_prov_chain;
5507c478bd9Sstevel@tonic-gate 	while (prov_chain != NULL) {
5517c478bd9Sstevel@tonic-gate 		pd = prov_chain->pm_prov_desc;
5527c478bd9Sstevel@tonic-gate 		KCF_PROV_REFHOLD(pd);
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 		if ((KCF_PROV_KEY_OPS(pd) != NULL) &&
5557c478bd9Sstevel@tonic-gate 		    (KCF_PROV_KEY_OPS(pd)->key_check != NULL)) {
5567c478bd9Sstevel@tonic-gate 			crypto_mechanism_t lmech;
5577c478bd9Sstevel@tonic-gate 
558ef56a3c5SKrishna Yenduri 			mutex_exit(&mp->kl_lock);
5597c478bd9Sstevel@tonic-gate 			lmech = *mech;
5607c478bd9Sstevel@tonic-gate 			KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd,
5617c478bd9Sstevel@tonic-gate 			    &lmech);
5627c478bd9Sstevel@tonic-gate 			error = KCF_PROV_KEY_CHECK(pd, &lmech, key);
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 			if (error != CRYPTO_SUCCESS) {
5657c478bd9Sstevel@tonic-gate 				KCF_PROV_REFRELE(pd);
5667c478bd9Sstevel@tonic-gate 				return (error);
5677c478bd9Sstevel@tonic-gate 			}
568ef56a3c5SKrishna Yenduri 			mutex_enter(&mp->kl_lock);
5697c478bd9Sstevel@tonic-gate 		}
5707c478bd9Sstevel@tonic-gate 		KCF_PROV_REFRELE(pd);
5717c478bd9Sstevel@tonic-gate 		prov_chain = prov_chain->pm_next;
5727c478bd9Sstevel@tonic-gate 	}
5737c478bd9Sstevel@tonic-gate 
574ef56a3c5SKrishna Yenduri 	mutex_exit(&mp->kl_lock);
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	/* All are happy with this key */
5777c478bd9Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate 
580894b2776Smcpowers int
581894b2776Smcpowers crypto_key_check_prov(crypto_provider_t provider, crypto_mechanism_t *mech,
582894b2776Smcpowers     crypto_key_t *key)
583894b2776Smcpowers {
584894b2776Smcpowers 	kcf_provider_desc_t *pd = provider;
585894b2776Smcpowers 	kcf_provider_desc_t *real_provider = pd;
586894b2776Smcpowers 	crypto_mechanism_t lmech;
587894b2776Smcpowers 	int rv;
588894b2776Smcpowers 
589894b2776Smcpowers 	ASSERT(KCF_PROV_REFHELD(pd));
590894b2776Smcpowers 
591894b2776Smcpowers 	if ((mech == NULL) || (key == NULL) ||
592894b2776Smcpowers 	    (key->ck_format == CRYPTO_KEY_REFERENCE))
593894b2776Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
594894b2776Smcpowers 
59572eff6e2Smcpowers 	/* no logical providers currently support the key check */
596894b2776Smcpowers 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
59772eff6e2Smcpowers 		return (CRYPTO_NOT_SUPPORTED);
598894b2776Smcpowers 	}
599894b2776Smcpowers 
600894b2776Smcpowers 	lmech = *mech;
601894b2776Smcpowers 	KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
602894b2776Smcpowers 	rv = KCF_PROV_KEY_CHECK(real_provider, &lmech, key);
603894b2776Smcpowers 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
604894b2776Smcpowers 		KCF_PROV_REFRELE(real_provider);
605894b2776Smcpowers 
606894b2776Smcpowers 	return (rv);
607894b2776Smcpowers }
608894b2776Smcpowers 
6097c478bd9Sstevel@tonic-gate /*
6107c478bd9Sstevel@tonic-gate  * Initialize the specified crypto_mechanism_info_t structure for
6117c478bd9Sstevel@tonic-gate  * the specified mechanism provider descriptor. Used by
6127c478bd9Sstevel@tonic-gate  * crypto_get_all_mech_info().
6137c478bd9Sstevel@tonic-gate  */
6147c478bd9Sstevel@tonic-gate static void
6157c478bd9Sstevel@tonic-gate init_mechanism_info(crypto_mechanism_info_t *mech_info,
6167c478bd9Sstevel@tonic-gate     kcf_prov_mech_desc_t *pmd)
6177c478bd9Sstevel@tonic-gate {
6187c478bd9Sstevel@tonic-gate 	crypto_func_group_t fg = pmd->pm_mech_info.cm_func_group_mask;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	/* min/max key sizes */
6216a1073f8Skrishna 	mech_info->mi_keysize_unit = pmd->pm_mech_info.cm_mech_flags &
6226a1073f8Skrishna 	    (CRYPTO_KEYSIZE_UNIT_IN_BITS | CRYPTO_KEYSIZE_UNIT_IN_BYTES);
6237c478bd9Sstevel@tonic-gate 	mech_info->mi_min_key_size =
6247c478bd9Sstevel@tonic-gate 	    (size_t)pmd->pm_mech_info.cm_min_key_length;
6257c478bd9Sstevel@tonic-gate 	mech_info->mi_max_key_size =
6267c478bd9Sstevel@tonic-gate 	    (size_t)pmd->pm_mech_info.cm_max_key_length;
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	/* usage flag */
6297c478bd9Sstevel@tonic-gate 	mech_info->mi_usage = 0;
6307c478bd9Sstevel@tonic-gate 	if (fg & (CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC))
6317c478bd9Sstevel@tonic-gate 		mech_info->mi_usage |= CRYPTO_MECH_USAGE_ENCRYPT;
6327c478bd9Sstevel@tonic-gate 	if (fg & (CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC))
6337c478bd9Sstevel@tonic-gate 		mech_info->mi_usage |= CRYPTO_MECH_USAGE_DECRYPT;
6347c478bd9Sstevel@tonic-gate 	if (fg & (CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC))
6357c478bd9Sstevel@tonic-gate 		mech_info->mi_usage |= CRYPTO_MECH_USAGE_MAC;
6367c478bd9Sstevel@tonic-gate }
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate /*
6397c478bd9Sstevel@tonic-gate  * Return the mechanism info for the specified mechanism.
6407c478bd9Sstevel@tonic-gate  */
6417c478bd9Sstevel@tonic-gate int
6427c478bd9Sstevel@tonic-gate crypto_get_all_mech_info(crypto_mech_type_t mech_type,
6437c478bd9Sstevel@tonic-gate     crypto_mechanism_info_t **mech_infos, uint_t *num_mech_infos,
6447c478bd9Sstevel@tonic-gate     int km_flag)
6457c478bd9Sstevel@tonic-gate {
6467c478bd9Sstevel@tonic-gate 	uint_t ninfos, cur_info;
6477c478bd9Sstevel@tonic-gate 	kcf_mech_entry_t *me;
6487c478bd9Sstevel@tonic-gate 	int rv;
6497c478bd9Sstevel@tonic-gate 	kcf_prov_mech_desc_t *hwp;
6507c478bd9Sstevel@tonic-gate 	crypto_mechanism_info_t *infos;
6517c478bd9Sstevel@tonic-gate 	size_t infos_size;
652ef56a3c5SKrishna Yenduri 	kcf_lock_withpad_t *mp;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	/* get to the mech entry corresponding to the specified mech type */
6557c478bd9Sstevel@tonic-gate 	if ((rv = kcf_get_mech_entry(mech_type, &me)) != CRYPTO_SUCCESS) {
6567c478bd9Sstevel@tonic-gate 		return (rv);
6577c478bd9Sstevel@tonic-gate 	}
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 	/* compute the number of key size ranges to return */
660ef56a3c5SKrishna Yenduri 	mp = &me_mutexes[CPU_SEQID];
661ef56a3c5SKrishna Yenduri 	mutex_enter(&mp->kl_lock);
6627c478bd9Sstevel@tonic-gate again:
6637c478bd9Sstevel@tonic-gate 	ninfos = PROV_COUNT(me);
664ef56a3c5SKrishna Yenduri 	mutex_exit(&mp->kl_lock);
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	if (ninfos == 0) {
6677c478bd9Sstevel@tonic-gate 		infos = NULL;
6687c478bd9Sstevel@tonic-gate 		rv = CRYPTO_SUCCESS;
6697c478bd9Sstevel@tonic-gate 		goto bail;
6707c478bd9Sstevel@tonic-gate 	}
6717c478bd9Sstevel@tonic-gate 	infos_size = ninfos * sizeof (crypto_mechanism_info_t);
6727c478bd9Sstevel@tonic-gate 	infos = kmem_alloc(infos_size, km_flag);
6737c478bd9Sstevel@tonic-gate 	if (infos == NULL) {
6747c478bd9Sstevel@tonic-gate 		rv = CRYPTO_HOST_MEMORY;
6757c478bd9Sstevel@tonic-gate 		goto bail;
6767c478bd9Sstevel@tonic-gate 	}
6777c478bd9Sstevel@tonic-gate 
678ef56a3c5SKrishna Yenduri 	mutex_enter(&mp->kl_lock);
6797c478bd9Sstevel@tonic-gate 	if (ninfos != PROV_COUNT(me)) {
6807c478bd9Sstevel@tonic-gate 		kmem_free(infos, infos_size);
6817c478bd9Sstevel@tonic-gate 		goto again;
6827c478bd9Sstevel@tonic-gate 	}
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	/* populate array of crypto mechanism infos */
6857c478bd9Sstevel@tonic-gate 	cur_info = 0;
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	/* software provider, if present */
6887c478bd9Sstevel@tonic-gate 	if (me->me_sw_prov != NULL)
6897c478bd9Sstevel@tonic-gate 		init_mechanism_info(&infos[cur_info++], me->me_sw_prov);
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	/* hardware providers */
6927c478bd9Sstevel@tonic-gate 	for (hwp = me->me_hw_prov_chain; hwp != NULL; hwp = hwp->pm_next)
6937c478bd9Sstevel@tonic-gate 		init_mechanism_info(&infos[cur_info++], hwp);
6947c478bd9Sstevel@tonic-gate 
695ef56a3c5SKrishna Yenduri 	mutex_exit(&mp->kl_lock);
6967c478bd9Sstevel@tonic-gate 	ASSERT(cur_info == ninfos);
6977c478bd9Sstevel@tonic-gate bail:
6987c478bd9Sstevel@tonic-gate 	*mech_infos = infos;
6997c478bd9Sstevel@tonic-gate 	*num_mech_infos = ninfos;
7007c478bd9Sstevel@tonic-gate 	return (rv);
7017c478bd9Sstevel@tonic-gate }
702894b2776Smcpowers 
703894b2776Smcpowers /*
7047d82f0f8SDina K Nimeh  * Frees the array of mechanism infos previously allocated by
7057d82f0f8SDina K Nimeh  * crypto_get_all_mech_info().
7067d82f0f8SDina K Nimeh  */
7077d82f0f8SDina K Nimeh void
7087d82f0f8SDina K Nimeh crypto_free_all_mech_info(crypto_mechanism_info_t *mech_infos, uint_t count)
7097d82f0f8SDina K Nimeh {
7107d82f0f8SDina K Nimeh 	if ((mech_infos != NULL) && (count > 0))
7117d82f0f8SDina K Nimeh 		kmem_free(mech_infos, count * sizeof (crypto_mechanism_info_t));
7127d82f0f8SDina K Nimeh }
7137d82f0f8SDina K Nimeh 
7147d82f0f8SDina K Nimeh /*
715894b2776Smcpowers  * memcmp_pad_max() is a specialized version of memcmp() which
716894b2776Smcpowers  * compares two pieces of data up to a maximum length.  If the
717894b2776Smcpowers  * the two data match up the maximum length, they are considered
718894b2776Smcpowers  * matching.  Trailing blanks do not cause the match to fail if
719894b2776Smcpowers  * one of the data is shorter.
720894b2776Smcpowers  *
721894b2776Smcpowers  * Examples of matches:
722894b2776Smcpowers  *	"one"           |
723894b2776Smcpowers  *	"one      "     |
724894b2776Smcpowers  *	                ^maximum length
725894b2776Smcpowers  *
726894b2776Smcpowers  *	"Number One     |  X"	(X is beyond maximum length)
727894b2776Smcpowers  *	"Number One   " |
728894b2776Smcpowers  *	                ^maximum length
729894b2776Smcpowers  *
730894b2776Smcpowers  * Examples of mismatches:
731894b2776Smcpowers  *	" one"
732894b2776Smcpowers  *	"one"
733894b2776Smcpowers  *
734894b2776Smcpowers  *	"Number One    X|"
735894b2776Smcpowers  *	"Number One     |"
736894b2776Smcpowers  *	                ^maximum length
737894b2776Smcpowers  */
738894b2776Smcpowers static int
739894b2776Smcpowers memcmp_pad_max(void *d1, uint_t d1_len, void *d2, uint_t d2_len, uint_t max_sz)
740894b2776Smcpowers {
741894b2776Smcpowers 	uint_t		len, extra_len;
742894b2776Smcpowers 	char		*marker;
743894b2776Smcpowers 
744894b2776Smcpowers 	/* No point in comparing anything beyond max_sz */
745894b2776Smcpowers 	if (d1_len > max_sz)
746894b2776Smcpowers 		d1_len = max_sz;
747894b2776Smcpowers 	if (d2_len > max_sz)
748894b2776Smcpowers 		d2_len = max_sz;
749894b2776Smcpowers 
750894b2776Smcpowers 	/* Find shorter of the two data. */
751894b2776Smcpowers 	if (d1_len <= d2_len) {
752894b2776Smcpowers 		len = d1_len;
753894b2776Smcpowers 		extra_len = d2_len;
754894b2776Smcpowers 		marker = d2;
755894b2776Smcpowers 	} else {	/* d1_len > d2_len */
756894b2776Smcpowers 		len = d2_len;
757894b2776Smcpowers 		extra_len = d1_len;
758894b2776Smcpowers 		marker = d1;
759894b2776Smcpowers 	}
760894b2776Smcpowers 
761894b2776Smcpowers 	/* Have a match in the shortest length of data? */
762894b2776Smcpowers 	if (memcmp(d1, d2, len) != 0)
763894b2776Smcpowers 		/* CONSTCOND */
764894b2776Smcpowers 		return (!0);
765894b2776Smcpowers 
766894b2776Smcpowers 	/* If the rest of longer data is nulls or blanks, call it a match. */
767894b2776Smcpowers 	while (len < extra_len)
768894b2776Smcpowers 		if (!isspace(marker[len++]))
769894b2776Smcpowers 			/* CONSTCOND */
770894b2776Smcpowers 			return (!0);
771894b2776Smcpowers 	return (0);
772894b2776Smcpowers }
773894b2776Smcpowers 
774894b2776Smcpowers /*
775894b2776Smcpowers  * Obtain ext info for specified provider and see if it matches.
776894b2776Smcpowers  */
777894b2776Smcpowers static boolean_t
778894b2776Smcpowers match_ext_info(kcf_provider_desc_t *pd, char *label, char *manuf, char *serial,
779894b2776Smcpowers     crypto_provider_ext_info_t *ext_info)
780894b2776Smcpowers {
781894b2776Smcpowers 	int rv;
782894b2776Smcpowers 
783c892ebf1Skrishna 	rv = crypto_get_provinfo(pd, ext_info);
784894b2776Smcpowers 	ASSERT(rv != CRYPTO_NOT_SUPPORTED);
785894b2776Smcpowers 	if (rv != CRYPTO_SUCCESS)
786894b2776Smcpowers 		return (B_FALSE);
787894b2776Smcpowers 
788894b2776Smcpowers 	if (memcmp_pad_max(ext_info->ei_label, CRYPTO_EXT_SIZE_LABEL,
789894b2776Smcpowers 	    label, strlen(label), CRYPTO_EXT_SIZE_LABEL))
790894b2776Smcpowers 		return (B_FALSE);
791894b2776Smcpowers 
792894b2776Smcpowers 	if (manuf != NULL) {
793894b2776Smcpowers 		if (memcmp_pad_max(ext_info->ei_manufacturerID,
794894b2776Smcpowers 		    CRYPTO_EXT_SIZE_MANUF, manuf, strlen(manuf),
795894b2776Smcpowers 		    CRYPTO_EXT_SIZE_MANUF))
796894b2776Smcpowers 			return (B_FALSE);
797894b2776Smcpowers 	}
798894b2776Smcpowers 
799894b2776Smcpowers 	if (serial != NULL) {
800894b2776Smcpowers 		if (memcmp_pad_max(ext_info->ei_serial_number,
801c892ebf1Skrishna 		    CRYPTO_EXT_SIZE_SERIAL, serial, strlen(serial),
802894b2776Smcpowers 		    CRYPTO_EXT_SIZE_SERIAL))
803894b2776Smcpowers 			return (B_FALSE);
804894b2776Smcpowers 	}
805894b2776Smcpowers 	return (B_TRUE);
806894b2776Smcpowers }
807894b2776Smcpowers 
808894b2776Smcpowers /*
809894b2776Smcpowers  * Find a provider based on its label, manufacturer ID, and serial number.
810894b2776Smcpowers  */
811894b2776Smcpowers crypto_provider_t
812894b2776Smcpowers crypto_get_provider(char *label, char *manuf, char *serial)
813894b2776Smcpowers {
814894b2776Smcpowers 	kcf_provider_desc_t **provider_array, *pd;
815894b2776Smcpowers 	crypto_provider_ext_info_t *ext_info;
816894b2776Smcpowers 	uint_t count;
817894b2776Smcpowers 	int i;
818894b2776Smcpowers 
819894b2776Smcpowers 	/* manuf and serial are optional */
820894b2776Smcpowers 	if (label == NULL)
821894b2776Smcpowers 		return (NULL);
822894b2776Smcpowers 
823894b2776Smcpowers 	if (kcf_get_slot_list(&count, &provider_array, B_FALSE)
824894b2776Smcpowers 	    != CRYPTO_SUCCESS)
825894b2776Smcpowers 		return (NULL);
826894b2776Smcpowers 
827894b2776Smcpowers 	if (count == 0)
828894b2776Smcpowers 		return (NULL);
829894b2776Smcpowers 
830894b2776Smcpowers 	ext_info = kmem_zalloc(sizeof (crypto_provider_ext_info_t), KM_SLEEP);
831894b2776Smcpowers 
832894b2776Smcpowers 	for (i = 0; i < count; i++) {
833894b2776Smcpowers 		pd = provider_array[i];
834894b2776Smcpowers 		if (match_ext_info(pd, label, manuf, serial, ext_info)) {
835894b2776Smcpowers 			KCF_PROV_REFHOLD(pd);
836894b2776Smcpowers 			break;
837894b2776Smcpowers 		}
838894b2776Smcpowers 	}
839894b2776Smcpowers 	if (i == count)
840894b2776Smcpowers 		pd = NULL;
841894b2776Smcpowers 
842894b2776Smcpowers 	kcf_free_provider_tab(count, provider_array);
843894b2776Smcpowers 	kmem_free(ext_info, sizeof (crypto_provider_ext_info_t));
844894b2776Smcpowers 	return (pd);
845894b2776Smcpowers }
846894b2776Smcpowers 
847c892ebf1Skrishna /*
848c892ebf1Skrishna  * Get the provider information given a provider handle. The caller
849c892ebf1Skrishna  * needs to allocate the space for the argument, info.
850c892ebf1Skrishna  */
851c892ebf1Skrishna int
852c892ebf1Skrishna crypto_get_provinfo(crypto_provider_t hndl, crypto_provider_ext_info_t *info)
853c892ebf1Skrishna {
854c892ebf1Skrishna 	int rv;
855c892ebf1Skrishna 	kcf_req_params_t params;
856c892ebf1Skrishna 	kcf_provider_desc_t *pd;
857c892ebf1Skrishna 	kcf_provider_desc_t *real_provider;
858c892ebf1Skrishna 
859c892ebf1Skrishna 	pd = (kcf_provider_desc_t *)hndl;
860c892ebf1Skrishna 	rv = kcf_get_hardware_provider_nomech(
861c892ebf1Skrishna 	    CRYPTO_OPS_OFFSET(provider_ops), CRYPTO_PROVIDER_OFFSET(ext_info),
862*9b009fc1SValerie Bubb Fenwick 	    pd, &real_provider);
863c892ebf1Skrishna 
864c892ebf1Skrishna 	if (rv == CRYPTO_SUCCESS && real_provider != NULL) {
865c892ebf1Skrishna 		ASSERT(real_provider == pd ||
866c892ebf1Skrishna 		    pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER);
867c892ebf1Skrishna 		KCF_WRAP_PROVMGMT_OPS_PARAMS(&params, KCF_OP_MGMT_EXTINFO,
868c892ebf1Skrishna 		    0, NULL, 0, NULL, 0, NULL, info, pd);
869c892ebf1Skrishna 		rv = kcf_submit_request(real_provider, NULL, NULL, &params,
870c892ebf1Skrishna 		    B_FALSE);
871c892ebf1Skrishna 		KCF_PROV_REFRELE(real_provider);
872c892ebf1Skrishna 	}
873c892ebf1Skrishna 
874c892ebf1Skrishna 	return (rv);
875c892ebf1Skrishna }
876c892ebf1Skrishna 
877894b2776Smcpowers void
878894b2776Smcpowers crypto_release_provider(crypto_provider_t provider)
879894b2776Smcpowers {
880894b2776Smcpowers 	KCF_PROV_REFRELE((kcf_provider_desc_t *)provider);
881894b2776Smcpowers }
882