xref: /onnv-gate/usr/src/uts/common/crypto/api/kcf_miscapi.c (revision 904:4f885c862682)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*904Smcpowers  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/sunddi.h>
310Sstevel@tonic-gate #include <sys/disp.h>
320Sstevel@tonic-gate #include <sys/modctl.h>
33*904Smcpowers #include <sys/sysmacros.h>
340Sstevel@tonic-gate #include <sys/crypto/common.h>
350Sstevel@tonic-gate #include <sys/crypto/api.h>
360Sstevel@tonic-gate #include <sys/crypto/impl.h>
370Sstevel@tonic-gate #include <sys/crypto/sched_impl.h>
380Sstevel@tonic-gate 
39*904Smcpowers #define	isspace(ch)	(((ch) == ' ') || ((ch) == '\r') || ((ch) == '\n') || \
40*904Smcpowers 			((ch) == '\t') || ((ch) == '\f'))
41*904Smcpowers 
42*904Smcpowers #define	CRYPTO_OPS_OFFSET(f)		offsetof(crypto_ops_t, co_##f)
43*904Smcpowers #define	CRYPTO_KEY_OFFSET(f)		offsetof(crypto_key_ops_t, f)
44*904Smcpowers #define	CRYPTO_PROVIDER_OFFSET(f)	\
45*904Smcpowers 	offsetof(crypto_provider_management_ops_t, f)
46*904Smcpowers 
470Sstevel@tonic-gate /* Miscellaneous exported entry points */
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * All event subscribers are put on a list. kcf_notify_list_lock
510Sstevel@tonic-gate  * protects changes to this list.
520Sstevel@tonic-gate  *
530Sstevel@tonic-gate  * The following locking order is maintained in the code - The
540Sstevel@tonic-gate  * global kcf_notify_list_lock followed by the individual lock
550Sstevel@tonic-gate  * in a kcf_ntfy_elem structure (kn_lock).
560Sstevel@tonic-gate  */
570Sstevel@tonic-gate kmutex_t		ntfy_list_lock;
580Sstevel@tonic-gate kcondvar_t		ntfy_list_cv;   /* cv the service thread waits on */
590Sstevel@tonic-gate static kcf_ntfy_elem_t *ntfy_list_head;
600Sstevel@tonic-gate static kcf_ntfy_elem_t *ntfy_list_tail;
610Sstevel@tonic-gate 
620Sstevel@tonic-gate /* count all the hardware and software providers */
630Sstevel@tonic-gate #define	PROV_COUNT(me) \
640Sstevel@tonic-gate 	(((me)->me_sw_prov != NULL ? 1 : 0) + (me)->me_num_hwprov)
650Sstevel@tonic-gate 
660Sstevel@tonic-gate /*
670Sstevel@tonic-gate  * crypto_mech2id()
680Sstevel@tonic-gate  *
690Sstevel@tonic-gate  * Arguments:
700Sstevel@tonic-gate  *	. mechname: A null-terminated string identifying the mechanism name.
710Sstevel@tonic-gate  *
720Sstevel@tonic-gate  * Description:
730Sstevel@tonic-gate  *	Walks the mechanisms tables, looking for an entry that matches the
740Sstevel@tonic-gate  *	mechname. Once it find it, it builds the 64-bit mech_type and returns
750Sstevel@tonic-gate  *	it.  If there are no hardware or software providers for the mechanism,
760Sstevel@tonic-gate  *	but there is an unloaded software provider, this routine will attempt
770Sstevel@tonic-gate  *	to load it.
780Sstevel@tonic-gate  *
790Sstevel@tonic-gate  * Context:
800Sstevel@tonic-gate  *	Process and interruption.
810Sstevel@tonic-gate  *
820Sstevel@tonic-gate  * Returns:
830Sstevel@tonic-gate  *	The unique mechanism identified by 'mechname', if found.
840Sstevel@tonic-gate  *	CRYPTO_MECH_INVALID otherwise.
850Sstevel@tonic-gate  */
860Sstevel@tonic-gate crypto_mech_type_t
870Sstevel@tonic-gate crypto_mech2id(char *mechname)
880Sstevel@tonic-gate {
890Sstevel@tonic-gate 	return (crypto_mech2id_common(mechname, B_TRUE));
900Sstevel@tonic-gate }
910Sstevel@tonic-gate 
920Sstevel@tonic-gate /*
930Sstevel@tonic-gate  * crypto_get_mech_list()
940Sstevel@tonic-gate  *
950Sstevel@tonic-gate  * Arguments:
960Sstevel@tonic-gate  *	. countp: pointer to contain the number of mech names returned
970Sstevel@tonic-gate  *	. kmflag: memory allocation flag.
980Sstevel@tonic-gate  *
990Sstevel@tonic-gate  * Description:
1000Sstevel@tonic-gate  *	Allocates an array of crypto_mech_name_t containing all the mechanisms
1010Sstevel@tonic-gate  *	currently available on the system. Sets *countp with the number of
1020Sstevel@tonic-gate  *	mechanism names returned.
1030Sstevel@tonic-gate  *
1040Sstevel@tonic-gate  *	We get a list of mech names which have a hardware provider by walking
1050Sstevel@tonic-gate  *	all the mechanism tables. We merge them with mech names obtained from
1060Sstevel@tonic-gate  *	the hint list. A mech name in the hint list is considered only if it
1070Sstevel@tonic-gate  *	is not disabled for the provider. Note that the hint list contains only
1080Sstevel@tonic-gate  *	software providers and the mech names supported by them.
1090Sstevel@tonic-gate  *
1100Sstevel@tonic-gate  * Context:
1110Sstevel@tonic-gate  *	Process and interruption. kmflag should be KM_NOSLEEP when called
1120Sstevel@tonic-gate  *	from an interruption context.
1130Sstevel@tonic-gate  *
1140Sstevel@tonic-gate  * Returns:
1150Sstevel@tonic-gate  *	The array of the crypto_mech_t allocated.
1160Sstevel@tonic-gate  *	NULL otherwise.
1170Sstevel@tonic-gate  */
1180Sstevel@tonic-gate crypto_mech_name_t *
1190Sstevel@tonic-gate crypto_get_mech_list(uint_t *countp, int kmflag)
1200Sstevel@tonic-gate {
1210Sstevel@tonic-gate 	uint_t count = 0, me_tab_size, i, j;
1220Sstevel@tonic-gate 	kcf_ops_class_t cl;
1230Sstevel@tonic-gate 	kcf_mech_entry_t *me, *me_tab;
1240Sstevel@tonic-gate 	crypto_mech_name_t *mech_name_tab, *tmp_mech_name_tab;
1250Sstevel@tonic-gate 	char *mech_name, *hint_mech, *end;
1260Sstevel@tonic-gate 	kcf_soft_conf_entry_t *p;
1270Sstevel@tonic-gate 	size_t n;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	/*
1300Sstevel@tonic-gate 	 * Count the maximum possible mechanisms that can come from the
1310Sstevel@tonic-gate 	 * hint list.
1320Sstevel@tonic-gate 	 */
1330Sstevel@tonic-gate 	mutex_enter(&soft_config_mutex);
1340Sstevel@tonic-gate 	p = soft_config_list;
1350Sstevel@tonic-gate 	while (p != NULL) {
1360Sstevel@tonic-gate 		count += p->ce_count;
1370Sstevel@tonic-gate 		p = p->ce_next;
1380Sstevel@tonic-gate 	}
1390Sstevel@tonic-gate 	mutex_exit(&soft_config_mutex);
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	/* First let's count'em, for mem allocation */
1420Sstevel@tonic-gate 	for (cl = KCF_FIRST_OPSCLASS; cl <= KCF_LAST_OPSCLASS; cl++) {
1430Sstevel@tonic-gate 		me_tab_size = kcf_mech_tabs_tab[cl].met_size;
1440Sstevel@tonic-gate 		me_tab = kcf_mech_tabs_tab[cl].met_tab;
1450Sstevel@tonic-gate 		for (i = 0; i < me_tab_size; i++) {
1460Sstevel@tonic-gate 			me = &me_tab[i];
1470Sstevel@tonic-gate 			mutex_enter(&(me->me_mutex));
1480Sstevel@tonic-gate 			if ((me->me_name[0] != 0) && (me->me_num_hwprov >= 1)) {
1490Sstevel@tonic-gate 				ASSERT(me->me_hw_prov_chain != NULL);
1500Sstevel@tonic-gate 				count++;
1510Sstevel@tonic-gate 			}
1520Sstevel@tonic-gate 			mutex_exit(&(me->me_mutex));
1530Sstevel@tonic-gate 		}
1540Sstevel@tonic-gate 	}
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	/*
1570Sstevel@tonic-gate 	 * Allocate a buffer to hold the mechanisms from
1580Sstevel@tonic-gate 	 * mech tabs and mechanisms from the hint list.
1590Sstevel@tonic-gate 	 */
1600Sstevel@tonic-gate 	n = count * CRYPTO_MAX_MECH_NAME;
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate again:
1630Sstevel@tonic-gate 	count = 0;
1640Sstevel@tonic-gate 	tmp_mech_name_tab = kmem_zalloc(n, kmflag);
1650Sstevel@tonic-gate 	if (tmp_mech_name_tab == NULL) {
1660Sstevel@tonic-gate 		*countp = 0;
1670Sstevel@tonic-gate 		return (NULL);
1680Sstevel@tonic-gate 	}
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	/*
1710Sstevel@tonic-gate 	 * Second round, fill in the table
1720Sstevel@tonic-gate 	 */
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	mech_name = (char *)tmp_mech_name_tab;
1750Sstevel@tonic-gate 	end = mech_name + n;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	for (cl = KCF_FIRST_OPSCLASS; cl <= KCF_LAST_OPSCLASS; cl++) {
1780Sstevel@tonic-gate 		me_tab_size = kcf_mech_tabs_tab[cl].met_size;
1790Sstevel@tonic-gate 		me_tab = kcf_mech_tabs_tab[cl].met_tab;
1800Sstevel@tonic-gate 		for (i = 0; i < me_tab_size; i++) {
1810Sstevel@tonic-gate 			me = &me_tab[i];
1820Sstevel@tonic-gate 			mutex_enter(&(me->me_mutex));
1830Sstevel@tonic-gate 			if ((me->me_name[0] != 0) && (me->me_num_hwprov >= 1)) {
1840Sstevel@tonic-gate 				ASSERT(me->me_hw_prov_chain != NULL);
1850Sstevel@tonic-gate 				if ((mech_name + CRYPTO_MAX_MECH_NAME) > end) {
1860Sstevel@tonic-gate 					mutex_exit(&(me->me_mutex));
1870Sstevel@tonic-gate 					kmem_free(tmp_mech_name_tab, n);
1880Sstevel@tonic-gate 					n = n << 1;
1890Sstevel@tonic-gate 					goto again;
1900Sstevel@tonic-gate 				}
1910Sstevel@tonic-gate 				(void) strncpy(mech_name, me->me_name,
1920Sstevel@tonic-gate 				    CRYPTO_MAX_MECH_NAME);
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 				mech_name += CRYPTO_MAX_MECH_NAME;
1950Sstevel@tonic-gate 				count++;
1960Sstevel@tonic-gate 			}
1970Sstevel@tonic-gate 			mutex_exit(&(me->me_mutex));
1980Sstevel@tonic-gate 		}
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	/*
2020Sstevel@tonic-gate 	 * Search tmp_mech_name_tab for each mechanism in the hint list. We
2030Sstevel@tonic-gate 	 * have to add any new mechanisms found in the hint list. Note that we
2040Sstevel@tonic-gate 	 * should not modload the providers here as it will be too early. It
2050Sstevel@tonic-gate 	 * may be the case that the caller never uses a provider.
2060Sstevel@tonic-gate 	 */
2070Sstevel@tonic-gate 	mutex_enter(&soft_config_mutex);
2080Sstevel@tonic-gate 	p = soft_config_list;
2090Sstevel@tonic-gate 	while (p != NULL) {
2100Sstevel@tonic-gate 		for (i = 0; i < p->ce_count; i++) {
2110Sstevel@tonic-gate 			hint_mech = p->ce_mechs[i];
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 			/* Do not consider the mechanism if it is disabled. */
2140Sstevel@tonic-gate 			if (is_mech_disabled_byname(CRYPTO_SW_PROVIDER,
2150Sstevel@tonic-gate 			    p->ce_name, 0, hint_mech))
2160Sstevel@tonic-gate 				continue;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 			/*
2190Sstevel@tonic-gate 			 * There may be duplicate mechanisms in the hint list.
2200Sstevel@tonic-gate 			 * So, we need to search all the entries that have been
2210Sstevel@tonic-gate 			 * added so far. That number would be count.
2220Sstevel@tonic-gate 			 */
2230Sstevel@tonic-gate 			for (j = 0; j < count; j++) {
2240Sstevel@tonic-gate 				if (strcmp(hint_mech,
2250Sstevel@tonic-gate 				    tmp_mech_name_tab[j]) == 0)
2260Sstevel@tonic-gate 					break;
2270Sstevel@tonic-gate 			}
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 			if (j == count) {	/* This is a new one. Add it. */
2300Sstevel@tonic-gate 				ASSERT((char *)&tmp_mech_name_tab[count] ==
2310Sstevel@tonic-gate 				    mech_name);
2320Sstevel@tonic-gate 				if ((mech_name + CRYPTO_MAX_MECH_NAME) > end) {
2330Sstevel@tonic-gate 					mutex_exit(&soft_config_mutex);
2340Sstevel@tonic-gate 					kmem_free(tmp_mech_name_tab, n);
2350Sstevel@tonic-gate 					n = n << 1;
2360Sstevel@tonic-gate 					goto again;
2370Sstevel@tonic-gate 				}
2380Sstevel@tonic-gate 				(void) strncpy(tmp_mech_name_tab[count],
2390Sstevel@tonic-gate 				    hint_mech, CRYPTO_MAX_MECH_NAME);
2400Sstevel@tonic-gate 				mech_name += CRYPTO_MAX_MECH_NAME;
2410Sstevel@tonic-gate 				count++;
2420Sstevel@tonic-gate 			}
2430Sstevel@tonic-gate 		}
2440Sstevel@tonic-gate 		p = p->ce_next;
2450Sstevel@tonic-gate 	}
2460Sstevel@tonic-gate 	mutex_exit(&soft_config_mutex);
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	/*
2490Sstevel@tonic-gate 	 * Check if we have consumed all of the space. We are done if
2500Sstevel@tonic-gate 	 * this is the case.
2510Sstevel@tonic-gate 	 */
2520Sstevel@tonic-gate 	ASSERT(mech_name <= end);
2530Sstevel@tonic-gate 	if (mech_name == end) {
2540Sstevel@tonic-gate 		mech_name_tab = tmp_mech_name_tab;
2550Sstevel@tonic-gate 		goto done;
2560Sstevel@tonic-gate 	}
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	/*
2590Sstevel@tonic-gate 	 * Allocate a buffer of the right size now that we have the
2600Sstevel@tonic-gate 	 * correct count.
2610Sstevel@tonic-gate 	 */
2620Sstevel@tonic-gate 	mech_name_tab = kmem_zalloc(count * CRYPTO_MAX_MECH_NAME, kmflag);
2630Sstevel@tonic-gate 	if (mech_name_tab == NULL) {
2640Sstevel@tonic-gate 		kmem_free(tmp_mech_name_tab, n);
2650Sstevel@tonic-gate 		*countp = 0;
2660Sstevel@tonic-gate 		return (NULL);
2670Sstevel@tonic-gate 	}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	bcopy(tmp_mech_name_tab, mech_name_tab, count * CRYPTO_MAX_MECH_NAME);
2700Sstevel@tonic-gate 	kmem_free(tmp_mech_name_tab, n);
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate done:
2730Sstevel@tonic-gate 	*countp = count;
2740Sstevel@tonic-gate 	return (mech_name_tab);
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate /*
2780Sstevel@tonic-gate  * crypto_free_mech_list()
2790Sstevel@tonic-gate  *
2800Sstevel@tonic-gate  * Arguments:
2810Sstevel@tonic-gate  *	. mech_names: An array of crypto_mech_name_t previously allocated by
2820Sstevel@tonic-gate  *	  crypto_get_mech_list.
2830Sstevel@tonic-gate  *	. count: the number of mech names in mech_names
2840Sstevel@tonic-gate  *
2850Sstevel@tonic-gate  * Description:
2860Sstevel@tonic-gate  *	Frees the the mech_names array.
2870Sstevel@tonic-gate  *
2880Sstevel@tonic-gate  * Context:
2890Sstevel@tonic-gate  *	Process and interruption.
2900Sstevel@tonic-gate  */
2910Sstevel@tonic-gate void
2920Sstevel@tonic-gate crypto_free_mech_list(crypto_mech_name_t *mech_names, uint_t count)
2930Sstevel@tonic-gate {
2940Sstevel@tonic-gate 	if ((mech_names != NULL) && (count > 0))
2950Sstevel@tonic-gate 		kmem_free(mech_names, count * CRYPTO_MAX_MECH_NAME);
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate /*
2990Sstevel@tonic-gate  * crypto_notify_events()
3000Sstevel@tonic-gate  *
3010Sstevel@tonic-gate  * Arguments:
3020Sstevel@tonic-gate  *	. nf: Callback function to invoke when event occurs.
3030Sstevel@tonic-gate  *	. event_mask: Mask of events.
3040Sstevel@tonic-gate  *
3050Sstevel@tonic-gate  * Description:
3060Sstevel@tonic-gate  *	Allocates a new element and inserts it in to the notification
3070Sstevel@tonic-gate  *	list.
3080Sstevel@tonic-gate  *
3090Sstevel@tonic-gate  * Context:
3100Sstevel@tonic-gate  *	Process context.
3110Sstevel@tonic-gate  *
3120Sstevel@tonic-gate  * Returns:
3130Sstevel@tonic-gate  *	A handle is returned if the client is put on the notification list.
3140Sstevel@tonic-gate  *	NULL is returned otherwise.
3150Sstevel@tonic-gate  */
3160Sstevel@tonic-gate crypto_notify_handle_t
3170Sstevel@tonic-gate crypto_notify_events(crypto_notify_callback_t nf, uint32_t event_mask)
3180Sstevel@tonic-gate {
3190Sstevel@tonic-gate 	kcf_ntfy_elem_t *nep;
3200Sstevel@tonic-gate 	crypto_notify_handle_t hndl;
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	/*
3230Sstevel@tonic-gate 	 * The only valid value for event_mask is CRYPTO_EVENT_PROVIDERS_CHANGE.
3240Sstevel@tonic-gate 	 */
3250Sstevel@tonic-gate 	if (nf == NULL || !(event_mask & CRYPTO_EVENT_PROVIDERS_CHANGE)) {
3260Sstevel@tonic-gate 		return (NULL);
3270Sstevel@tonic-gate 	}
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	nep = kmem_zalloc(sizeof (kcf_ntfy_elem_t), KM_SLEEP);
3300Sstevel@tonic-gate 	mutex_init(&nep->kn_lock, NULL, MUTEX_DEFAULT, NULL);
3310Sstevel@tonic-gate 	cv_init(&nep->kn_cv, NULL, CV_DEFAULT, NULL);
3320Sstevel@tonic-gate 	nep->kn_state = NTFY_WAITING;
3330Sstevel@tonic-gate 	nep->kn_func = nf;
3340Sstevel@tonic-gate 	nep->kn_event_mask = event_mask;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	mutex_enter(&ntfy_list_lock);
3370Sstevel@tonic-gate 	if (ntfy_list_head == NULL) {
3380Sstevel@tonic-gate 		ntfy_list_head = ntfy_list_tail = nep;
3390Sstevel@tonic-gate 	} else {
3400Sstevel@tonic-gate 		ntfy_list_tail->kn_next = nep;
3410Sstevel@tonic-gate 		nep->kn_prev = ntfy_list_tail;
3420Sstevel@tonic-gate 		ntfy_list_tail = nep;
3430Sstevel@tonic-gate 	}
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	hndl = (crypto_notify_handle_t)nep;
3460Sstevel@tonic-gate 	mutex_exit(&ntfy_list_lock);
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	return (hndl);
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate /*
3520Sstevel@tonic-gate  * crypto_unnotify_events()
3530Sstevel@tonic-gate  *
3540Sstevel@tonic-gate  * Arguments:
3550Sstevel@tonic-gate  *	. hndl - Handle returned from an earlier crypto_notify_events().
3560Sstevel@tonic-gate  *
3570Sstevel@tonic-gate  * Description:
3580Sstevel@tonic-gate  *	Removes the element specified by hndl from the notification list.
3590Sstevel@tonic-gate  *	We wait for the notification routine to complete, if the routine
3600Sstevel@tonic-gate  *	is currently being called. We also free the element.
3610Sstevel@tonic-gate  *
3620Sstevel@tonic-gate  * Context:
3630Sstevel@tonic-gate  *	Process context.
3640Sstevel@tonic-gate  */
3650Sstevel@tonic-gate void
3660Sstevel@tonic-gate crypto_unnotify_events(crypto_notify_handle_t hndl)
3670Sstevel@tonic-gate {
3680Sstevel@tonic-gate 	kcf_ntfy_elem_t *nep = (kcf_ntfy_elem_t *)hndl;
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	if (hndl == NULL)
3710Sstevel@tonic-gate 		return;
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate retry:
3740Sstevel@tonic-gate 	mutex_enter(&ntfy_list_lock);
3750Sstevel@tonic-gate 	mutex_enter(&nep->kn_lock);
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	if (nep->kn_state == NTFY_WAITING) {
3780Sstevel@tonic-gate 		kcf_ntfy_elem_t *nextp = nep->kn_next;
3790Sstevel@tonic-gate 		kcf_ntfy_elem_t *prevp = nep->kn_prev;
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 		if (nextp != NULL)
3820Sstevel@tonic-gate 			nextp->kn_prev = prevp;
3830Sstevel@tonic-gate 		else
3840Sstevel@tonic-gate 			ntfy_list_tail = prevp;
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 		if (prevp != NULL)
3870Sstevel@tonic-gate 			prevp->kn_next = nextp;
3880Sstevel@tonic-gate 		else
3890Sstevel@tonic-gate 			ntfy_list_head = nextp;
3900Sstevel@tonic-gate 	} else {
3910Sstevel@tonic-gate 		ASSERT(nep->kn_state == NTFY_RUNNING);
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 		/*
3940Sstevel@tonic-gate 		 * We have to drop this lock as the client might call
3950Sstevel@tonic-gate 		 * crypto_notify_events() in the callback routine resulting
3960Sstevel@tonic-gate 		 * in a deadlock.
3970Sstevel@tonic-gate 		 */
3980Sstevel@tonic-gate 		mutex_exit(&ntfy_list_lock);
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 		/*
4010Sstevel@tonic-gate 		 * Another thread is working on this element. We will wait
4020Sstevel@tonic-gate 		 * for that thread to signal us when done. No other thread
4030Sstevel@tonic-gate 		 * will free this element. So, we can be sure it stays valid
4040Sstevel@tonic-gate 		 * after the wait.
4050Sstevel@tonic-gate 		 */
4060Sstevel@tonic-gate 		while (nep->kn_state == NTFY_RUNNING)
4070Sstevel@tonic-gate 			cv_wait(&nep->kn_cv, &nep->kn_lock);
4080Sstevel@tonic-gate 		mutex_exit(&nep->kn_lock);
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 		/*
4110Sstevel@tonic-gate 		 * We have to remove the element from the notification list.
4120Sstevel@tonic-gate 		 * So, start over and do the work (acquire locks etc.). This is
4130Sstevel@tonic-gate 		 * safe (i.e. We won't be in this routine forever) as the
4140Sstevel@tonic-gate 		 * CRYPTO_EVENT_PROVIDERS_CHANGE event does not happen
4150Sstevel@tonic-gate 		 * frequently. We have to revisit this code if we
4160Sstevel@tonic-gate 		 * add a new event that happens often.
4170Sstevel@tonic-gate 		 */
4180Sstevel@tonic-gate 		goto retry;
4190Sstevel@tonic-gate 	}
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	mutex_exit(&nep->kn_lock);
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	/* Free the element */
4240Sstevel@tonic-gate 	mutex_destroy(&nep->kn_lock);
4250Sstevel@tonic-gate 	cv_destroy(&nep->kn_cv);
4260Sstevel@tonic-gate 	kmem_free(nep, sizeof (kcf_ntfy_elem_t));
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	mutex_exit(&ntfy_list_lock);
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate /*
4320Sstevel@tonic-gate  * This routine is called from crypto_register_provider() and
4330Sstevel@tonic-gate  * crypto_unregister_provider() with the CRYPTO_EVENT_PROVIDERS_CHANGE event.
4340Sstevel@tonic-gate  *
4350Sstevel@tonic-gate  * We walk the notification list and do the callbacks.
4360Sstevel@tonic-gate  */
4370Sstevel@tonic-gate void
4380Sstevel@tonic-gate kcf_walk_ntfylist(uint32_t event, void *event_arg)
4390Sstevel@tonic-gate {
4400Sstevel@tonic-gate 	kcf_ntfy_elem_t *nep;
4410Sstevel@tonic-gate 	int nelem = 0;
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	mutex_enter(&ntfy_list_lock);
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	/*
4460Sstevel@tonic-gate 	 * Count how many clients are on the notification list. We need
4470Sstevel@tonic-gate 	 * this count to ensure that clients which joined the list after we
4480Sstevel@tonic-gate 	 * have started this walk, are not wrongly notified.
4490Sstevel@tonic-gate 	 */
4500Sstevel@tonic-gate 	for (nep = ntfy_list_head; nep != NULL; nep = nep->kn_next)
4510Sstevel@tonic-gate 		nelem++;
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	for (nep = ntfy_list_head; (nep != NULL && nelem); nep = nep->kn_next) {
4540Sstevel@tonic-gate 		nelem--;
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 		/*
4570Sstevel@tonic-gate 		 * Check if this client is interested in the
4580Sstevel@tonic-gate 		 * event.
4590Sstevel@tonic-gate 		 */
4600Sstevel@tonic-gate 		if (!(nep->kn_event_mask & event))
4610Sstevel@tonic-gate 			continue;
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 		mutex_enter(&nep->kn_lock);
4640Sstevel@tonic-gate 		nep->kn_state = NTFY_RUNNING;
4650Sstevel@tonic-gate 		mutex_exit(&nep->kn_lock);
4660Sstevel@tonic-gate 		mutex_exit(&ntfy_list_lock);
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 		/*
4690Sstevel@tonic-gate 		 * We invoke the callback routine with no locks held. Another
4700Sstevel@tonic-gate 		 * client could have joined the list meanwhile. This is fine
4710Sstevel@tonic-gate 		 * as we maintain nelem as stated above. The NULL check in the
4720Sstevel@tonic-gate 		 * for loop guards against shrinkage. Also, any callers of
4730Sstevel@tonic-gate 		 * crypto_unnotify_events() at this point cv_wait till kn_state
4740Sstevel@tonic-gate 		 * changes to NTFY_WAITING. Hence, nep is assured to be valid.
4750Sstevel@tonic-gate 		 */
4760Sstevel@tonic-gate 		(*nep->kn_func)(event, event_arg);
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 		mutex_enter(&nep->kn_lock);
4790Sstevel@tonic-gate 		nep->kn_state = NTFY_WAITING;
4800Sstevel@tonic-gate 		cv_broadcast(&nep->kn_cv);
4810Sstevel@tonic-gate 		mutex_exit(&nep->kn_lock);
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 		mutex_enter(&ntfy_list_lock);
4840Sstevel@tonic-gate 	}
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	mutex_exit(&ntfy_list_lock);
4870Sstevel@tonic-gate }
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate /*
4900Sstevel@tonic-gate  * crypto_key_check()
4910Sstevel@tonic-gate  *
4920Sstevel@tonic-gate  * Arguments:
4930Sstevel@tonic-gate  *	. mech: the mechanism to check the key with.
4940Sstevel@tonic-gate  *	. key: the key to check for validity and weakness.
4950Sstevel@tonic-gate  *
4960Sstevel@tonic-gate  * Description:
4970Sstevel@tonic-gate  *	Checks the validity and strength of the key for the mechanism.
4980Sstevel@tonic-gate  *	CRYPTO_KEY_REFERENCE is not supported for this routine.
4990Sstevel@tonic-gate  *	If more than one provider is capable of key checking for the mechanism,
5000Sstevel@tonic-gate  *	then run the key through them all.
5010Sstevel@tonic-gate  *	A conservative approach is adopted here: New weak keys may be
5020Sstevel@tonic-gate  *	discovered with more recent providers. If at least one provider is
5030Sstevel@tonic-gate  *	not happy with a key, then it is no good.
5040Sstevel@tonic-gate  *
5050Sstevel@tonic-gate  * Context:
5060Sstevel@tonic-gate  *	Process and interruption.
5070Sstevel@tonic-gate  */
5080Sstevel@tonic-gate int
5090Sstevel@tonic-gate crypto_key_check(crypto_mechanism_t *mech, crypto_key_t *key)
5100Sstevel@tonic-gate {
5110Sstevel@tonic-gate 	int error;
5120Sstevel@tonic-gate 	kcf_mech_entry_t *me;
5130Sstevel@tonic-gate 	kcf_provider_desc_t *pd;
5140Sstevel@tonic-gate 	kcf_prov_mech_desc_t *prov_chain;
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	/* when mech is a valid mechanism, me will be its mech_entry */
5170Sstevel@tonic-gate 	if ((mech == NULL) || (key == NULL) ||
5180Sstevel@tonic-gate 	    (key->ck_format == CRYPTO_KEY_REFERENCE))
5190Sstevel@tonic-gate 		return (CRYPTO_ARGUMENTS_BAD);
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	if ((error = kcf_get_mech_entry(mech->cm_type, &me)) != KCF_SUCCESS) {
5220Sstevel@tonic-gate 		/* error is one of the KCF_INVALID_MECH_XXX's */
5230Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
5240Sstevel@tonic-gate 	}
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	mutex_enter(&me->me_mutex);
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	/* First let the software provider check this key */
5290Sstevel@tonic-gate 	if (me->me_sw_prov != NULL) {
5300Sstevel@tonic-gate 		pd = me->me_sw_prov->pm_prov_desc;
5310Sstevel@tonic-gate 		KCF_PROV_REFHOLD(pd);
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 		if ((KCF_PROV_KEY_OPS(pd) != NULL) &&
5340Sstevel@tonic-gate 		    (KCF_PROV_KEY_OPS(pd)->key_check != NULL)) {
5350Sstevel@tonic-gate 			crypto_mechanism_t lmech;
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 			mutex_exit(&me->me_mutex);
5380Sstevel@tonic-gate 			lmech = *mech;
5390Sstevel@tonic-gate 			KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
5400Sstevel@tonic-gate 			error = KCF_PROV_KEY_CHECK(pd, &lmech, key);
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 			if (error != CRYPTO_SUCCESS) {
5430Sstevel@tonic-gate 				KCF_PROV_REFRELE(pd);
5440Sstevel@tonic-gate 				return (error);
5450Sstevel@tonic-gate 			}
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 			mutex_enter(&me->me_mutex);
5480Sstevel@tonic-gate 		}
5490Sstevel@tonic-gate 		KCF_PROV_REFRELE(pd);
5500Sstevel@tonic-gate 	}
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	prov_chain = me->me_hw_prov_chain;
5530Sstevel@tonic-gate 	while (prov_chain != NULL) {
5540Sstevel@tonic-gate 		pd = prov_chain->pm_prov_desc;
5550Sstevel@tonic-gate 		KCF_PROV_REFHOLD(pd);
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 		if ((KCF_PROV_KEY_OPS(pd) != NULL) &&
5580Sstevel@tonic-gate 		    (KCF_PROV_KEY_OPS(pd)->key_check != NULL)) {
5590Sstevel@tonic-gate 			crypto_mechanism_t lmech;
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 			mutex_exit(&me->me_mutex);
5620Sstevel@tonic-gate 			lmech = *mech;
5630Sstevel@tonic-gate 			KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd,
5640Sstevel@tonic-gate 			    &lmech);
5650Sstevel@tonic-gate 			error = KCF_PROV_KEY_CHECK(pd, &lmech, key);
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 			if (error != CRYPTO_SUCCESS) {
5680Sstevel@tonic-gate 				KCF_PROV_REFRELE(pd);
5690Sstevel@tonic-gate 				return (error);
5700Sstevel@tonic-gate 			}
5710Sstevel@tonic-gate 			mutex_enter(&me->me_mutex);
5720Sstevel@tonic-gate 		}
5730Sstevel@tonic-gate 		KCF_PROV_REFRELE(pd);
5740Sstevel@tonic-gate 		prov_chain = prov_chain->pm_next;
5750Sstevel@tonic-gate 	}
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	mutex_exit(&me->me_mutex);
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	/* All are happy with this key */
5800Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
5810Sstevel@tonic-gate }
5820Sstevel@tonic-gate 
583*904Smcpowers int
584*904Smcpowers crypto_key_check_prov(crypto_provider_t provider, crypto_mechanism_t *mech,
585*904Smcpowers     crypto_key_t *key)
586*904Smcpowers {
587*904Smcpowers 	kcf_provider_desc_t *pd = provider;
588*904Smcpowers 	kcf_provider_desc_t *real_provider = pd;
589*904Smcpowers 	crypto_mechanism_t lmech;
590*904Smcpowers 	int rv;
591*904Smcpowers 
592*904Smcpowers 	ASSERT(KCF_PROV_REFHELD(pd));
593*904Smcpowers 
594*904Smcpowers 	if ((mech == NULL) || (key == NULL) ||
595*904Smcpowers 	    (key->ck_format == CRYPTO_KEY_REFERENCE))
596*904Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
597*904Smcpowers 
598*904Smcpowers 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
599*904Smcpowers 		rv = kcf_get_hardware_provider(mech->cm_type,
600*904Smcpowers 		    CRYPTO_MECH_INVALID, CRYPTO_OPS_OFFSET(key_ops),
601*904Smcpowers 		    CRYPTO_KEY_OFFSET(key_check), CHECK_RESTRICT_FALSE,
602*904Smcpowers 		    pd, &real_provider);
603*904Smcpowers 
604*904Smcpowers 		if (rv != CRYPTO_SUCCESS)
605*904Smcpowers 			return (rv);
606*904Smcpowers 	}
607*904Smcpowers 
608*904Smcpowers 	lmech = *mech;
609*904Smcpowers 	KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
610*904Smcpowers 	rv = KCF_PROV_KEY_CHECK(real_provider, &lmech, key);
611*904Smcpowers 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
612*904Smcpowers 		KCF_PROV_REFRELE(real_provider);
613*904Smcpowers 
614*904Smcpowers 	return (rv);
615*904Smcpowers }
616*904Smcpowers 
6170Sstevel@tonic-gate /*
6180Sstevel@tonic-gate  * Initialize the specified crypto_mechanism_info_t structure for
6190Sstevel@tonic-gate  * the specified mechanism provider descriptor. Used by
6200Sstevel@tonic-gate  * crypto_get_all_mech_info().
6210Sstevel@tonic-gate  */
6220Sstevel@tonic-gate static void
6230Sstevel@tonic-gate init_mechanism_info(crypto_mechanism_info_t *mech_info,
6240Sstevel@tonic-gate     kcf_prov_mech_desc_t *pmd)
6250Sstevel@tonic-gate {
6260Sstevel@tonic-gate 	crypto_func_group_t fg = pmd->pm_mech_info.cm_func_group_mask;
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	/* min/max key sizes */
6290Sstevel@tonic-gate 	mech_info->mi_keysize_unit =
6300Sstevel@tonic-gate 	    pmd->pm_mech_info.cm_keysize_unit;
6310Sstevel@tonic-gate 	mech_info->mi_min_key_size =
6320Sstevel@tonic-gate 	    (size_t)pmd->pm_mech_info.cm_min_key_length;
6330Sstevel@tonic-gate 	mech_info->mi_max_key_size =
6340Sstevel@tonic-gate 	    (size_t)pmd->pm_mech_info.cm_max_key_length;
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	/* usage flag */
6370Sstevel@tonic-gate 	mech_info->mi_usage = 0;
6380Sstevel@tonic-gate 	if (fg & (CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC))
6390Sstevel@tonic-gate 		mech_info->mi_usage |= CRYPTO_MECH_USAGE_ENCRYPT;
6400Sstevel@tonic-gate 	if (fg & (CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC))
6410Sstevel@tonic-gate 		mech_info->mi_usage |= CRYPTO_MECH_USAGE_DECRYPT;
6420Sstevel@tonic-gate 	if (fg & (CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC))
6430Sstevel@tonic-gate 		mech_info->mi_usage |= CRYPTO_MECH_USAGE_MAC;
6440Sstevel@tonic-gate }
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate /*
6470Sstevel@tonic-gate  * Return the mechanism info for the specified mechanism.
6480Sstevel@tonic-gate  */
6490Sstevel@tonic-gate int
6500Sstevel@tonic-gate crypto_get_all_mech_info(crypto_mech_type_t mech_type,
6510Sstevel@tonic-gate     crypto_mechanism_info_t **mech_infos, uint_t *num_mech_infos,
6520Sstevel@tonic-gate     int km_flag)
6530Sstevel@tonic-gate {
6540Sstevel@tonic-gate 	uint_t ninfos, cur_info;
6550Sstevel@tonic-gate 	kcf_mech_entry_t *me;
6560Sstevel@tonic-gate 	int rv;
6570Sstevel@tonic-gate 	kcf_prov_mech_desc_t *hwp;
6580Sstevel@tonic-gate 	crypto_mechanism_info_t *infos;
6590Sstevel@tonic-gate 	size_t infos_size;
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	/* get to the mech entry corresponding to the specified mech type */
6620Sstevel@tonic-gate 	if ((rv = kcf_get_mech_entry(mech_type, &me)) != CRYPTO_SUCCESS) {
6630Sstevel@tonic-gate 		return (rv);
6640Sstevel@tonic-gate 	}
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	/* compute the number of key size ranges to return */
6670Sstevel@tonic-gate 	mutex_enter(&me->me_mutex);
6680Sstevel@tonic-gate again:
6690Sstevel@tonic-gate 	ninfos = PROV_COUNT(me);
6700Sstevel@tonic-gate 	mutex_exit(&me->me_mutex);
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	if (ninfos == 0) {
6730Sstevel@tonic-gate 		infos = NULL;
6740Sstevel@tonic-gate 		rv = CRYPTO_SUCCESS;
6750Sstevel@tonic-gate 		goto bail;
6760Sstevel@tonic-gate 	}
6770Sstevel@tonic-gate 	infos_size = ninfos * sizeof (crypto_mechanism_info_t);
6780Sstevel@tonic-gate 	infos = kmem_alloc(infos_size, km_flag);
6790Sstevel@tonic-gate 	if (infos == NULL) {
6800Sstevel@tonic-gate 		rv = CRYPTO_HOST_MEMORY;
6810Sstevel@tonic-gate 		goto bail;
6820Sstevel@tonic-gate 	}
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	mutex_enter(&me->me_mutex);
6850Sstevel@tonic-gate 	if (ninfos != PROV_COUNT(me)) {
6860Sstevel@tonic-gate 		kmem_free(infos, infos_size);
6870Sstevel@tonic-gate 		goto again;
6880Sstevel@tonic-gate 	}
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	/* populate array of crypto mechanism infos */
6910Sstevel@tonic-gate 	cur_info = 0;
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	/* software provider, if present */
6940Sstevel@tonic-gate 	if (me->me_sw_prov != NULL)
6950Sstevel@tonic-gate 		init_mechanism_info(&infos[cur_info++], me->me_sw_prov);
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	/* hardware providers */
6980Sstevel@tonic-gate 	for (hwp = me->me_hw_prov_chain; hwp != NULL; hwp = hwp->pm_next)
6990Sstevel@tonic-gate 		init_mechanism_info(&infos[cur_info++], hwp);
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	mutex_exit(&me->me_mutex);
7020Sstevel@tonic-gate 	ASSERT(cur_info == ninfos);
7030Sstevel@tonic-gate bail:
7040Sstevel@tonic-gate 	*mech_infos = infos;
7050Sstevel@tonic-gate 	*num_mech_infos = ninfos;
7060Sstevel@tonic-gate 	return (rv);
7070Sstevel@tonic-gate }
708*904Smcpowers 
709*904Smcpowers /*
710*904Smcpowers  * memcmp_pad_max() is a specialized version of memcmp() which
711*904Smcpowers  * compares two pieces of data up to a maximum length.  If the
712*904Smcpowers  * the two data match up the maximum length, they are considered
713*904Smcpowers  * matching.  Trailing blanks do not cause the match to fail if
714*904Smcpowers  * one of the data is shorter.
715*904Smcpowers  *
716*904Smcpowers  * Examples of matches:
717*904Smcpowers  *	"one"           |
718*904Smcpowers  *	"one      "     |
719*904Smcpowers  *	                ^maximum length
720*904Smcpowers  *
721*904Smcpowers  *	"Number One     |  X"	(X is beyond maximum length)
722*904Smcpowers  *	"Number One   " |
723*904Smcpowers  *	                ^maximum length
724*904Smcpowers  *
725*904Smcpowers  * Examples of mismatches:
726*904Smcpowers  *	" one"
727*904Smcpowers  *	"one"
728*904Smcpowers  *
729*904Smcpowers  *	"Number One    X|"
730*904Smcpowers  *	"Number One     |"
731*904Smcpowers  *	                ^maximum length
732*904Smcpowers  */
733*904Smcpowers static int
734*904Smcpowers memcmp_pad_max(void *d1, uint_t d1_len, void *d2, uint_t d2_len, uint_t max_sz)
735*904Smcpowers {
736*904Smcpowers 	uint_t		len, extra_len;
737*904Smcpowers 	char		*marker;
738*904Smcpowers 
739*904Smcpowers 	/* No point in comparing anything beyond max_sz */
740*904Smcpowers 	if (d1_len > max_sz)
741*904Smcpowers 		d1_len = max_sz;
742*904Smcpowers 	if (d2_len > max_sz)
743*904Smcpowers 		d2_len = max_sz;
744*904Smcpowers 
745*904Smcpowers 	/* Find shorter of the two data. */
746*904Smcpowers 	if (d1_len <= d2_len) {
747*904Smcpowers 		len = d1_len;
748*904Smcpowers 		extra_len = d2_len;
749*904Smcpowers 		marker = d2;
750*904Smcpowers 	} else {	/* d1_len > d2_len */
751*904Smcpowers 		len = d2_len;
752*904Smcpowers 		extra_len = d1_len;
753*904Smcpowers 		marker = d1;
754*904Smcpowers 	}
755*904Smcpowers 
756*904Smcpowers 	/* Have a match in the shortest length of data? */
757*904Smcpowers 	if (memcmp(d1, d2, len) != 0)
758*904Smcpowers 		/* CONSTCOND */
759*904Smcpowers 		return (!0);
760*904Smcpowers 
761*904Smcpowers 	/* If the rest of longer data is nulls or blanks, call it a match. */
762*904Smcpowers 	while (len < extra_len)
763*904Smcpowers 		if (!isspace(marker[len++]))
764*904Smcpowers 			/* CONSTCOND */
765*904Smcpowers 			return (!0);
766*904Smcpowers 	return (0);
767*904Smcpowers }
768*904Smcpowers 
769*904Smcpowers /*
770*904Smcpowers  * Obtain ext info for specified provider and see if it matches.
771*904Smcpowers  */
772*904Smcpowers static boolean_t
773*904Smcpowers match_ext_info(kcf_provider_desc_t *pd, char *label, char *manuf, char *serial,
774*904Smcpowers     crypto_provider_ext_info_t *ext_info)
775*904Smcpowers {
776*904Smcpowers 	kcf_provider_desc_t *real_provider;
777*904Smcpowers 	int rv;
778*904Smcpowers 	kcf_req_params_t params;
779*904Smcpowers 
780*904Smcpowers 	(void) kcf_get_hardware_provider_nomech(
781*904Smcpowers 	    CRYPTO_OPS_OFFSET(provider_ops), CRYPTO_PROVIDER_OFFSET(ext_info),
782*904Smcpowers 	    CHECK_RESTRICT_FALSE, pd, &real_provider);
783*904Smcpowers 
784*904Smcpowers 	if (real_provider != NULL) {
785*904Smcpowers 		ASSERT(real_provider == pd ||
786*904Smcpowers 		    pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER);
787*904Smcpowers 		KCF_WRAP_PROVMGMT_OPS_PARAMS(&params, KCF_OP_MGMT_EXTINFO,
788*904Smcpowers 		    0, NULL, 0, NULL, 0, NULL, ext_info, pd);
789*904Smcpowers 		rv = kcf_submit_request(real_provider, NULL, NULL, &params,
790*904Smcpowers 		    B_FALSE);
791*904Smcpowers 		ASSERT(rv != CRYPTO_NOT_SUPPORTED);
792*904Smcpowers 		KCF_PROV_REFRELE(real_provider);
793*904Smcpowers 	}
794*904Smcpowers 
795*904Smcpowers 	if (rv != CRYPTO_SUCCESS)
796*904Smcpowers 		return (B_FALSE);
797*904Smcpowers 
798*904Smcpowers 	if (memcmp_pad_max(ext_info->ei_label, CRYPTO_EXT_SIZE_LABEL,
799*904Smcpowers 	    label, strlen(label), CRYPTO_EXT_SIZE_LABEL))
800*904Smcpowers 		return (B_FALSE);
801*904Smcpowers 
802*904Smcpowers 	if (manuf != NULL) {
803*904Smcpowers 		if (memcmp_pad_max(ext_info->ei_manufacturerID,
804*904Smcpowers 		    CRYPTO_EXT_SIZE_MANUF, manuf, strlen(manuf),
805*904Smcpowers 		    CRYPTO_EXT_SIZE_MANUF))
806*904Smcpowers 			return (B_FALSE);
807*904Smcpowers 	}
808*904Smcpowers 
809*904Smcpowers 	if (serial != NULL) {
810*904Smcpowers 		if (memcmp_pad_max(ext_info->ei_serial_number,
811*904Smcpowers 		    CRYPTO_EXT_SIZE_SERIAL, label, strlen(label),
812*904Smcpowers 		    CRYPTO_EXT_SIZE_SERIAL))
813*904Smcpowers 			return (B_FALSE);
814*904Smcpowers 	}
815*904Smcpowers 	return (B_TRUE);
816*904Smcpowers }
817*904Smcpowers 
818*904Smcpowers /*
819*904Smcpowers  * Find a provider based on its label, manufacturer ID, and serial number.
820*904Smcpowers  */
821*904Smcpowers crypto_provider_t
822*904Smcpowers crypto_get_provider(char *label, char *manuf, char *serial)
823*904Smcpowers {
824*904Smcpowers 	kcf_provider_desc_t **provider_array, *pd;
825*904Smcpowers 	crypto_provider_ext_info_t *ext_info;
826*904Smcpowers 	uint_t count;
827*904Smcpowers 	int i;
828*904Smcpowers 
829*904Smcpowers 	/* manuf and serial are optional */
830*904Smcpowers 	if (label == NULL)
831*904Smcpowers 		return (NULL);
832*904Smcpowers 
833*904Smcpowers 	if (kcf_get_slot_list(&count, &provider_array, B_FALSE)
834*904Smcpowers 	    != CRYPTO_SUCCESS)
835*904Smcpowers 		return (NULL);
836*904Smcpowers 
837*904Smcpowers 	if (count == 0)
838*904Smcpowers 		return (NULL);
839*904Smcpowers 
840*904Smcpowers 	ext_info = kmem_zalloc(sizeof (crypto_provider_ext_info_t), KM_SLEEP);
841*904Smcpowers 
842*904Smcpowers 	for (i = 0; i < count; i++) {
843*904Smcpowers 		pd = provider_array[i];
844*904Smcpowers 		if (match_ext_info(pd, label, manuf, serial, ext_info)) {
845*904Smcpowers 			KCF_PROV_REFHOLD(pd);
846*904Smcpowers 			break;
847*904Smcpowers 		}
848*904Smcpowers 	}
849*904Smcpowers 	if (i == count)
850*904Smcpowers 		pd = NULL;
851*904Smcpowers 
852*904Smcpowers 	kcf_free_provider_tab(count, provider_array);
853*904Smcpowers 	kmem_free(ext_info, sizeof (crypto_provider_ext_info_t));
854*904Smcpowers 	return (pd);
855*904Smcpowers }
856*904Smcpowers 
857*904Smcpowers void
858*904Smcpowers crypto_release_provider(crypto_provider_t provider)
859*904Smcpowers {
860*904Smcpowers 	KCF_PROV_REFRELE((kcf_provider_desc_t *)provider);
861*904Smcpowers }
862