xref: /onnv-gate/usr/src/uts/common/crypto/api/kcf_miscapi.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/sunddi.h>
31*0Sstevel@tonic-gate #include <sys/disp.h>
32*0Sstevel@tonic-gate #include <sys/modctl.h>
33*0Sstevel@tonic-gate #include <sys/crypto/common.h>
34*0Sstevel@tonic-gate #include <sys/crypto/api.h>
35*0Sstevel@tonic-gate #include <sys/crypto/impl.h>
36*0Sstevel@tonic-gate #include <sys/crypto/sched_impl.h>
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate /* Miscellaneous exported entry points */
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate /*
41*0Sstevel@tonic-gate  * All event subscribers are put on a list. kcf_notify_list_lock
42*0Sstevel@tonic-gate  * protects changes to this list.
43*0Sstevel@tonic-gate  *
44*0Sstevel@tonic-gate  * The following locking order is maintained in the code - The
45*0Sstevel@tonic-gate  * global kcf_notify_list_lock followed by the individual lock
46*0Sstevel@tonic-gate  * in a kcf_ntfy_elem structure (kn_lock).
47*0Sstevel@tonic-gate  */
48*0Sstevel@tonic-gate kmutex_t		ntfy_list_lock;
49*0Sstevel@tonic-gate kcondvar_t		ntfy_list_cv;   /* cv the service thread waits on */
50*0Sstevel@tonic-gate static kcf_ntfy_elem_t *ntfy_list_head;
51*0Sstevel@tonic-gate static kcf_ntfy_elem_t *ntfy_list_tail;
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate /* count all the hardware and software providers */
54*0Sstevel@tonic-gate #define	PROV_COUNT(me) \
55*0Sstevel@tonic-gate 	(((me)->me_sw_prov != NULL ? 1 : 0) + (me)->me_num_hwprov)
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate /*
58*0Sstevel@tonic-gate  * crypto_mech2id()
59*0Sstevel@tonic-gate  *
60*0Sstevel@tonic-gate  * Arguments:
61*0Sstevel@tonic-gate  *	. mechname: A null-terminated string identifying the mechanism name.
62*0Sstevel@tonic-gate  *
63*0Sstevel@tonic-gate  * Description:
64*0Sstevel@tonic-gate  *	Walks the mechanisms tables, looking for an entry that matches the
65*0Sstevel@tonic-gate  *	mechname. Once it find it, it builds the 64-bit mech_type and returns
66*0Sstevel@tonic-gate  *	it.  If there are no hardware or software providers for the mechanism,
67*0Sstevel@tonic-gate  *	but there is an unloaded software provider, this routine will attempt
68*0Sstevel@tonic-gate  *	to load it.
69*0Sstevel@tonic-gate  *
70*0Sstevel@tonic-gate  * Context:
71*0Sstevel@tonic-gate  *	Process and interruption.
72*0Sstevel@tonic-gate  *
73*0Sstevel@tonic-gate  * Returns:
74*0Sstevel@tonic-gate  *	The unique mechanism identified by 'mechname', if found.
75*0Sstevel@tonic-gate  *	CRYPTO_MECH_INVALID otherwise.
76*0Sstevel@tonic-gate  */
77*0Sstevel@tonic-gate crypto_mech_type_t
78*0Sstevel@tonic-gate crypto_mech2id(char *mechname)
79*0Sstevel@tonic-gate {
80*0Sstevel@tonic-gate 	return (crypto_mech2id_common(mechname, B_TRUE));
81*0Sstevel@tonic-gate }
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate /*
84*0Sstevel@tonic-gate  * crypto_get_mech_list()
85*0Sstevel@tonic-gate  *
86*0Sstevel@tonic-gate  * Arguments:
87*0Sstevel@tonic-gate  *	. countp: pointer to contain the number of mech names returned
88*0Sstevel@tonic-gate  *	. kmflag: memory allocation flag.
89*0Sstevel@tonic-gate  *
90*0Sstevel@tonic-gate  * Description:
91*0Sstevel@tonic-gate  *	Allocates an array of crypto_mech_name_t containing all the mechanisms
92*0Sstevel@tonic-gate  *	currently available on the system. Sets *countp with the number of
93*0Sstevel@tonic-gate  *	mechanism names returned.
94*0Sstevel@tonic-gate  *
95*0Sstevel@tonic-gate  *	We get a list of mech names which have a hardware provider by walking
96*0Sstevel@tonic-gate  *	all the mechanism tables. We merge them with mech names obtained from
97*0Sstevel@tonic-gate  *	the hint list. A mech name in the hint list is considered only if it
98*0Sstevel@tonic-gate  *	is not disabled for the provider. Note that the hint list contains only
99*0Sstevel@tonic-gate  *	software providers and the mech names supported by them.
100*0Sstevel@tonic-gate  *
101*0Sstevel@tonic-gate  * Context:
102*0Sstevel@tonic-gate  *	Process and interruption. kmflag should be KM_NOSLEEP when called
103*0Sstevel@tonic-gate  *	from an interruption context.
104*0Sstevel@tonic-gate  *
105*0Sstevel@tonic-gate  * Returns:
106*0Sstevel@tonic-gate  *	The array of the crypto_mech_t allocated.
107*0Sstevel@tonic-gate  *	NULL otherwise.
108*0Sstevel@tonic-gate  */
109*0Sstevel@tonic-gate crypto_mech_name_t *
110*0Sstevel@tonic-gate crypto_get_mech_list(uint_t *countp, int kmflag)
111*0Sstevel@tonic-gate {
112*0Sstevel@tonic-gate 	uint_t count = 0, me_tab_size, i, j;
113*0Sstevel@tonic-gate 	kcf_ops_class_t cl;
114*0Sstevel@tonic-gate 	kcf_mech_entry_t *me, *me_tab;
115*0Sstevel@tonic-gate 	crypto_mech_name_t *mech_name_tab, *tmp_mech_name_tab;
116*0Sstevel@tonic-gate 	char *mech_name, *hint_mech, *end;
117*0Sstevel@tonic-gate 	kcf_soft_conf_entry_t *p;
118*0Sstevel@tonic-gate 	size_t n;
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	/*
121*0Sstevel@tonic-gate 	 * Count the maximum possible mechanisms that can come from the
122*0Sstevel@tonic-gate 	 * hint list.
123*0Sstevel@tonic-gate 	 */
124*0Sstevel@tonic-gate 	mutex_enter(&soft_config_mutex);
125*0Sstevel@tonic-gate 	p = soft_config_list;
126*0Sstevel@tonic-gate 	while (p != NULL) {
127*0Sstevel@tonic-gate 		count += p->ce_count;
128*0Sstevel@tonic-gate 		p = p->ce_next;
129*0Sstevel@tonic-gate 	}
130*0Sstevel@tonic-gate 	mutex_exit(&soft_config_mutex);
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate 	/* First let's count'em, for mem allocation */
133*0Sstevel@tonic-gate 	for (cl = KCF_FIRST_OPSCLASS; cl <= KCF_LAST_OPSCLASS; cl++) {
134*0Sstevel@tonic-gate 		me_tab_size = kcf_mech_tabs_tab[cl].met_size;
135*0Sstevel@tonic-gate 		me_tab = kcf_mech_tabs_tab[cl].met_tab;
136*0Sstevel@tonic-gate 		for (i = 0; i < me_tab_size; i++) {
137*0Sstevel@tonic-gate 			me = &me_tab[i];
138*0Sstevel@tonic-gate 			mutex_enter(&(me->me_mutex));
139*0Sstevel@tonic-gate 			if ((me->me_name[0] != 0) && (me->me_num_hwprov >= 1)) {
140*0Sstevel@tonic-gate 				ASSERT(me->me_hw_prov_chain != NULL);
141*0Sstevel@tonic-gate 				count++;
142*0Sstevel@tonic-gate 			}
143*0Sstevel@tonic-gate 			mutex_exit(&(me->me_mutex));
144*0Sstevel@tonic-gate 		}
145*0Sstevel@tonic-gate 	}
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	/*
148*0Sstevel@tonic-gate 	 * Allocate a buffer to hold the mechanisms from
149*0Sstevel@tonic-gate 	 * mech tabs and mechanisms from the hint list.
150*0Sstevel@tonic-gate 	 */
151*0Sstevel@tonic-gate 	n = count * CRYPTO_MAX_MECH_NAME;
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate again:
154*0Sstevel@tonic-gate 	count = 0;
155*0Sstevel@tonic-gate 	tmp_mech_name_tab = kmem_zalloc(n, kmflag);
156*0Sstevel@tonic-gate 	if (tmp_mech_name_tab == NULL) {
157*0Sstevel@tonic-gate 		*countp = 0;
158*0Sstevel@tonic-gate 		return (NULL);
159*0Sstevel@tonic-gate 	}
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	/*
162*0Sstevel@tonic-gate 	 * Second round, fill in the table
163*0Sstevel@tonic-gate 	 */
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	mech_name = (char *)tmp_mech_name_tab;
166*0Sstevel@tonic-gate 	end = mech_name + n;
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	for (cl = KCF_FIRST_OPSCLASS; cl <= KCF_LAST_OPSCLASS; cl++) {
169*0Sstevel@tonic-gate 		me_tab_size = kcf_mech_tabs_tab[cl].met_size;
170*0Sstevel@tonic-gate 		me_tab = kcf_mech_tabs_tab[cl].met_tab;
171*0Sstevel@tonic-gate 		for (i = 0; i < me_tab_size; i++) {
172*0Sstevel@tonic-gate 			me = &me_tab[i];
173*0Sstevel@tonic-gate 			mutex_enter(&(me->me_mutex));
174*0Sstevel@tonic-gate 			if ((me->me_name[0] != 0) && (me->me_num_hwprov >= 1)) {
175*0Sstevel@tonic-gate 				ASSERT(me->me_hw_prov_chain != NULL);
176*0Sstevel@tonic-gate 				if ((mech_name + CRYPTO_MAX_MECH_NAME) > end) {
177*0Sstevel@tonic-gate 					mutex_exit(&(me->me_mutex));
178*0Sstevel@tonic-gate 					kmem_free(tmp_mech_name_tab, n);
179*0Sstevel@tonic-gate 					n = n << 1;
180*0Sstevel@tonic-gate 					goto again;
181*0Sstevel@tonic-gate 				}
182*0Sstevel@tonic-gate 				(void) strncpy(mech_name, me->me_name,
183*0Sstevel@tonic-gate 				    CRYPTO_MAX_MECH_NAME);
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 				mech_name += CRYPTO_MAX_MECH_NAME;
186*0Sstevel@tonic-gate 				count++;
187*0Sstevel@tonic-gate 			}
188*0Sstevel@tonic-gate 			mutex_exit(&(me->me_mutex));
189*0Sstevel@tonic-gate 		}
190*0Sstevel@tonic-gate 	}
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 	/*
193*0Sstevel@tonic-gate 	 * Search tmp_mech_name_tab for each mechanism in the hint list. We
194*0Sstevel@tonic-gate 	 * have to add any new mechanisms found in the hint list. Note that we
195*0Sstevel@tonic-gate 	 * should not modload the providers here as it will be too early. It
196*0Sstevel@tonic-gate 	 * may be the case that the caller never uses a provider.
197*0Sstevel@tonic-gate 	 */
198*0Sstevel@tonic-gate 	mutex_enter(&soft_config_mutex);
199*0Sstevel@tonic-gate 	p = soft_config_list;
200*0Sstevel@tonic-gate 	while (p != NULL) {
201*0Sstevel@tonic-gate 		for (i = 0; i < p->ce_count; i++) {
202*0Sstevel@tonic-gate 			hint_mech = p->ce_mechs[i];
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 			/* Do not consider the mechanism if it is disabled. */
205*0Sstevel@tonic-gate 			if (is_mech_disabled_byname(CRYPTO_SW_PROVIDER,
206*0Sstevel@tonic-gate 			    p->ce_name, 0, hint_mech))
207*0Sstevel@tonic-gate 				continue;
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 			/*
210*0Sstevel@tonic-gate 			 * There may be duplicate mechanisms in the hint list.
211*0Sstevel@tonic-gate 			 * So, we need to search all the entries that have been
212*0Sstevel@tonic-gate 			 * added so far. That number would be count.
213*0Sstevel@tonic-gate 			 */
214*0Sstevel@tonic-gate 			for (j = 0; j < count; j++) {
215*0Sstevel@tonic-gate 				if (strcmp(hint_mech,
216*0Sstevel@tonic-gate 				    tmp_mech_name_tab[j]) == 0)
217*0Sstevel@tonic-gate 					break;
218*0Sstevel@tonic-gate 			}
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 			if (j == count) {	/* This is a new one. Add it. */
221*0Sstevel@tonic-gate 				ASSERT((char *)&tmp_mech_name_tab[count] ==
222*0Sstevel@tonic-gate 				    mech_name);
223*0Sstevel@tonic-gate 				if ((mech_name + CRYPTO_MAX_MECH_NAME) > end) {
224*0Sstevel@tonic-gate 					mutex_exit(&soft_config_mutex);
225*0Sstevel@tonic-gate 					kmem_free(tmp_mech_name_tab, n);
226*0Sstevel@tonic-gate 					n = n << 1;
227*0Sstevel@tonic-gate 					goto again;
228*0Sstevel@tonic-gate 				}
229*0Sstevel@tonic-gate 				(void) strncpy(tmp_mech_name_tab[count],
230*0Sstevel@tonic-gate 				    hint_mech, CRYPTO_MAX_MECH_NAME);
231*0Sstevel@tonic-gate 				mech_name += CRYPTO_MAX_MECH_NAME;
232*0Sstevel@tonic-gate 				count++;
233*0Sstevel@tonic-gate 			}
234*0Sstevel@tonic-gate 		}
235*0Sstevel@tonic-gate 		p = p->ce_next;
236*0Sstevel@tonic-gate 	}
237*0Sstevel@tonic-gate 	mutex_exit(&soft_config_mutex);
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 	/*
240*0Sstevel@tonic-gate 	 * Check if we have consumed all of the space. We are done if
241*0Sstevel@tonic-gate 	 * this is the case.
242*0Sstevel@tonic-gate 	 */
243*0Sstevel@tonic-gate 	ASSERT(mech_name <= end);
244*0Sstevel@tonic-gate 	if (mech_name == end) {
245*0Sstevel@tonic-gate 		mech_name_tab = tmp_mech_name_tab;
246*0Sstevel@tonic-gate 		goto done;
247*0Sstevel@tonic-gate 	}
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	/*
250*0Sstevel@tonic-gate 	 * Allocate a buffer of the right size now that we have the
251*0Sstevel@tonic-gate 	 * correct count.
252*0Sstevel@tonic-gate 	 */
253*0Sstevel@tonic-gate 	mech_name_tab = kmem_zalloc(count * CRYPTO_MAX_MECH_NAME, kmflag);
254*0Sstevel@tonic-gate 	if (mech_name_tab == NULL) {
255*0Sstevel@tonic-gate 		kmem_free(tmp_mech_name_tab, n);
256*0Sstevel@tonic-gate 		*countp = 0;
257*0Sstevel@tonic-gate 		return (NULL);
258*0Sstevel@tonic-gate 	}
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	bcopy(tmp_mech_name_tab, mech_name_tab, count * CRYPTO_MAX_MECH_NAME);
261*0Sstevel@tonic-gate 	kmem_free(tmp_mech_name_tab, n);
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate done:
264*0Sstevel@tonic-gate 	*countp = count;
265*0Sstevel@tonic-gate 	return (mech_name_tab);
266*0Sstevel@tonic-gate }
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate /*
269*0Sstevel@tonic-gate  * crypto_free_mech_list()
270*0Sstevel@tonic-gate  *
271*0Sstevel@tonic-gate  * Arguments:
272*0Sstevel@tonic-gate  *	. mech_names: An array of crypto_mech_name_t previously allocated by
273*0Sstevel@tonic-gate  *	  crypto_get_mech_list.
274*0Sstevel@tonic-gate  *	. count: the number of mech names in mech_names
275*0Sstevel@tonic-gate  *
276*0Sstevel@tonic-gate  * Description:
277*0Sstevel@tonic-gate  *	Frees the the mech_names array.
278*0Sstevel@tonic-gate  *
279*0Sstevel@tonic-gate  * Context:
280*0Sstevel@tonic-gate  *	Process and interruption.
281*0Sstevel@tonic-gate  */
282*0Sstevel@tonic-gate void
283*0Sstevel@tonic-gate crypto_free_mech_list(crypto_mech_name_t *mech_names, uint_t count)
284*0Sstevel@tonic-gate {
285*0Sstevel@tonic-gate 	if ((mech_names != NULL) && (count > 0))
286*0Sstevel@tonic-gate 		kmem_free(mech_names, count * CRYPTO_MAX_MECH_NAME);
287*0Sstevel@tonic-gate }
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate /*
290*0Sstevel@tonic-gate  * crypto_notify_events()
291*0Sstevel@tonic-gate  *
292*0Sstevel@tonic-gate  * Arguments:
293*0Sstevel@tonic-gate  *	. nf: Callback function to invoke when event occurs.
294*0Sstevel@tonic-gate  *	. event_mask: Mask of events.
295*0Sstevel@tonic-gate  *
296*0Sstevel@tonic-gate  * Description:
297*0Sstevel@tonic-gate  *	Allocates a new element and inserts it in to the notification
298*0Sstevel@tonic-gate  *	list.
299*0Sstevel@tonic-gate  *
300*0Sstevel@tonic-gate  * Context:
301*0Sstevel@tonic-gate  *	Process context.
302*0Sstevel@tonic-gate  *
303*0Sstevel@tonic-gate  * Returns:
304*0Sstevel@tonic-gate  *	A handle is returned if the client is put on the notification list.
305*0Sstevel@tonic-gate  *	NULL is returned otherwise.
306*0Sstevel@tonic-gate  */
307*0Sstevel@tonic-gate crypto_notify_handle_t
308*0Sstevel@tonic-gate crypto_notify_events(crypto_notify_callback_t nf, uint32_t event_mask)
309*0Sstevel@tonic-gate {
310*0Sstevel@tonic-gate 	kcf_ntfy_elem_t *nep;
311*0Sstevel@tonic-gate 	crypto_notify_handle_t hndl;
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate 	/*
314*0Sstevel@tonic-gate 	 * The only valid value for event_mask is CRYPTO_EVENT_PROVIDERS_CHANGE.
315*0Sstevel@tonic-gate 	 */
316*0Sstevel@tonic-gate 	if (nf == NULL || !(event_mask & CRYPTO_EVENT_PROVIDERS_CHANGE)) {
317*0Sstevel@tonic-gate 		return (NULL);
318*0Sstevel@tonic-gate 	}
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 	nep = kmem_zalloc(sizeof (kcf_ntfy_elem_t), KM_SLEEP);
321*0Sstevel@tonic-gate 	mutex_init(&nep->kn_lock, NULL, MUTEX_DEFAULT, NULL);
322*0Sstevel@tonic-gate 	cv_init(&nep->kn_cv, NULL, CV_DEFAULT, NULL);
323*0Sstevel@tonic-gate 	nep->kn_state = NTFY_WAITING;
324*0Sstevel@tonic-gate 	nep->kn_func = nf;
325*0Sstevel@tonic-gate 	nep->kn_event_mask = event_mask;
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	mutex_enter(&ntfy_list_lock);
328*0Sstevel@tonic-gate 	if (ntfy_list_head == NULL) {
329*0Sstevel@tonic-gate 		ntfy_list_head = ntfy_list_tail = nep;
330*0Sstevel@tonic-gate 	} else {
331*0Sstevel@tonic-gate 		ntfy_list_tail->kn_next = nep;
332*0Sstevel@tonic-gate 		nep->kn_prev = ntfy_list_tail;
333*0Sstevel@tonic-gate 		ntfy_list_tail = nep;
334*0Sstevel@tonic-gate 	}
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	hndl = (crypto_notify_handle_t)nep;
337*0Sstevel@tonic-gate 	mutex_exit(&ntfy_list_lock);
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 	return (hndl);
340*0Sstevel@tonic-gate }
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate /*
343*0Sstevel@tonic-gate  * crypto_unnotify_events()
344*0Sstevel@tonic-gate  *
345*0Sstevel@tonic-gate  * Arguments:
346*0Sstevel@tonic-gate  *	. hndl - Handle returned from an earlier crypto_notify_events().
347*0Sstevel@tonic-gate  *
348*0Sstevel@tonic-gate  * Description:
349*0Sstevel@tonic-gate  *	Removes the element specified by hndl from the notification list.
350*0Sstevel@tonic-gate  *	We wait for the notification routine to complete, if the routine
351*0Sstevel@tonic-gate  *	is currently being called. We also free the element.
352*0Sstevel@tonic-gate  *
353*0Sstevel@tonic-gate  * Context:
354*0Sstevel@tonic-gate  *	Process context.
355*0Sstevel@tonic-gate  */
356*0Sstevel@tonic-gate void
357*0Sstevel@tonic-gate crypto_unnotify_events(crypto_notify_handle_t hndl)
358*0Sstevel@tonic-gate {
359*0Sstevel@tonic-gate 	kcf_ntfy_elem_t *nep = (kcf_ntfy_elem_t *)hndl;
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 	if (hndl == NULL)
362*0Sstevel@tonic-gate 		return;
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate retry:
365*0Sstevel@tonic-gate 	mutex_enter(&ntfy_list_lock);
366*0Sstevel@tonic-gate 	mutex_enter(&nep->kn_lock);
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	if (nep->kn_state == NTFY_WAITING) {
369*0Sstevel@tonic-gate 		kcf_ntfy_elem_t *nextp = nep->kn_next;
370*0Sstevel@tonic-gate 		kcf_ntfy_elem_t *prevp = nep->kn_prev;
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 		if (nextp != NULL)
373*0Sstevel@tonic-gate 			nextp->kn_prev = prevp;
374*0Sstevel@tonic-gate 		else
375*0Sstevel@tonic-gate 			ntfy_list_tail = prevp;
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 		if (prevp != NULL)
378*0Sstevel@tonic-gate 			prevp->kn_next = nextp;
379*0Sstevel@tonic-gate 		else
380*0Sstevel@tonic-gate 			ntfy_list_head = nextp;
381*0Sstevel@tonic-gate 	} else {
382*0Sstevel@tonic-gate 		ASSERT(nep->kn_state == NTFY_RUNNING);
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 		/*
385*0Sstevel@tonic-gate 		 * We have to drop this lock as the client might call
386*0Sstevel@tonic-gate 		 * crypto_notify_events() in the callback routine resulting
387*0Sstevel@tonic-gate 		 * in a deadlock.
388*0Sstevel@tonic-gate 		 */
389*0Sstevel@tonic-gate 		mutex_exit(&ntfy_list_lock);
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 		/*
392*0Sstevel@tonic-gate 		 * Another thread is working on this element. We will wait
393*0Sstevel@tonic-gate 		 * for that thread to signal us when done. No other thread
394*0Sstevel@tonic-gate 		 * will free this element. So, we can be sure it stays valid
395*0Sstevel@tonic-gate 		 * after the wait.
396*0Sstevel@tonic-gate 		 */
397*0Sstevel@tonic-gate 		while (nep->kn_state == NTFY_RUNNING)
398*0Sstevel@tonic-gate 			cv_wait(&nep->kn_cv, &nep->kn_lock);
399*0Sstevel@tonic-gate 		mutex_exit(&nep->kn_lock);
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate 		/*
402*0Sstevel@tonic-gate 		 * We have to remove the element from the notification list.
403*0Sstevel@tonic-gate 		 * So, start over and do the work (acquire locks etc.). This is
404*0Sstevel@tonic-gate 		 * safe (i.e. We won't be in this routine forever) as the
405*0Sstevel@tonic-gate 		 * CRYPTO_EVENT_PROVIDERS_CHANGE event does not happen
406*0Sstevel@tonic-gate 		 * frequently. We have to revisit this code if we
407*0Sstevel@tonic-gate 		 * add a new event that happens often.
408*0Sstevel@tonic-gate 		 */
409*0Sstevel@tonic-gate 		goto retry;
410*0Sstevel@tonic-gate 	}
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 	mutex_exit(&nep->kn_lock);
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	/* Free the element */
415*0Sstevel@tonic-gate 	mutex_destroy(&nep->kn_lock);
416*0Sstevel@tonic-gate 	cv_destroy(&nep->kn_cv);
417*0Sstevel@tonic-gate 	kmem_free(nep, sizeof (kcf_ntfy_elem_t));
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate 	mutex_exit(&ntfy_list_lock);
420*0Sstevel@tonic-gate }
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate /*
423*0Sstevel@tonic-gate  * This routine is called from crypto_register_provider() and
424*0Sstevel@tonic-gate  * crypto_unregister_provider() with the CRYPTO_EVENT_PROVIDERS_CHANGE event.
425*0Sstevel@tonic-gate  *
426*0Sstevel@tonic-gate  * We walk the notification list and do the callbacks.
427*0Sstevel@tonic-gate  */
428*0Sstevel@tonic-gate void
429*0Sstevel@tonic-gate kcf_walk_ntfylist(uint32_t event, void *event_arg)
430*0Sstevel@tonic-gate {
431*0Sstevel@tonic-gate 	kcf_ntfy_elem_t *nep;
432*0Sstevel@tonic-gate 	int nelem = 0;
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	mutex_enter(&ntfy_list_lock);
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 	/*
437*0Sstevel@tonic-gate 	 * Count how many clients are on the notification list. We need
438*0Sstevel@tonic-gate 	 * this count to ensure that clients which joined the list after we
439*0Sstevel@tonic-gate 	 * have started this walk, are not wrongly notified.
440*0Sstevel@tonic-gate 	 */
441*0Sstevel@tonic-gate 	for (nep = ntfy_list_head; nep != NULL; nep = nep->kn_next)
442*0Sstevel@tonic-gate 		nelem++;
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate 	for (nep = ntfy_list_head; (nep != NULL && nelem); nep = nep->kn_next) {
445*0Sstevel@tonic-gate 		nelem--;
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 		/*
448*0Sstevel@tonic-gate 		 * Check if this client is interested in the
449*0Sstevel@tonic-gate 		 * event.
450*0Sstevel@tonic-gate 		 */
451*0Sstevel@tonic-gate 		if (!(nep->kn_event_mask & event))
452*0Sstevel@tonic-gate 			continue;
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 		mutex_enter(&nep->kn_lock);
455*0Sstevel@tonic-gate 		nep->kn_state = NTFY_RUNNING;
456*0Sstevel@tonic-gate 		mutex_exit(&nep->kn_lock);
457*0Sstevel@tonic-gate 		mutex_exit(&ntfy_list_lock);
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 		/*
460*0Sstevel@tonic-gate 		 * We invoke the callback routine with no locks held. Another
461*0Sstevel@tonic-gate 		 * client could have joined the list meanwhile. This is fine
462*0Sstevel@tonic-gate 		 * as we maintain nelem as stated above. The NULL check in the
463*0Sstevel@tonic-gate 		 * for loop guards against shrinkage. Also, any callers of
464*0Sstevel@tonic-gate 		 * crypto_unnotify_events() at this point cv_wait till kn_state
465*0Sstevel@tonic-gate 		 * changes to NTFY_WAITING. Hence, nep is assured to be valid.
466*0Sstevel@tonic-gate 		 */
467*0Sstevel@tonic-gate 		(*nep->kn_func)(event, event_arg);
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate 		mutex_enter(&nep->kn_lock);
470*0Sstevel@tonic-gate 		nep->kn_state = NTFY_WAITING;
471*0Sstevel@tonic-gate 		cv_broadcast(&nep->kn_cv);
472*0Sstevel@tonic-gate 		mutex_exit(&nep->kn_lock);
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 		mutex_enter(&ntfy_list_lock);
475*0Sstevel@tonic-gate 	}
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate 	mutex_exit(&ntfy_list_lock);
478*0Sstevel@tonic-gate }
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate /*
481*0Sstevel@tonic-gate  * crypto_key_check()
482*0Sstevel@tonic-gate  *
483*0Sstevel@tonic-gate  * Arguments:
484*0Sstevel@tonic-gate  *	. mech: the mechanism to check the key with.
485*0Sstevel@tonic-gate  *	. key: the key to check for validity and weakness.
486*0Sstevel@tonic-gate  *
487*0Sstevel@tonic-gate  * Description:
488*0Sstevel@tonic-gate  *	Checks the validity and strength of the key for the mechanism.
489*0Sstevel@tonic-gate  *	CRYPTO_KEY_REFERENCE is not supported for this routine.
490*0Sstevel@tonic-gate  *	If more than one provider is capable of key checking for the mechanism,
491*0Sstevel@tonic-gate  *	then run the key through them all.
492*0Sstevel@tonic-gate  *	A conservative approach is adopted here: New weak keys may be
493*0Sstevel@tonic-gate  *	discovered with more recent providers. If at least one provider is
494*0Sstevel@tonic-gate  *	not happy with a key, then it is no good.
495*0Sstevel@tonic-gate  *
496*0Sstevel@tonic-gate  * Context:
497*0Sstevel@tonic-gate  *	Process and interruption.
498*0Sstevel@tonic-gate  */
499*0Sstevel@tonic-gate int
500*0Sstevel@tonic-gate crypto_key_check(crypto_mechanism_t *mech, crypto_key_t *key)
501*0Sstevel@tonic-gate {
502*0Sstevel@tonic-gate 	int error;
503*0Sstevel@tonic-gate 	kcf_mech_entry_t *me;
504*0Sstevel@tonic-gate 	kcf_provider_desc_t *pd;
505*0Sstevel@tonic-gate 	kcf_prov_mech_desc_t *prov_chain;
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	/* when mech is a valid mechanism, me will be its mech_entry */
508*0Sstevel@tonic-gate 	if ((mech == NULL) || (key == NULL) ||
509*0Sstevel@tonic-gate 	    (key->ck_format == CRYPTO_KEY_REFERENCE))
510*0Sstevel@tonic-gate 		return (CRYPTO_ARGUMENTS_BAD);
511*0Sstevel@tonic-gate 
512*0Sstevel@tonic-gate 	if ((error = kcf_get_mech_entry(mech->cm_type, &me)) != KCF_SUCCESS) {
513*0Sstevel@tonic-gate 		/* error is one of the KCF_INVALID_MECH_XXX's */
514*0Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
515*0Sstevel@tonic-gate 	}
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 	mutex_enter(&me->me_mutex);
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 	/* First let the software provider check this key */
520*0Sstevel@tonic-gate 	if (me->me_sw_prov != NULL) {
521*0Sstevel@tonic-gate 		pd = me->me_sw_prov->pm_prov_desc;
522*0Sstevel@tonic-gate 		KCF_PROV_REFHOLD(pd);
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 		if ((KCF_PROV_KEY_OPS(pd) != NULL) &&
525*0Sstevel@tonic-gate 		    (KCF_PROV_KEY_OPS(pd)->key_check != NULL)) {
526*0Sstevel@tonic-gate 			crypto_mechanism_t lmech;
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 			mutex_exit(&me->me_mutex);
529*0Sstevel@tonic-gate 			lmech = *mech;
530*0Sstevel@tonic-gate 			KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
531*0Sstevel@tonic-gate 			error = KCF_PROV_KEY_CHECK(pd, &lmech, key);
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 			if (error != CRYPTO_SUCCESS) {
534*0Sstevel@tonic-gate 				KCF_PROV_REFRELE(pd);
535*0Sstevel@tonic-gate 				return (error);
536*0Sstevel@tonic-gate 			}
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate 			mutex_enter(&me->me_mutex);
539*0Sstevel@tonic-gate 		}
540*0Sstevel@tonic-gate 		KCF_PROV_REFRELE(pd);
541*0Sstevel@tonic-gate 	}
542*0Sstevel@tonic-gate 
543*0Sstevel@tonic-gate 	prov_chain = me->me_hw_prov_chain;
544*0Sstevel@tonic-gate 	while (prov_chain != NULL) {
545*0Sstevel@tonic-gate 		pd = prov_chain->pm_prov_desc;
546*0Sstevel@tonic-gate 		KCF_PROV_REFHOLD(pd);
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate 		if ((KCF_PROV_KEY_OPS(pd) != NULL) &&
549*0Sstevel@tonic-gate 		    (KCF_PROV_KEY_OPS(pd)->key_check != NULL)) {
550*0Sstevel@tonic-gate 			crypto_mechanism_t lmech;
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate 			mutex_exit(&me->me_mutex);
553*0Sstevel@tonic-gate 			lmech = *mech;
554*0Sstevel@tonic-gate 			KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd,
555*0Sstevel@tonic-gate 			    &lmech);
556*0Sstevel@tonic-gate 			error = KCF_PROV_KEY_CHECK(pd, &lmech, key);
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate 			if (error != CRYPTO_SUCCESS) {
559*0Sstevel@tonic-gate 				KCF_PROV_REFRELE(pd);
560*0Sstevel@tonic-gate 				return (error);
561*0Sstevel@tonic-gate 			}
562*0Sstevel@tonic-gate 			mutex_enter(&me->me_mutex);
563*0Sstevel@tonic-gate 		}
564*0Sstevel@tonic-gate 		KCF_PROV_REFRELE(pd);
565*0Sstevel@tonic-gate 		prov_chain = prov_chain->pm_next;
566*0Sstevel@tonic-gate 	}
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 	mutex_exit(&me->me_mutex);
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate 	/* All are happy with this key */
571*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
572*0Sstevel@tonic-gate }
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate /*
575*0Sstevel@tonic-gate  * Initialize the specified crypto_mechanism_info_t structure for
576*0Sstevel@tonic-gate  * the specified mechanism provider descriptor. Used by
577*0Sstevel@tonic-gate  * crypto_get_all_mech_info().
578*0Sstevel@tonic-gate  */
579*0Sstevel@tonic-gate static void
580*0Sstevel@tonic-gate init_mechanism_info(crypto_mechanism_info_t *mech_info,
581*0Sstevel@tonic-gate     kcf_prov_mech_desc_t *pmd)
582*0Sstevel@tonic-gate {
583*0Sstevel@tonic-gate 	crypto_func_group_t fg = pmd->pm_mech_info.cm_func_group_mask;
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 	/* min/max key sizes */
586*0Sstevel@tonic-gate 	mech_info->mi_keysize_unit =
587*0Sstevel@tonic-gate 	    pmd->pm_mech_info.cm_keysize_unit;
588*0Sstevel@tonic-gate 	mech_info->mi_min_key_size =
589*0Sstevel@tonic-gate 	    (size_t)pmd->pm_mech_info.cm_min_key_length;
590*0Sstevel@tonic-gate 	mech_info->mi_max_key_size =
591*0Sstevel@tonic-gate 	    (size_t)pmd->pm_mech_info.cm_max_key_length;
592*0Sstevel@tonic-gate 
593*0Sstevel@tonic-gate 	/* usage flag */
594*0Sstevel@tonic-gate 	mech_info->mi_usage = 0;
595*0Sstevel@tonic-gate 	if (fg & (CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC))
596*0Sstevel@tonic-gate 		mech_info->mi_usage |= CRYPTO_MECH_USAGE_ENCRYPT;
597*0Sstevel@tonic-gate 	if (fg & (CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC))
598*0Sstevel@tonic-gate 		mech_info->mi_usage |= CRYPTO_MECH_USAGE_DECRYPT;
599*0Sstevel@tonic-gate 	if (fg & (CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC))
600*0Sstevel@tonic-gate 		mech_info->mi_usage |= CRYPTO_MECH_USAGE_MAC;
601*0Sstevel@tonic-gate }
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate /*
604*0Sstevel@tonic-gate  * Return the mechanism info for the specified mechanism.
605*0Sstevel@tonic-gate  */
606*0Sstevel@tonic-gate int
607*0Sstevel@tonic-gate crypto_get_all_mech_info(crypto_mech_type_t mech_type,
608*0Sstevel@tonic-gate     crypto_mechanism_info_t **mech_infos, uint_t *num_mech_infos,
609*0Sstevel@tonic-gate     int km_flag)
610*0Sstevel@tonic-gate {
611*0Sstevel@tonic-gate 	uint_t ninfos, cur_info;
612*0Sstevel@tonic-gate 	kcf_mech_entry_t *me;
613*0Sstevel@tonic-gate 	int rv;
614*0Sstevel@tonic-gate 	kcf_prov_mech_desc_t *hwp;
615*0Sstevel@tonic-gate 	crypto_mechanism_info_t *infos;
616*0Sstevel@tonic-gate 	size_t infos_size;
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate 	/* get to the mech entry corresponding to the specified mech type */
619*0Sstevel@tonic-gate 	if ((rv = kcf_get_mech_entry(mech_type, &me)) != CRYPTO_SUCCESS) {
620*0Sstevel@tonic-gate 		return (rv);
621*0Sstevel@tonic-gate 	}
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 	/* compute the number of key size ranges to return */
624*0Sstevel@tonic-gate 	mutex_enter(&me->me_mutex);
625*0Sstevel@tonic-gate again:
626*0Sstevel@tonic-gate 	ninfos = PROV_COUNT(me);
627*0Sstevel@tonic-gate 	mutex_exit(&me->me_mutex);
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	if (ninfos == 0) {
630*0Sstevel@tonic-gate 		infos = NULL;
631*0Sstevel@tonic-gate 		rv = CRYPTO_SUCCESS;
632*0Sstevel@tonic-gate 		goto bail;
633*0Sstevel@tonic-gate 	}
634*0Sstevel@tonic-gate 	infos_size = ninfos * sizeof (crypto_mechanism_info_t);
635*0Sstevel@tonic-gate 	infos = kmem_alloc(infos_size, km_flag);
636*0Sstevel@tonic-gate 	if (infos == NULL) {
637*0Sstevel@tonic-gate 		rv = CRYPTO_HOST_MEMORY;
638*0Sstevel@tonic-gate 		goto bail;
639*0Sstevel@tonic-gate 	}
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate 	mutex_enter(&me->me_mutex);
642*0Sstevel@tonic-gate 	if (ninfos != PROV_COUNT(me)) {
643*0Sstevel@tonic-gate 		kmem_free(infos, infos_size);
644*0Sstevel@tonic-gate 		goto again;
645*0Sstevel@tonic-gate 	}
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	/* populate array of crypto mechanism infos */
648*0Sstevel@tonic-gate 	cur_info = 0;
649*0Sstevel@tonic-gate 
650*0Sstevel@tonic-gate 	/* software provider, if present */
651*0Sstevel@tonic-gate 	if (me->me_sw_prov != NULL)
652*0Sstevel@tonic-gate 		init_mechanism_info(&infos[cur_info++], me->me_sw_prov);
653*0Sstevel@tonic-gate 
654*0Sstevel@tonic-gate 	/* hardware providers */
655*0Sstevel@tonic-gate 	for (hwp = me->me_hw_prov_chain; hwp != NULL; hwp = hwp->pm_next)
656*0Sstevel@tonic-gate 		init_mechanism_info(&infos[cur_info++], hwp);
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate 	mutex_exit(&me->me_mutex);
659*0Sstevel@tonic-gate 	ASSERT(cur_info == ninfos);
660*0Sstevel@tonic-gate bail:
661*0Sstevel@tonic-gate 	*mech_infos = infos;
662*0Sstevel@tonic-gate 	*num_mech_infos = ninfos;
663*0Sstevel@tonic-gate 	return (rv);
664*0Sstevel@tonic-gate }
665