xref: /illumos-gate/usr/src/uts/common/crypto/api/kcf_miscapi.c (revision de81e71e031139a0a7f13b7bf64152c3faa76698)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/sunddi.h>
28 #include <sys/disp.h>
29 #include <sys/modctl.h>
30 #include <sys/sysmacros.h>
31 #include <sys/crypto/common.h>
32 #include <sys/crypto/api.h>
33 #include <sys/crypto/impl.h>
34 #include <sys/crypto/sched_impl.h>
35 
36 #define	isspace(ch)	(((ch) == ' ') || ((ch) == '\r') || ((ch) == '\n') || \
37 			((ch) == '\t') || ((ch) == '\f'))
38 
39 #define	CRYPTO_OPS_OFFSET(f)		offsetof(crypto_ops_t, co_##f)
40 #define	CRYPTO_KEY_OFFSET(f)		offsetof(crypto_key_ops_t, f)
41 #define	CRYPTO_PROVIDER_OFFSET(f)	\
42 	offsetof(crypto_provider_management_ops_t, f)
43 
44 /* Miscellaneous exported entry points */
45 
46 /*
47  * All event subscribers are put on a list. kcf_notify_list_lock
48  * protects changes to this list.
49  *
50  * The following locking order is maintained in the code - The
51  * global kcf_notify_list_lock followed by the individual lock
52  * in a kcf_ntfy_elem structure (kn_lock).
53  */
54 kmutex_t		ntfy_list_lock;
55 kcondvar_t		ntfy_list_cv;   /* cv the service thread waits on */
56 static kcf_ntfy_elem_t *ntfy_list_head;
57 static kcf_ntfy_elem_t *ntfy_list_tail;
58 
59 /* count all the hardware and software providers */
60 #define	PROV_COUNT(me) \
61 	(((me)->me_sw_prov != NULL ? 1 : 0) + (me)->me_num_hwprov)
62 
63 /*
64  * crypto_mech2id()
65  *
66  * Arguments:
67  *	. mechname: A null-terminated string identifying the mechanism name.
68  *
69  * Description:
70  *	Walks the mechanisms tables, looking for an entry that matches the
71  *	mechname. Once it find it, it builds the 64-bit mech_type and returns
72  *	it.  If there are no hardware or software providers for the mechanism,
73  *	but there is an unloaded software provider, this routine will attempt
74  *	to load it.
75  *
76  * Context:
77  *	Process and interruption.
78  *
79  * Returns:
80  *	The unique mechanism identified by 'mechname', if found.
81  *	CRYPTO_MECH_INVALID otherwise.
82  */
83 crypto_mech_type_t
84 crypto_mech2id(char *mechname)
85 {
86 	return (crypto_mech2id_common(mechname, B_TRUE));
87 }
88 
89 /*
90  * crypto_get_mech_list()
91  *
92  * Arguments:
93  *	. countp: pointer to contain the number of mech names returned
94  *	. kmflag: memory allocation flag.
95  *
96  * Description:
97  *	Allocates an array of crypto_mech_name_t containing all the mechanisms
98  *	currently available on the system. Sets *countp with the number of
99  *	mechanism names returned.
100  *
101  *	We get a list of mech names which have a hardware provider by walking
102  *	all the mechanism tables. We merge them with mech names obtained from
103  *	the hint list. A mech name in the hint list is considered only if it
104  *	is not disabled for the provider. Note that the hint list contains only
105  *	software providers and the mech names supported by them.
106  *
107  * Context:
108  *	Process and interruption. kmflag should be KM_NOSLEEP when called
109  *	from an interruption context.
110  *
111  * Returns:
112  *	The array of the crypto_mech_t allocated.
113  *	NULL otherwise.
114  */
115 crypto_mech_name_t *
116 crypto_get_mech_list(uint_t *countp, int kmflag)
117 {
118 	uint_t count = 0, me_tab_size, i, j;
119 	kcf_ops_class_t cl;
120 	kcf_mech_entry_t *me, *me_tab;
121 	crypto_mech_name_t *mech_name_tab, *tmp_mech_name_tab;
122 	char *mech_name, *hint_mech, *end;
123 	kcf_soft_conf_entry_t *p;
124 	size_t n;
125 
126 	/*
127 	 * Count the maximum possible mechanisms that can come from the
128 	 * hint list.
129 	 */
130 	mutex_enter(&soft_config_mutex);
131 	p = soft_config_list;
132 	while (p != NULL) {
133 		count += p->ce_count;
134 		p = p->ce_next;
135 	}
136 	mutex_exit(&soft_config_mutex);
137 
138 	/* First let's count'em, for mem allocation */
139 	for (cl = KCF_FIRST_OPSCLASS; cl <= KCF_LAST_OPSCLASS; cl++) {
140 		me_tab_size = kcf_mech_tabs_tab[cl].met_size;
141 		me_tab = kcf_mech_tabs_tab[cl].met_tab;
142 		for (i = 0; i < me_tab_size; i++) {
143 			me = &me_tab[i];
144 			mutex_enter(&(me->me_mutex));
145 			if ((me->me_name[0] != 0) && (me->me_num_hwprov >= 1)) {
146 				ASSERT(me->me_hw_prov_chain != NULL);
147 				count++;
148 			}
149 			mutex_exit(&(me->me_mutex));
150 		}
151 	}
152 
153 	/*
154 	 * Allocate a buffer to hold the mechanisms from
155 	 * mech tabs and mechanisms from the hint list.
156 	 */
157 	n = count * CRYPTO_MAX_MECH_NAME;
158 
159 again:
160 	count = 0;
161 	tmp_mech_name_tab = kmem_zalloc(n, kmflag);
162 	if (tmp_mech_name_tab == NULL) {
163 		*countp = 0;
164 		return (NULL);
165 	}
166 
167 	/*
168 	 * Second round, fill in the table
169 	 */
170 
171 	mech_name = (char *)tmp_mech_name_tab;
172 	end = mech_name + n;
173 
174 	for (cl = KCF_FIRST_OPSCLASS; cl <= KCF_LAST_OPSCLASS; cl++) {
175 		me_tab_size = kcf_mech_tabs_tab[cl].met_size;
176 		me_tab = kcf_mech_tabs_tab[cl].met_tab;
177 		for (i = 0; i < me_tab_size; i++) {
178 			me = &me_tab[i];
179 			mutex_enter(&(me->me_mutex));
180 			if ((me->me_name[0] != 0) && (me->me_num_hwprov >= 1)) {
181 				ASSERT(me->me_hw_prov_chain != NULL);
182 				if ((mech_name + CRYPTO_MAX_MECH_NAME) > end) {
183 					mutex_exit(&(me->me_mutex));
184 					kmem_free(tmp_mech_name_tab, n);
185 					n = n << 1;
186 					goto again;
187 				}
188 				(void) strncpy(mech_name, me->me_name,
189 				    CRYPTO_MAX_MECH_NAME);
190 
191 				mech_name += CRYPTO_MAX_MECH_NAME;
192 				count++;
193 			}
194 			mutex_exit(&(me->me_mutex));
195 		}
196 	}
197 
198 	/*
199 	 * Search tmp_mech_name_tab for each mechanism in the hint list. We
200 	 * have to add any new mechanisms found in the hint list. Note that we
201 	 * should not modload the providers here as it will be too early. It
202 	 * may be the case that the caller never uses a provider.
203 	 */
204 	mutex_enter(&soft_config_mutex);
205 	p = soft_config_list;
206 	while (p != NULL) {
207 		for (i = 0; i < p->ce_count; i++) {
208 			hint_mech = p->ce_mechs[i];
209 
210 			/* Do not consider the mechanism if it is disabled. */
211 			if (is_mech_disabled_byname(CRYPTO_SW_PROVIDER,
212 			    p->ce_name, 0, hint_mech))
213 				continue;
214 
215 			/*
216 			 * There may be duplicate mechanisms in the hint list.
217 			 * So, we need to search all the entries that have been
218 			 * added so far. That number would be count.
219 			 */
220 			for (j = 0; j < count; j++) {
221 				if (strcmp(hint_mech,
222 				    tmp_mech_name_tab[j]) == 0)
223 					break;
224 			}
225 
226 			if (j == count) {	/* This is a new one. Add it. */
227 				ASSERT((char *)&tmp_mech_name_tab[count] ==
228 				    mech_name);
229 				if ((mech_name + CRYPTO_MAX_MECH_NAME) > end) {
230 					mutex_exit(&soft_config_mutex);
231 					kmem_free(tmp_mech_name_tab, n);
232 					n = n << 1;
233 					goto again;
234 				}
235 				(void) strncpy(tmp_mech_name_tab[count],
236 				    hint_mech, CRYPTO_MAX_MECH_NAME);
237 				mech_name += CRYPTO_MAX_MECH_NAME;
238 				count++;
239 			}
240 		}
241 		p = p->ce_next;
242 	}
243 	mutex_exit(&soft_config_mutex);
244 
245 	/*
246 	 * Check if we have consumed all of the space. We are done if
247 	 * this is the case.
248 	 */
249 	ASSERT(mech_name <= end);
250 	if (mech_name == end) {
251 		mech_name_tab = tmp_mech_name_tab;
252 		goto done;
253 	}
254 
255 	/*
256 	 * Allocate a buffer of the right size now that we have the
257 	 * correct count.
258 	 */
259 	mech_name_tab = kmem_zalloc(count * CRYPTO_MAX_MECH_NAME, kmflag);
260 	if (mech_name_tab == NULL) {
261 		kmem_free(tmp_mech_name_tab, n);
262 		*countp = 0;
263 		return (NULL);
264 	}
265 
266 	bcopy(tmp_mech_name_tab, mech_name_tab, count * CRYPTO_MAX_MECH_NAME);
267 	kmem_free(tmp_mech_name_tab, n);
268 
269 done:
270 	*countp = count;
271 	return (mech_name_tab);
272 }
273 
274 /*
275  * crypto_free_mech_list()
276  *
277  * Arguments:
278  *	. mech_names: An array of crypto_mech_name_t previously allocated by
279  *	  crypto_get_mech_list.
280  *	. count: the number of mech names in mech_names
281  *
282  * Description:
283  *	Frees the the mech_names array.
284  *
285  * Context:
286  *	Process and interruption.
287  */
288 void
289 crypto_free_mech_list(crypto_mech_name_t *mech_names, uint_t count)
290 {
291 	if ((mech_names != NULL) && (count > 0))
292 		kmem_free(mech_names, count * CRYPTO_MAX_MECH_NAME);
293 }
294 
295 /*
296  * crypto_notify_events()
297  *
298  * Arguments:
299  *	. nf: Callback function to invoke when event occurs.
300  *	. event_mask: Mask of events.
301  *
302  * Description:
303  *	Allocates a new element and inserts it in to the notification
304  *	list.
305  *
306  * Context:
307  *	Process context.
308  *
309  * Returns:
310  *	A handle is returned if the client is put on the notification list.
311  *	NULL is returned otherwise.
312  */
313 crypto_notify_handle_t
314 crypto_notify_events(crypto_notify_callback_t nf, uint32_t event_mask)
315 {
316 	kcf_ntfy_elem_t *nep;
317 	crypto_notify_handle_t hndl;
318 
319 	/* Check the input */
320 	if (nf == NULL || !(event_mask & (CRYPTO_EVENT_MECHS_CHANGED |
321 	    CRYPTO_EVENT_PROVIDER_REGISTERED |
322 	    CRYPTO_EVENT_PROVIDER_UNREGISTERED))) {
323 		return (NULL);
324 	}
325 
326 	nep = kmem_zalloc(sizeof (kcf_ntfy_elem_t), KM_SLEEP);
327 	mutex_init(&nep->kn_lock, NULL, MUTEX_DEFAULT, NULL);
328 	cv_init(&nep->kn_cv, NULL, CV_DEFAULT, NULL);
329 	nep->kn_state = NTFY_WAITING;
330 	nep->kn_func = nf;
331 	nep->kn_event_mask = event_mask;
332 
333 	mutex_enter(&ntfy_list_lock);
334 	if (ntfy_list_head == NULL) {
335 		ntfy_list_head = ntfy_list_tail = nep;
336 	} else {
337 		ntfy_list_tail->kn_next = nep;
338 		nep->kn_prev = ntfy_list_tail;
339 		ntfy_list_tail = nep;
340 	}
341 
342 	hndl = (crypto_notify_handle_t)nep;
343 	mutex_exit(&ntfy_list_lock);
344 
345 	return (hndl);
346 }
347 
348 /*
349  * crypto_unnotify_events()
350  *
351  * Arguments:
352  *	. hndl - Handle returned from an earlier crypto_notify_events().
353  *
354  * Description:
355  *	Removes the element specified by hndl from the notification list.
356  *	We wait for the notification routine to complete, if the routine
357  *	is currently being called. We also free the element.
358  *
359  * Context:
360  *	Process context.
361  */
362 void
363 crypto_unnotify_events(crypto_notify_handle_t hndl)
364 {
365 	kcf_ntfy_elem_t *nep = (kcf_ntfy_elem_t *)hndl;
366 
367 	if (hndl == NULL)
368 		return;
369 
370 retry:
371 	mutex_enter(&ntfy_list_lock);
372 	mutex_enter(&nep->kn_lock);
373 
374 	if (nep->kn_state == NTFY_WAITING) {
375 		kcf_ntfy_elem_t *nextp = nep->kn_next;
376 		kcf_ntfy_elem_t *prevp = nep->kn_prev;
377 
378 		if (nextp != NULL)
379 			nextp->kn_prev = prevp;
380 		else
381 			ntfy_list_tail = prevp;
382 
383 		if (prevp != NULL)
384 			prevp->kn_next = nextp;
385 		else
386 			ntfy_list_head = nextp;
387 	} else {
388 		ASSERT(nep->kn_state == NTFY_RUNNING);
389 
390 		/*
391 		 * We have to drop this lock as the client might call
392 		 * crypto_notify_events() in the callback routine resulting
393 		 * in a deadlock.
394 		 */
395 		mutex_exit(&ntfy_list_lock);
396 
397 		/*
398 		 * Another thread is working on this element. We will wait
399 		 * for that thread to signal us when done. No other thread
400 		 * will free this element. So, we can be sure it stays valid
401 		 * after the wait.
402 		 */
403 		while (nep->kn_state == NTFY_RUNNING)
404 			cv_wait(&nep->kn_cv, &nep->kn_lock);
405 		mutex_exit(&nep->kn_lock);
406 
407 		/*
408 		 * We have to remove the element from the notification list.
409 		 * So, start over and do the work (acquire locks etc.). This is
410 		 * safe (i.e. We won't be in this routine forever) as the
411 		 * events do not happen frequently. We have to revisit this
412 		 * code if we add a new event that happens often.
413 		 */
414 		goto retry;
415 	}
416 
417 	mutex_exit(&nep->kn_lock);
418 
419 	/* Free the element */
420 	mutex_destroy(&nep->kn_lock);
421 	cv_destroy(&nep->kn_cv);
422 	kmem_free(nep, sizeof (kcf_ntfy_elem_t));
423 
424 	mutex_exit(&ntfy_list_lock);
425 }
426 
427 /*
428  * We walk the notification list and do the callbacks.
429  */
430 void
431 kcf_walk_ntfylist(uint32_t event, void *event_arg)
432 {
433 	kcf_ntfy_elem_t *nep;
434 	int nelem = 0;
435 
436 	mutex_enter(&ntfy_list_lock);
437 
438 	/*
439 	 * Count how many clients are on the notification list. We need
440 	 * this count to ensure that clients which joined the list after we
441 	 * have started this walk, are not wrongly notified.
442 	 */
443 	for (nep = ntfy_list_head; nep != NULL; nep = nep->kn_next)
444 		nelem++;
445 
446 	for (nep = ntfy_list_head; (nep != NULL && nelem); nep = nep->kn_next) {
447 		nelem--;
448 
449 		/*
450 		 * Check if this client is interested in the
451 		 * event.
452 		 */
453 		if (!(nep->kn_event_mask & event))
454 			continue;
455 
456 		mutex_enter(&nep->kn_lock);
457 		nep->kn_state = NTFY_RUNNING;
458 		mutex_exit(&nep->kn_lock);
459 		mutex_exit(&ntfy_list_lock);
460 
461 		/*
462 		 * We invoke the callback routine with no locks held. Another
463 		 * client could have joined the list meanwhile. This is fine
464 		 * as we maintain nelem as stated above. The NULL check in the
465 		 * for loop guards against shrinkage. Also, any callers of
466 		 * crypto_unnotify_events() at this point cv_wait till kn_state
467 		 * changes to NTFY_WAITING. Hence, nep is assured to be valid.
468 		 */
469 		(*nep->kn_func)(event, event_arg);
470 
471 		mutex_enter(&nep->kn_lock);
472 		nep->kn_state = NTFY_WAITING;
473 		cv_broadcast(&nep->kn_cv);
474 		mutex_exit(&nep->kn_lock);
475 
476 		mutex_enter(&ntfy_list_lock);
477 	}
478 
479 	mutex_exit(&ntfy_list_lock);
480 }
481 
482 /*
483  * crypto_key_check()
484  *
485  * Arguments:
486  *	. mech: the mechanism to check the key with.
487  *	. key: the key to check for validity and weakness.
488  *
489  * Description:
490  *	Checks the validity and strength of the key for the mechanism.
491  *	CRYPTO_KEY_REFERENCE is not supported for this routine.
492  *	If more than one provider is capable of key checking for the mechanism,
493  *	then run the key through them all.
494  *	A conservative approach is adopted here: New weak keys may be
495  *	discovered with more recent providers. If at least one provider is
496  *	not happy with a key, then it is no good.
497  *
498  * Context:
499  *	Process and interruption.
500  */
501 int
502 crypto_key_check(crypto_mechanism_t *mech, crypto_key_t *key)
503 {
504 	int error;
505 	kcf_mech_entry_t *me;
506 	kcf_provider_desc_t *pd;
507 	kcf_prov_mech_desc_t *prov_chain;
508 
509 	/* when mech is a valid mechanism, me will be its mech_entry */
510 	if ((mech == NULL) || (key == NULL) ||
511 	    (key->ck_format == CRYPTO_KEY_REFERENCE))
512 		return (CRYPTO_ARGUMENTS_BAD);
513 
514 	if ((error = kcf_get_mech_entry(mech->cm_type, &me)) != KCF_SUCCESS) {
515 		/* error is one of the KCF_INVALID_MECH_XXX's */
516 		return (CRYPTO_MECHANISM_INVALID);
517 	}
518 
519 	mutex_enter(&me->me_mutex);
520 
521 	/* First let the software provider check this key */
522 	if (me->me_sw_prov != NULL) {
523 		pd = me->me_sw_prov->pm_prov_desc;
524 		KCF_PROV_REFHOLD(pd);
525 
526 		if ((KCF_PROV_KEY_OPS(pd) != NULL) &&
527 		    (KCF_PROV_KEY_OPS(pd)->key_check != NULL)) {
528 			crypto_mechanism_t lmech;
529 
530 			mutex_exit(&me->me_mutex);
531 			lmech = *mech;
532 			KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
533 			error = KCF_PROV_KEY_CHECK(pd, &lmech, key);
534 
535 			if (error != CRYPTO_SUCCESS) {
536 				KCF_PROV_REFRELE(pd);
537 				return (error);
538 			}
539 
540 			mutex_enter(&me->me_mutex);
541 		}
542 		KCF_PROV_REFRELE(pd);
543 	}
544 
545 	prov_chain = me->me_hw_prov_chain;
546 	while (prov_chain != NULL) {
547 		pd = prov_chain->pm_prov_desc;
548 		KCF_PROV_REFHOLD(pd);
549 
550 		if ((KCF_PROV_KEY_OPS(pd) != NULL) &&
551 		    (KCF_PROV_KEY_OPS(pd)->key_check != NULL)) {
552 			crypto_mechanism_t lmech;
553 
554 			mutex_exit(&me->me_mutex);
555 			lmech = *mech;
556 			KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd,
557 			    &lmech);
558 			error = KCF_PROV_KEY_CHECK(pd, &lmech, key);
559 
560 			if (error != CRYPTO_SUCCESS) {
561 				KCF_PROV_REFRELE(pd);
562 				return (error);
563 			}
564 			mutex_enter(&me->me_mutex);
565 		}
566 		KCF_PROV_REFRELE(pd);
567 		prov_chain = prov_chain->pm_next;
568 	}
569 
570 	mutex_exit(&me->me_mutex);
571 
572 	/* All are happy with this key */
573 	return (CRYPTO_SUCCESS);
574 }
575 
576 int
577 crypto_key_check_prov(crypto_provider_t provider, crypto_mechanism_t *mech,
578     crypto_key_t *key)
579 {
580 	kcf_provider_desc_t *pd = provider;
581 	kcf_provider_desc_t *real_provider = pd;
582 	crypto_mechanism_t lmech;
583 	int rv;
584 
585 	ASSERT(KCF_PROV_REFHELD(pd));
586 
587 	if ((mech == NULL) || (key == NULL) ||
588 	    (key->ck_format == CRYPTO_KEY_REFERENCE))
589 		return (CRYPTO_ARGUMENTS_BAD);
590 
591 	/* no logical providers currently support the key check */
592 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
593 		return (CRYPTO_NOT_SUPPORTED);
594 	}
595 
596 	lmech = *mech;
597 	KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
598 	rv = KCF_PROV_KEY_CHECK(real_provider, &lmech, key);
599 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
600 		KCF_PROV_REFRELE(real_provider);
601 
602 	return (rv);
603 }
604 
605 /*
606  * Initialize the specified crypto_mechanism_info_t structure for
607  * the specified mechanism provider descriptor. Used by
608  * crypto_get_all_mech_info().
609  */
610 static void
611 init_mechanism_info(crypto_mechanism_info_t *mech_info,
612     kcf_prov_mech_desc_t *pmd)
613 {
614 	crypto_func_group_t fg = pmd->pm_mech_info.cm_func_group_mask;
615 
616 	/* min/max key sizes */
617 	mech_info->mi_keysize_unit = pmd->pm_mech_info.cm_mech_flags &
618 	    (CRYPTO_KEYSIZE_UNIT_IN_BITS | CRYPTO_KEYSIZE_UNIT_IN_BYTES);
619 	mech_info->mi_min_key_size =
620 	    (size_t)pmd->pm_mech_info.cm_min_key_length;
621 	mech_info->mi_max_key_size =
622 	    (size_t)pmd->pm_mech_info.cm_max_key_length;
623 
624 	/* usage flag */
625 	mech_info->mi_usage = 0;
626 	if (fg & (CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC))
627 		mech_info->mi_usage |= CRYPTO_MECH_USAGE_ENCRYPT;
628 	if (fg & (CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC))
629 		mech_info->mi_usage |= CRYPTO_MECH_USAGE_DECRYPT;
630 	if (fg & (CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC))
631 		mech_info->mi_usage |= CRYPTO_MECH_USAGE_MAC;
632 }
633 
634 /*
635  * Return the mechanism info for the specified mechanism.
636  */
637 int
638 crypto_get_all_mech_info(crypto_mech_type_t mech_type,
639     crypto_mechanism_info_t **mech_infos, uint_t *num_mech_infos,
640     int km_flag)
641 {
642 	uint_t ninfos, cur_info;
643 	kcf_mech_entry_t *me;
644 	int rv;
645 	kcf_prov_mech_desc_t *hwp;
646 	crypto_mechanism_info_t *infos;
647 	size_t infos_size;
648 
649 	/* get to the mech entry corresponding to the specified mech type */
650 	if ((rv = kcf_get_mech_entry(mech_type, &me)) != CRYPTO_SUCCESS) {
651 		return (rv);
652 	}
653 
654 	/* compute the number of key size ranges to return */
655 	mutex_enter(&me->me_mutex);
656 again:
657 	ninfos = PROV_COUNT(me);
658 	mutex_exit(&me->me_mutex);
659 
660 	if (ninfos == 0) {
661 		infos = NULL;
662 		rv = CRYPTO_SUCCESS;
663 		goto bail;
664 	}
665 	infos_size = ninfos * sizeof (crypto_mechanism_info_t);
666 	infos = kmem_alloc(infos_size, km_flag);
667 	if (infos == NULL) {
668 		rv = CRYPTO_HOST_MEMORY;
669 		goto bail;
670 	}
671 
672 	mutex_enter(&me->me_mutex);
673 	if (ninfos != PROV_COUNT(me)) {
674 		kmem_free(infos, infos_size);
675 		goto again;
676 	}
677 
678 	/* populate array of crypto mechanism infos */
679 	cur_info = 0;
680 
681 	/* software provider, if present */
682 	if (me->me_sw_prov != NULL)
683 		init_mechanism_info(&infos[cur_info++], me->me_sw_prov);
684 
685 	/* hardware providers */
686 	for (hwp = me->me_hw_prov_chain; hwp != NULL; hwp = hwp->pm_next)
687 		init_mechanism_info(&infos[cur_info++], hwp);
688 
689 	mutex_exit(&me->me_mutex);
690 	ASSERT(cur_info == ninfos);
691 bail:
692 	*mech_infos = infos;
693 	*num_mech_infos = ninfos;
694 	return (rv);
695 }
696 
697 /*
698  * Frees the array of mechanism infos previously allocated by
699  * crypto_get_all_mech_info().
700  */
701 void
702 crypto_free_all_mech_info(crypto_mechanism_info_t *mech_infos, uint_t count)
703 {
704 	if ((mech_infos != NULL) && (count > 0))
705 		kmem_free(mech_infos, count * sizeof (crypto_mechanism_info_t));
706 }
707 
708 /*
709  * memcmp_pad_max() is a specialized version of memcmp() which
710  * compares two pieces of data up to a maximum length.  If the
711  * the two data match up the maximum length, they are considered
712  * matching.  Trailing blanks do not cause the match to fail if
713  * one of the data is shorter.
714  *
715  * Examples of matches:
716  *	"one"           |
717  *	"one      "     |
718  *	                ^maximum length
719  *
720  *	"Number One     |  X"	(X is beyond maximum length)
721  *	"Number One   " |
722  *	                ^maximum length
723  *
724  * Examples of mismatches:
725  *	" one"
726  *	"one"
727  *
728  *	"Number One    X|"
729  *	"Number One     |"
730  *	                ^maximum length
731  */
732 static int
733 memcmp_pad_max(void *d1, uint_t d1_len, void *d2, uint_t d2_len, uint_t max_sz)
734 {
735 	uint_t		len, extra_len;
736 	char		*marker;
737 
738 	/* No point in comparing anything beyond max_sz */
739 	if (d1_len > max_sz)
740 		d1_len = max_sz;
741 	if (d2_len > max_sz)
742 		d2_len = max_sz;
743 
744 	/* Find shorter of the two data. */
745 	if (d1_len <= d2_len) {
746 		len = d1_len;
747 		extra_len = d2_len;
748 		marker = d2;
749 	} else {	/* d1_len > d2_len */
750 		len = d2_len;
751 		extra_len = d1_len;
752 		marker = d1;
753 	}
754 
755 	/* Have a match in the shortest length of data? */
756 	if (memcmp(d1, d2, len) != 0)
757 		/* CONSTCOND */
758 		return (!0);
759 
760 	/* If the rest of longer data is nulls or blanks, call it a match. */
761 	while (len < extra_len)
762 		if (!isspace(marker[len++]))
763 			/* CONSTCOND */
764 			return (!0);
765 	return (0);
766 }
767 
768 /*
769  * Obtain ext info for specified provider and see if it matches.
770  */
771 static boolean_t
772 match_ext_info(kcf_provider_desc_t *pd, char *label, char *manuf, char *serial,
773     crypto_provider_ext_info_t *ext_info)
774 {
775 	int rv;
776 
777 	rv = crypto_get_provinfo(pd, ext_info);
778 	ASSERT(rv != CRYPTO_NOT_SUPPORTED);
779 	if (rv != CRYPTO_SUCCESS)
780 		return (B_FALSE);
781 
782 	if (memcmp_pad_max(ext_info->ei_label, CRYPTO_EXT_SIZE_LABEL,
783 	    label, strlen(label), CRYPTO_EXT_SIZE_LABEL))
784 		return (B_FALSE);
785 
786 	if (manuf != NULL) {
787 		if (memcmp_pad_max(ext_info->ei_manufacturerID,
788 		    CRYPTO_EXT_SIZE_MANUF, manuf, strlen(manuf),
789 		    CRYPTO_EXT_SIZE_MANUF))
790 			return (B_FALSE);
791 	}
792 
793 	if (serial != NULL) {
794 		if (memcmp_pad_max(ext_info->ei_serial_number,
795 		    CRYPTO_EXT_SIZE_SERIAL, serial, strlen(serial),
796 		    CRYPTO_EXT_SIZE_SERIAL))
797 			return (B_FALSE);
798 	}
799 	return (B_TRUE);
800 }
801 
802 /*
803  * Find a provider based on its label, manufacturer ID, and serial number.
804  */
805 crypto_provider_t
806 crypto_get_provider(char *label, char *manuf, char *serial)
807 {
808 	kcf_provider_desc_t **provider_array, *pd;
809 	crypto_provider_ext_info_t *ext_info;
810 	uint_t count;
811 	int i;
812 
813 	/* manuf and serial are optional */
814 	if (label == NULL)
815 		return (NULL);
816 
817 	if (kcf_get_slot_list(&count, &provider_array, B_FALSE)
818 	    != CRYPTO_SUCCESS)
819 		return (NULL);
820 
821 	if (count == 0)
822 		return (NULL);
823 
824 	ext_info = kmem_zalloc(sizeof (crypto_provider_ext_info_t), KM_SLEEP);
825 
826 	for (i = 0; i < count; i++) {
827 		pd = provider_array[i];
828 		if (match_ext_info(pd, label, manuf, serial, ext_info)) {
829 			KCF_PROV_REFHOLD(pd);
830 			break;
831 		}
832 	}
833 	if (i == count)
834 		pd = NULL;
835 
836 	kcf_free_provider_tab(count, provider_array);
837 	kmem_free(ext_info, sizeof (crypto_provider_ext_info_t));
838 	return (pd);
839 }
840 
841 /*
842  * Get the provider information given a provider handle. The caller
843  * needs to allocate the space for the argument, info.
844  */
845 int
846 crypto_get_provinfo(crypto_provider_t hndl, crypto_provider_ext_info_t *info)
847 {
848 	int rv;
849 	kcf_req_params_t params;
850 	kcf_provider_desc_t *pd;
851 	kcf_provider_desc_t *real_provider;
852 
853 	pd = (kcf_provider_desc_t *)hndl;
854 	rv = kcf_get_hardware_provider_nomech(
855 	    CRYPTO_OPS_OFFSET(provider_ops), CRYPTO_PROVIDER_OFFSET(ext_info),
856 	    CHECK_RESTRICT_FALSE, pd, &real_provider);
857 
858 	if (rv == CRYPTO_SUCCESS && real_provider != NULL) {
859 		ASSERT(real_provider == pd ||
860 		    pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER);
861 		KCF_WRAP_PROVMGMT_OPS_PARAMS(&params, KCF_OP_MGMT_EXTINFO,
862 		    0, NULL, 0, NULL, 0, NULL, info, pd);
863 		rv = kcf_submit_request(real_provider, NULL, NULL, &params,
864 		    B_FALSE);
865 		KCF_PROV_REFRELE(real_provider);
866 	}
867 
868 	return (rv);
869 }
870 
871 void
872 crypto_release_provider(crypto_provider_t provider)
873 {
874 	KCF_PROV_REFRELE((kcf_provider_desc_t *)provider);
875 }
876