xref: /onnv-gate/usr/src/uts/common/crypto/spi/kcf_spi.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 2005 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 /*
30*0Sstevel@tonic-gate  * This file is part of the core Kernel Cryptographic Framework.
31*0Sstevel@tonic-gate  * It implements the SPI functions exported to cryptographic
32*0Sstevel@tonic-gate  * providers.
33*0Sstevel@tonic-gate  */
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #include <sys/ksynch.h>
36*0Sstevel@tonic-gate #include <sys/cmn_err.h>
37*0Sstevel@tonic-gate #include <sys/ddi.h>
38*0Sstevel@tonic-gate #include <sys/sunddi.h>
39*0Sstevel@tonic-gate #include <sys/modctl.h>
40*0Sstevel@tonic-gate #include <sys/crypto/common.h>
41*0Sstevel@tonic-gate #include <sys/crypto/impl.h>
42*0Sstevel@tonic-gate #include <sys/crypto/sched_impl.h>
43*0Sstevel@tonic-gate #include <sys/crypto/spi.h>
44*0Sstevel@tonic-gate #include <sys/taskq.h>
45*0Sstevel@tonic-gate #include <sys/disp.h>
46*0Sstevel@tonic-gate #include <sys/kstat.h>
47*0Sstevel@tonic-gate #include <sys/policy.h>
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate /*
50*0Sstevel@tonic-gate  * minalloc and maxalloc values to be used for taskq_create().
51*0Sstevel@tonic-gate  */
52*0Sstevel@tonic-gate int crypto_taskq_minalloc = CYRPTO_TASKQ_MIN;
53*0Sstevel@tonic-gate int crypto_taskq_maxalloc = CRYPTO_TASKQ_MAX;
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate static void free_provider_list(kcf_provider_list_t *);
56*0Sstevel@tonic-gate static void remove_provider(kcf_provider_desc_t *);
57*0Sstevel@tonic-gate static void process_logical_providers(crypto_provider_info_t *,
58*0Sstevel@tonic-gate     kcf_provider_desc_t *);
59*0Sstevel@tonic-gate static void copy_ops_vector(crypto_ops_t *, crypto_ops_t *);
60*0Sstevel@tonic-gate static int init_prov_mechs(crypto_provider_info_t *, kcf_provider_desc_t *);
61*0Sstevel@tonic-gate static int kcf_prov_kstat_update(kstat_t *, int);
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate static kcf_prov_stats_t kcf_stats_ks_data_template = {
64*0Sstevel@tonic-gate 	{ "kcf_ops_total",		KSTAT_DATA_UINT64 },
65*0Sstevel@tonic-gate 	{ "kcf_ops_passed",		KSTAT_DATA_UINT64 },
66*0Sstevel@tonic-gate 	{ "kcf_ops_failed",		KSTAT_DATA_UINT64 },
67*0Sstevel@tonic-gate 	{ "kcf_ops_returned_busy",	KSTAT_DATA_UINT64 }
68*0Sstevel@tonic-gate };
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate #define	KCF_SPI_COPY_OPS(src, dst, ops) if ((src)->ops != NULL) \
71*0Sstevel@tonic-gate 	*((dst)->ops) = *((src)->ops);
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate /*
74*0Sstevel@tonic-gate  * This routine is used to add cryptographic providers to the KEF framework.
75*0Sstevel@tonic-gate  * Providers pass a crypto_provider_info structure to crypto_register_provider()
76*0Sstevel@tonic-gate  * and get back a handle.  The crypto_provider_info structure contains a
77*0Sstevel@tonic-gate  * list of mechanisms supported by the provider and an ops vector containing
78*0Sstevel@tonic-gate  * provider entry points.  Hardware providers call this routine in their attach
79*0Sstevel@tonic-gate  * routines.  Software providers call this routine in their _init() routine.
80*0Sstevel@tonic-gate  */
81*0Sstevel@tonic-gate int
82*0Sstevel@tonic-gate crypto_register_provider(crypto_provider_info_t *info,
83*0Sstevel@tonic-gate     crypto_kcf_provider_handle_t *handle)
84*0Sstevel@tonic-gate {
85*0Sstevel@tonic-gate 	int i;
86*0Sstevel@tonic-gate 	int vstatus = 0;
87*0Sstevel@tonic-gate 	struct modctl *mcp;
88*0Sstevel@tonic-gate 	char *name;
89*0Sstevel@tonic-gate 	char ks_name[KSTAT_STRLEN];
90*0Sstevel@tonic-gate 	crypto_notify_event_change_t ec;
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 	kcf_provider_desc_t *prov_desc = NULL;
93*0Sstevel@tonic-gate 	int ret = CRYPTO_ARGUMENTS_BAD;
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate 	if (info->pi_interface_version != CRYPTO_SPI_VERSION_1)
96*0Sstevel@tonic-gate 		return (CRYPTO_VERSION_MISMATCH);
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 	/*
99*0Sstevel@tonic-gate 	 * Check provider type, must be software, hardware, or logical.
100*0Sstevel@tonic-gate 	 */
101*0Sstevel@tonic-gate 	if (info->pi_provider_type != CRYPTO_HW_PROVIDER &&
102*0Sstevel@tonic-gate 	    info->pi_provider_type != CRYPTO_SW_PROVIDER &&
103*0Sstevel@tonic-gate 	    info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER)
104*0Sstevel@tonic-gate 		return (CRYPTO_ARGUMENTS_BAD);
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 	/*
107*0Sstevel@tonic-gate 	 * Allocate and initialize a new provider descriptor. We also
108*0Sstevel@tonic-gate 	 * hold it and release it when done.
109*0Sstevel@tonic-gate 	 */
110*0Sstevel@tonic-gate 	prov_desc = kcf_alloc_provider_desc(info);
111*0Sstevel@tonic-gate 	KCF_PROV_REFHOLD(prov_desc);
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 	prov_desc->pd_prov_type = info->pi_provider_type;
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 	/* provider-private handle, opaque to KCF */
116*0Sstevel@tonic-gate 	prov_desc->pd_prov_handle = info->pi_provider_handle;
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 	/* copy provider description string */
119*0Sstevel@tonic-gate 	if (info->pi_provider_description != NULL) {
120*0Sstevel@tonic-gate 		/*
121*0Sstevel@tonic-gate 		 * pi_provider_descriptor is a string that can contain
122*0Sstevel@tonic-gate 		 * up to CRYPTO_PROVIDER_DESCR_MAX_LEN + 1 characters
123*0Sstevel@tonic-gate 		 * INCLUDING the terminating null character. A bcopy()
124*0Sstevel@tonic-gate 		 * is necessary here as pd_description should not have
125*0Sstevel@tonic-gate 		 * a null character. See comments in kcf_alloc_provider_desc()
126*0Sstevel@tonic-gate 		 * for details on pd_description field.
127*0Sstevel@tonic-gate 		 */
128*0Sstevel@tonic-gate 		bcopy(info->pi_provider_description, prov_desc->pd_description,
129*0Sstevel@tonic-gate 		    min(strlen(info->pi_provider_description),
130*0Sstevel@tonic-gate 		    CRYPTO_PROVIDER_DESCR_MAX_LEN));
131*0Sstevel@tonic-gate 	}
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate 	if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
134*0Sstevel@tonic-gate 		if (info->pi_ops_vector == NULL) {
135*0Sstevel@tonic-gate 			return (CRYPTO_ARGUMENTS_BAD);
136*0Sstevel@tonic-gate 		}
137*0Sstevel@tonic-gate 		copy_ops_vector(info->pi_ops_vector, prov_desc->pd_ops_vector);
138*0Sstevel@tonic-gate 	}
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 	/*
141*0Sstevel@tonic-gate 	 * For software providers, copy the module name and module ID.
142*0Sstevel@tonic-gate 	 * For hardware providers, copy the driver name and instance.
143*0Sstevel@tonic-gate 	 */
144*0Sstevel@tonic-gate 	switch (info->pi_provider_type) {
145*0Sstevel@tonic-gate 	case  CRYPTO_SW_PROVIDER:
146*0Sstevel@tonic-gate 		if (info->pi_provider_dev.pd_sw == NULL)
147*0Sstevel@tonic-gate 			goto bail;
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate 		if ((mcp = mod_getctl(info->pi_provider_dev.pd_sw)) == NULL)
150*0Sstevel@tonic-gate 			goto bail;
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 		prov_desc->pd_module_id = mcp->mod_id;
153*0Sstevel@tonic-gate 		name = mcp->mod_modname;
154*0Sstevel@tonic-gate 		break;
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate 	case CRYPTO_HW_PROVIDER:
157*0Sstevel@tonic-gate 	case CRYPTO_LOGICAL_PROVIDER:
158*0Sstevel@tonic-gate 		if (info->pi_provider_dev.pd_hw == NULL)
159*0Sstevel@tonic-gate 			goto bail;
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 		prov_desc->pd_instance =
162*0Sstevel@tonic-gate 		    ddi_get_instance(info->pi_provider_dev.pd_hw);
163*0Sstevel@tonic-gate 		name = (char *)ddi_driver_name(info->pi_provider_dev.pd_hw);
164*0Sstevel@tonic-gate 		break;
165*0Sstevel@tonic-gate 	}
166*0Sstevel@tonic-gate 	if (name == NULL)
167*0Sstevel@tonic-gate 		goto bail;
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	prov_desc->pd_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
170*0Sstevel@tonic-gate 	(void) strcpy(prov_desc->pd_name, name);
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	if ((prov_desc->pd_mctlp = kcf_get_modctl(info)) == NULL)
173*0Sstevel@tonic-gate 		goto bail;
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 	/* process the mechanisms supported by the provider */
176*0Sstevel@tonic-gate 	if ((ret = init_prov_mechs(info, prov_desc)) != CRYPTO_SUCCESS)
177*0Sstevel@tonic-gate 		goto bail;
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate 	/*
180*0Sstevel@tonic-gate 	 * Add provider to providers tables, also sets the descriptor
181*0Sstevel@tonic-gate 	 * pd_prov_id field.
182*0Sstevel@tonic-gate 	 */
183*0Sstevel@tonic-gate 	if ((ret = kcf_prov_tab_add_provider(prov_desc)) != CRYPTO_SUCCESS) {
184*0Sstevel@tonic-gate 		undo_register_provider(prov_desc, B_FALSE);
185*0Sstevel@tonic-gate 		goto bail;
186*0Sstevel@tonic-gate 	}
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 	if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
189*0Sstevel@tonic-gate 		if ((vstatus = kcf_verify_signature(prov_desc)) ==
190*0Sstevel@tonic-gate 		    CRYPTO_MODVERIFICATION_FAILED) {
191*0Sstevel@tonic-gate 			undo_register_provider(prov_desc, B_TRUE);
192*0Sstevel@tonic-gate 			ret = CRYPTO_MODVERIFICATION_FAILED;
193*0Sstevel@tonic-gate 			goto bail;
194*0Sstevel@tonic-gate 		}
195*0Sstevel@tonic-gate 	}
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate 	/*
198*0Sstevel@tonic-gate 	 * We create a taskq only for a hardware provider. The global
199*0Sstevel@tonic-gate 	 * software queue is used for software providers. The taskq
200*0Sstevel@tonic-gate 	 * is limited to one thread since tasks are guaranteed to be
201*0Sstevel@tonic-gate 	 * executed in the order they are scheduled, if nthreads == 1. We
202*0Sstevel@tonic-gate 	 * pass TASKQ_PREPOPULATE flag to keep some entries cached to
203*0Sstevel@tonic-gate 	 * improve performance.
204*0Sstevel@tonic-gate 	 */
205*0Sstevel@tonic-gate 	if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
206*0Sstevel@tonic-gate 		prov_desc->pd_sched_info.ks_taskq = taskq_create("kcf_taskq",
207*0Sstevel@tonic-gate 		    1, minclsyspri, crypto_taskq_minalloc,
208*0Sstevel@tonic-gate 		    crypto_taskq_maxalloc, TASKQ_PREPOPULATE);
209*0Sstevel@tonic-gate 	else
210*0Sstevel@tonic-gate 		prov_desc->pd_sched_info.ks_taskq = NULL;
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	/* no kernel session to logical providers */
213*0Sstevel@tonic-gate 	if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
214*0Sstevel@tonic-gate 		/*
215*0Sstevel@tonic-gate 		 * Open a session for session-oriented providers. This session
216*0Sstevel@tonic-gate 		 * is used for all kernel consumers. This is fine as a provider
217*0Sstevel@tonic-gate 		 * is required to support multiple thread access to a session.
218*0Sstevel@tonic-gate 		 * We can do this only after the taskq has been created as we
219*0Sstevel@tonic-gate 		 * do a kcf_submit_request() to open the session.
220*0Sstevel@tonic-gate 		 */
221*0Sstevel@tonic-gate 		if (KCF_PROV_SESSION_OPS(prov_desc) != NULL) {
222*0Sstevel@tonic-gate 			kcf_req_params_t params;
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 			KCF_WRAP_SESSION_OPS_PARAMS(&params,
225*0Sstevel@tonic-gate 			    KCF_OP_SESSION_OPEN, &prov_desc->pd_sid, 0,
226*0Sstevel@tonic-gate 			    CRYPTO_USER, NULL, 0, prov_desc);
227*0Sstevel@tonic-gate 			ret = kcf_submit_request(prov_desc, NULL, NULL, &params,
228*0Sstevel@tonic-gate 			    B_FALSE);
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 			if (ret != CRYPTO_SUCCESS) {
231*0Sstevel@tonic-gate 				undo_register_provider(prov_desc, B_TRUE);
232*0Sstevel@tonic-gate 				ret = CRYPTO_FAILED;
233*0Sstevel@tonic-gate 				goto bail;
234*0Sstevel@tonic-gate 			}
235*0Sstevel@tonic-gate 		}
236*0Sstevel@tonic-gate 	}
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
239*0Sstevel@tonic-gate 		/*
240*0Sstevel@tonic-gate 		 * Create the kstat for this provider. There is a kstat
241*0Sstevel@tonic-gate 		 * installed for each successfully registered provider.
242*0Sstevel@tonic-gate 		 * This kstat is deleted, when the provider unregisters.
243*0Sstevel@tonic-gate 		 */
244*0Sstevel@tonic-gate 		if (prov_desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
245*0Sstevel@tonic-gate 			(void) snprintf(ks_name, KSTAT_STRLEN, "%s_%s",
246*0Sstevel@tonic-gate 			    prov_desc->pd_name, "provider_stats");
247*0Sstevel@tonic-gate 		} else {
248*0Sstevel@tonic-gate 			(void) snprintf(ks_name, KSTAT_STRLEN, "%s_%d_%u_%s",
249*0Sstevel@tonic-gate 			    prov_desc->pd_name, prov_desc->pd_instance,
250*0Sstevel@tonic-gate 			    prov_desc->pd_prov_id, "provider_stats");
251*0Sstevel@tonic-gate 		}
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 		prov_desc->pd_kstat = kstat_create("kcf", 0, ks_name, "crypto",
254*0Sstevel@tonic-gate 		    KSTAT_TYPE_NAMED, sizeof (kcf_prov_stats_t) /
255*0Sstevel@tonic-gate 		    sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 		if (prov_desc->pd_kstat != NULL) {
258*0Sstevel@tonic-gate 			bcopy(&kcf_stats_ks_data_template,
259*0Sstevel@tonic-gate 			    &prov_desc->pd_ks_data,
260*0Sstevel@tonic-gate 			    sizeof (kcf_stats_ks_data_template));
261*0Sstevel@tonic-gate 			prov_desc->pd_kstat->ks_data = &prov_desc->pd_ks_data;
262*0Sstevel@tonic-gate 			KCF_PROV_REFHOLD(prov_desc);
263*0Sstevel@tonic-gate 			KCF_PROV_IREFHOLD(prov_desc);
264*0Sstevel@tonic-gate 			prov_desc->pd_kstat->ks_private = prov_desc;
265*0Sstevel@tonic-gate 			prov_desc->pd_kstat->ks_update = kcf_prov_kstat_update;
266*0Sstevel@tonic-gate 			kstat_install(prov_desc->pd_kstat);
267*0Sstevel@tonic-gate 		}
268*0Sstevel@tonic-gate 	}
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
271*0Sstevel@tonic-gate 		process_logical_providers(info, prov_desc);
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	/*
274*0Sstevel@tonic-gate 	 * Inform interested kernel clients of the event.
275*0Sstevel@tonic-gate 	 * Logical providers are not visible to kernel clients.
276*0Sstevel@tonic-gate 	 */
277*0Sstevel@tonic-gate 	if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
278*0Sstevel@tonic-gate 		ec.ec_provider_type = prov_desc->pd_prov_type;
279*0Sstevel@tonic-gate 		ec.ec_change = CRYPTO_EVENT_CHANGE_ADDED;
280*0Sstevel@tonic-gate 		for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
281*0Sstevel@tonic-gate 			/* Skip any mechanisms not allowed by the policy */
282*0Sstevel@tonic-gate 			if (is_mech_disabled(prov_desc,
283*0Sstevel@tonic-gate 			    prov_desc->pd_mechanisms[i].cm_mech_name))
284*0Sstevel@tonic-gate 				continue;
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 			(void) strncpy(ec.ec_mech_name,
287*0Sstevel@tonic-gate 			    prov_desc->pd_mechanisms[i].cm_mech_name,
288*0Sstevel@tonic-gate 			    CRYPTO_MAX_MECH_NAME);
289*0Sstevel@tonic-gate 			kcf_walk_ntfylist(CRYPTO_EVENT_PROVIDERS_CHANGE, &ec);
290*0Sstevel@tonic-gate 		}
291*0Sstevel@tonic-gate 	}
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 	mutex_enter(&prov_desc->pd_lock);
294*0Sstevel@tonic-gate 	prov_desc->pd_state = (vstatus == 0) ? KCF_PROV_READY :
295*0Sstevel@tonic-gate 	    KCF_PROV_UNVERIFIED;
296*0Sstevel@tonic-gate 	mutex_exit(&prov_desc->pd_lock);
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	*handle = prov_desc->pd_kcf_prov_handle;
299*0Sstevel@tonic-gate 	KCF_PROV_REFRELE(prov_desc);
300*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate bail:
303*0Sstevel@tonic-gate 	KCF_PROV_REFRELE(prov_desc);
304*0Sstevel@tonic-gate 	return (ret);
305*0Sstevel@tonic-gate }
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate /*
308*0Sstevel@tonic-gate  * This routine is used to notify the framework when a provider is being
309*0Sstevel@tonic-gate  * removed.  Hardware providers call this routine in their detach routines.
310*0Sstevel@tonic-gate  * Software providers call this routine in their _fini() routine.
311*0Sstevel@tonic-gate  */
312*0Sstevel@tonic-gate int
313*0Sstevel@tonic-gate crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
314*0Sstevel@tonic-gate {
315*0Sstevel@tonic-gate 	int i;
316*0Sstevel@tonic-gate 	uint_t mech_idx;
317*0Sstevel@tonic-gate 	kcf_provider_desc_t *desc;
318*0Sstevel@tonic-gate 	crypto_notify_event_change_t ec;
319*0Sstevel@tonic-gate 	kcf_prov_state_t saved_state;
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	/* lookup provider descriptor */
322*0Sstevel@tonic-gate 	if ((desc = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
323*0Sstevel@tonic-gate 		return (CRYPTO_UNKNOWN_PROVIDER);
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	mutex_enter(&desc->pd_lock);
326*0Sstevel@tonic-gate 	/*
327*0Sstevel@tonic-gate 	 * Check if any other thread is disabling or removing
328*0Sstevel@tonic-gate 	 * this provider. We return if this is the case.
329*0Sstevel@tonic-gate 	 */
330*0Sstevel@tonic-gate 	if (desc->pd_state >= KCF_PROV_DISABLED) {
331*0Sstevel@tonic-gate 		mutex_exit(&desc->pd_lock);
332*0Sstevel@tonic-gate 		/* Release reference held by kcf_prov_tab_lookup(). */
333*0Sstevel@tonic-gate 		KCF_PROV_REFRELE(desc);
334*0Sstevel@tonic-gate 		return (CRYPTO_BUSY);
335*0Sstevel@tonic-gate 	}
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	saved_state = desc->pd_state;
338*0Sstevel@tonic-gate 	desc->pd_state = KCF_PROV_REMOVED;
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	if (saved_state == KCF_PROV_BUSY) {
341*0Sstevel@tonic-gate 		/*
342*0Sstevel@tonic-gate 		 * The per-provider taskq thread may be waiting. We
343*0Sstevel@tonic-gate 		 * signal it so that it can start failing requests.
344*0Sstevel@tonic-gate 		 * Note that we do not need a cv_broadcast() as we keep
345*0Sstevel@tonic-gate 		 * only a single thread per taskq.
346*0Sstevel@tonic-gate 		 */
347*0Sstevel@tonic-gate 		cv_signal(&desc->pd_resume_cv);
348*0Sstevel@tonic-gate 	}
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
351*0Sstevel@tonic-gate 		/*
352*0Sstevel@tonic-gate 		 * Check if this provider is currently being used.
353*0Sstevel@tonic-gate 		 * pd_irefcnt is the number of holds from the internal
354*0Sstevel@tonic-gate 		 * structures. We add one to account for the above lookup.
355*0Sstevel@tonic-gate 		 */
356*0Sstevel@tonic-gate 		if (desc->pd_refcnt > desc->pd_irefcnt + 1) {
357*0Sstevel@tonic-gate 			desc->pd_state = saved_state;
358*0Sstevel@tonic-gate 			mutex_exit(&desc->pd_lock);
359*0Sstevel@tonic-gate 			/* Release reference held by kcf_prov_tab_lookup(). */
360*0Sstevel@tonic-gate 			KCF_PROV_REFRELE(desc);
361*0Sstevel@tonic-gate 			/*
362*0Sstevel@tonic-gate 			 * The administrator presumably will stop the clients
363*0Sstevel@tonic-gate 			 * thus removing the holds, when they get the busy
364*0Sstevel@tonic-gate 			 * return value.  Any retry will succeed then.
365*0Sstevel@tonic-gate 			 */
366*0Sstevel@tonic-gate 			return (CRYPTO_BUSY);
367*0Sstevel@tonic-gate 		}
368*0Sstevel@tonic-gate 	}
369*0Sstevel@tonic-gate 	mutex_exit(&desc->pd_lock);
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	if (desc->pd_prov_type != CRYPTO_SW_PROVIDER) {
372*0Sstevel@tonic-gate 		remove_provider(desc);
373*0Sstevel@tonic-gate 	}
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	if (desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
376*0Sstevel@tonic-gate 		/* remove the provider from the mechanisms tables */
377*0Sstevel@tonic-gate 		for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
378*0Sstevel@tonic-gate 		    mech_idx++) {
379*0Sstevel@tonic-gate 			kcf_remove_mech_provider(
380*0Sstevel@tonic-gate 			    desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
381*0Sstevel@tonic-gate 		}
382*0Sstevel@tonic-gate 	}
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	/* remove provider from providers table */
385*0Sstevel@tonic-gate 	if (kcf_prov_tab_rem_provider((crypto_provider_id_t)handle) !=
386*0Sstevel@tonic-gate 	    CRYPTO_SUCCESS) {
387*0Sstevel@tonic-gate 		/* Release reference held by kcf_prov_tab_lookup(). */
388*0Sstevel@tonic-gate 		KCF_PROV_REFRELE(desc);
389*0Sstevel@tonic-gate 		return (CRYPTO_UNKNOWN_PROVIDER);
390*0Sstevel@tonic-gate 	}
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	/* destroy the kstat created for this provider */
393*0Sstevel@tonic-gate 	if (desc->pd_kstat != NULL) {
394*0Sstevel@tonic-gate 		kcf_provider_desc_t *kspd = desc->pd_kstat->ks_private;
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 		/* release reference held by desc->pd_kstat->ks_private */
397*0Sstevel@tonic-gate 		ASSERT(desc == kspd);
398*0Sstevel@tonic-gate 		kstat_delete(kspd->pd_kstat);
399*0Sstevel@tonic-gate 		KCF_PROV_REFRELE(kspd);
400*0Sstevel@tonic-gate 		KCF_PROV_IREFRELE(kspd);
401*0Sstevel@tonic-gate 	}
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 	if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
404*0Sstevel@tonic-gate 		/* Release reference held by kcf_prov_tab_lookup(). */
405*0Sstevel@tonic-gate 		KCF_PROV_REFRELE(desc);
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 		/*
408*0Sstevel@tonic-gate 		 * Wait till the existing requests complete.
409*0Sstevel@tonic-gate 		 */
410*0Sstevel@tonic-gate 		mutex_enter(&desc->pd_lock);
411*0Sstevel@tonic-gate 		while (desc->pd_state != KCF_PROV_FREED)
412*0Sstevel@tonic-gate 			cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
413*0Sstevel@tonic-gate 		mutex_exit(&desc->pd_lock);
414*0Sstevel@tonic-gate 	} else {
415*0Sstevel@tonic-gate 		/*
416*0Sstevel@tonic-gate 		 * Wait until requests that have been sent to the provider
417*0Sstevel@tonic-gate 		 * complete.
418*0Sstevel@tonic-gate 		 */
419*0Sstevel@tonic-gate 		mutex_enter(&desc->pd_lock);
420*0Sstevel@tonic-gate 		while (desc->pd_irefcnt > 0)
421*0Sstevel@tonic-gate 			cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
422*0Sstevel@tonic-gate 		mutex_exit(&desc->pd_lock);
423*0Sstevel@tonic-gate 	}
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 	/*
426*0Sstevel@tonic-gate 	 * Inform interested kernel clients of the event.
427*0Sstevel@tonic-gate 	 * Logical providers are not visible to kernel clients.
428*0Sstevel@tonic-gate 	 */
429*0Sstevel@tonic-gate 	if (desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
430*0Sstevel@tonic-gate 		ec.ec_provider_type = desc->pd_prov_type;
431*0Sstevel@tonic-gate 		ec.ec_change = CRYPTO_EVENT_CHANGE_REMOVED;
432*0Sstevel@tonic-gate 		for (i = 0; i < desc->pd_mech_list_count; i++) {
433*0Sstevel@tonic-gate 			/* Skip any mechanisms not allowed by the policy */
434*0Sstevel@tonic-gate 			if (is_mech_disabled(desc,
435*0Sstevel@tonic-gate 			    desc->pd_mechanisms[i].cm_mech_name))
436*0Sstevel@tonic-gate 				continue;
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate 			(void) strncpy(ec.ec_mech_name,
439*0Sstevel@tonic-gate 			    desc->pd_mechanisms[i].cm_mech_name,
440*0Sstevel@tonic-gate 			    CRYPTO_MAX_MECH_NAME);
441*0Sstevel@tonic-gate 			kcf_walk_ntfylist(CRYPTO_EVENT_PROVIDERS_CHANGE, &ec);
442*0Sstevel@tonic-gate 		}
443*0Sstevel@tonic-gate 	}
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
446*0Sstevel@tonic-gate 		/*
447*0Sstevel@tonic-gate 		 * This is the only place where kcf_free_provider_desc()
448*0Sstevel@tonic-gate 		 * is called directly. KCF_PROV_REFRELE() should free the
449*0Sstevel@tonic-gate 		 * structure in all other places.
450*0Sstevel@tonic-gate 		 */
451*0Sstevel@tonic-gate 		ASSERT(desc->pd_state == KCF_PROV_FREED &&
452*0Sstevel@tonic-gate 		    desc->pd_refcnt == 0);
453*0Sstevel@tonic-gate 		kcf_free_provider_desc(desc);
454*0Sstevel@tonic-gate 	} else {
455*0Sstevel@tonic-gate 		KCF_PROV_REFRELE(desc);
456*0Sstevel@tonic-gate 	}
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
459*0Sstevel@tonic-gate }
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate /*
462*0Sstevel@tonic-gate  * This routine is used to notify the framework that the state of
463*0Sstevel@tonic-gate  * a cryptographic provider has changed. Valid state codes are:
464*0Sstevel@tonic-gate  *
465*0Sstevel@tonic-gate  * CRYPTO_PROVIDER_READY
466*0Sstevel@tonic-gate  * 	The provider indicates that it can process more requests. A provider
467*0Sstevel@tonic-gate  *	will notify with this event if it previously has notified us with a
468*0Sstevel@tonic-gate  *	CRYPTO_PROVIDER_BUSY.
469*0Sstevel@tonic-gate  *
470*0Sstevel@tonic-gate  * CRYPTO_PROVIDER_BUSY
471*0Sstevel@tonic-gate  * 	The provider can not take more requests.
472*0Sstevel@tonic-gate  *
473*0Sstevel@tonic-gate  * CRYPTO_PROVIDER_FAILED
474*0Sstevel@tonic-gate  *	The provider encountered an internal error. The framework will not
475*0Sstevel@tonic-gate  * 	be sending any more requests to the provider. The provider may notify
476*0Sstevel@tonic-gate  *	with a CRYPTO_PROVIDER_READY, if it is able to recover from the error.
477*0Sstevel@tonic-gate  *
478*0Sstevel@tonic-gate  * This routine can be called from user or interrupt context.
479*0Sstevel@tonic-gate  */
480*0Sstevel@tonic-gate void
481*0Sstevel@tonic-gate crypto_provider_notification(crypto_kcf_provider_handle_t handle, uint_t state)
482*0Sstevel@tonic-gate {
483*0Sstevel@tonic-gate 	kcf_provider_desc_t *pd;
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate 	/* lookup the provider from the given handle */
486*0Sstevel@tonic-gate 	if ((pd = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
487*0Sstevel@tonic-gate 		return;
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 	mutex_enter(&pd->pd_lock);
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
492*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "crypto_provider_notification: "
493*0Sstevel@tonic-gate 		    "logical provider (%x) ignored\n", handle);
494*0Sstevel@tonic-gate 		goto out;
495*0Sstevel@tonic-gate 	}
496*0Sstevel@tonic-gate 	switch (state) {
497*0Sstevel@tonic-gate 	case CRYPTO_PROVIDER_READY:
498*0Sstevel@tonic-gate 		switch (pd->pd_state) {
499*0Sstevel@tonic-gate 		case KCF_PROV_BUSY:
500*0Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_READY;
501*0Sstevel@tonic-gate 			/*
502*0Sstevel@tonic-gate 			 * Signal the per-provider taskq thread that it
503*0Sstevel@tonic-gate 			 * can start submitting requests. Note that we do
504*0Sstevel@tonic-gate 			 * not need a cv_broadcast() as we keep only a
505*0Sstevel@tonic-gate 			 * single thread per taskq.
506*0Sstevel@tonic-gate 			 */
507*0Sstevel@tonic-gate 			cv_signal(&pd->pd_resume_cv);
508*0Sstevel@tonic-gate 			break;
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 		case KCF_PROV_FAILED:
511*0Sstevel@tonic-gate 			/*
512*0Sstevel@tonic-gate 			 * The provider recovered from the error. Let us
513*0Sstevel@tonic-gate 			 * use it now.
514*0Sstevel@tonic-gate 			 */
515*0Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_READY;
516*0Sstevel@tonic-gate 			break;
517*0Sstevel@tonic-gate 		}
518*0Sstevel@tonic-gate 		break;
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate 	case CRYPTO_PROVIDER_BUSY:
521*0Sstevel@tonic-gate 		switch (pd->pd_state) {
522*0Sstevel@tonic-gate 		case KCF_PROV_READY:
523*0Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_BUSY;
524*0Sstevel@tonic-gate 			break;
525*0Sstevel@tonic-gate 		}
526*0Sstevel@tonic-gate 		break;
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	case CRYPTO_PROVIDER_FAILED:
529*0Sstevel@tonic-gate 		/*
530*0Sstevel@tonic-gate 		 * We note the failure and return. The per-provider taskq
531*0Sstevel@tonic-gate 		 * thread checks this flag and starts failing the
532*0Sstevel@tonic-gate 		 * requests, if it is set. See process_req_hwp() for details.
533*0Sstevel@tonic-gate 		 */
534*0Sstevel@tonic-gate 		switch (pd->pd_state) {
535*0Sstevel@tonic-gate 		case KCF_PROV_READY:
536*0Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_FAILED;
537*0Sstevel@tonic-gate 			break;
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate 		case KCF_PROV_BUSY:
540*0Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_FAILED;
541*0Sstevel@tonic-gate 			/*
542*0Sstevel@tonic-gate 			 * The per-provider taskq thread may be waiting. We
543*0Sstevel@tonic-gate 			 * signal it so that it can start failing requests.
544*0Sstevel@tonic-gate 			 */
545*0Sstevel@tonic-gate 			cv_signal(&pd->pd_resume_cv);
546*0Sstevel@tonic-gate 			break;
547*0Sstevel@tonic-gate 		}
548*0Sstevel@tonic-gate 		break;
549*0Sstevel@tonic-gate 	}
550*0Sstevel@tonic-gate out:
551*0Sstevel@tonic-gate 	mutex_exit(&pd->pd_lock);
552*0Sstevel@tonic-gate 	KCF_PROV_REFRELE(pd);
553*0Sstevel@tonic-gate }
554*0Sstevel@tonic-gate 
555*0Sstevel@tonic-gate /*
556*0Sstevel@tonic-gate  * This routine is used to notify the framework the result of
557*0Sstevel@tonic-gate  * an asynchronous request handled by a provider. Valid error
558*0Sstevel@tonic-gate  * codes are the same as the CRYPTO_* errors defined in common.h.
559*0Sstevel@tonic-gate  *
560*0Sstevel@tonic-gate  * This routine can be called from user or interrupt context.
561*0Sstevel@tonic-gate  */
562*0Sstevel@tonic-gate void
563*0Sstevel@tonic-gate crypto_op_notification(crypto_req_handle_t handle, int error)
564*0Sstevel@tonic-gate {
565*0Sstevel@tonic-gate 	kcf_call_type_t ctype;
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 	if ((ctype = GET_REQ_TYPE(handle)) == CRYPTO_SYNCH) {
568*0Sstevel@tonic-gate 		kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)handle;
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate 		if (error != CRYPTO_SUCCESS)
571*0Sstevel@tonic-gate 			sreq->sn_provider->pd_sched_info.ks_nfails++;
572*0Sstevel@tonic-gate 		KCF_PROV_IREFRELE(sreq->sn_provider);
573*0Sstevel@tonic-gate 		kcf_sop_done(sreq, error);
574*0Sstevel@tonic-gate 	} else {
575*0Sstevel@tonic-gate 		kcf_areq_node_t *areq = (kcf_areq_node_t *)handle;
576*0Sstevel@tonic-gate 
577*0Sstevel@tonic-gate 		ASSERT(ctype == CRYPTO_ASYNCH);
578*0Sstevel@tonic-gate 		if (error != CRYPTO_SUCCESS)
579*0Sstevel@tonic-gate 			areq->an_provider->pd_sched_info.ks_nfails++;
580*0Sstevel@tonic-gate 		KCF_PROV_IREFRELE(areq->an_provider);
581*0Sstevel@tonic-gate 		kcf_aop_done(areq, error);
582*0Sstevel@tonic-gate 	}
583*0Sstevel@tonic-gate }
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate /*
586*0Sstevel@tonic-gate  * This routine is used by software providers to determine
587*0Sstevel@tonic-gate  * whether to use KM_SLEEP or KM_NOSLEEP during memory allocation.
588*0Sstevel@tonic-gate  * Note that hardware providers can always use KM_SLEEP. So,
589*0Sstevel@tonic-gate  * they do not need to call this routine.
590*0Sstevel@tonic-gate  *
591*0Sstevel@tonic-gate  * This routine can be called from user or interrupt context.
592*0Sstevel@tonic-gate  */
593*0Sstevel@tonic-gate int
594*0Sstevel@tonic-gate crypto_kmflag(crypto_req_handle_t handle)
595*0Sstevel@tonic-gate {
596*0Sstevel@tonic-gate 	return (REQHNDL2_KMFLAG(handle));
597*0Sstevel@tonic-gate }
598*0Sstevel@tonic-gate 
599*0Sstevel@tonic-gate 
600*0Sstevel@tonic-gate /*
601*0Sstevel@tonic-gate  * Copy an ops vector from src to dst. Used during provider registration
602*0Sstevel@tonic-gate  * to copy the ops vector from the provider info structure to the
603*0Sstevel@tonic-gate  * provider descriptor maintained by KCF.
604*0Sstevel@tonic-gate  * Copying the ops vector specified by the provider is needed since the
605*0Sstevel@tonic-gate  * framework does not require the provider info structure to be
606*0Sstevel@tonic-gate  * persistent.
607*0Sstevel@tonic-gate  */
608*0Sstevel@tonic-gate static void
609*0Sstevel@tonic-gate copy_ops_vector(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
610*0Sstevel@tonic-gate {
611*0Sstevel@tonic-gate 	KCF_SPI_COPY_OPS(src_ops, dst_ops, control_ops);
612*0Sstevel@tonic-gate 	KCF_SPI_COPY_OPS(src_ops, dst_ops, digest_ops);
613*0Sstevel@tonic-gate 	KCF_SPI_COPY_OPS(src_ops, dst_ops, cipher_ops);
614*0Sstevel@tonic-gate 	KCF_SPI_COPY_OPS(src_ops, dst_ops, mac_ops);
615*0Sstevel@tonic-gate 	KCF_SPI_COPY_OPS(src_ops, dst_ops, sign_ops);
616*0Sstevel@tonic-gate 	KCF_SPI_COPY_OPS(src_ops, dst_ops, verify_ops);
617*0Sstevel@tonic-gate 	KCF_SPI_COPY_OPS(src_ops, dst_ops, dual_ops);
618*0Sstevel@tonic-gate 	KCF_SPI_COPY_OPS(src_ops, dst_ops, dual_cipher_mac_ops);
619*0Sstevel@tonic-gate 	KCF_SPI_COPY_OPS(src_ops, dst_ops, random_ops);
620*0Sstevel@tonic-gate 	KCF_SPI_COPY_OPS(src_ops, dst_ops, session_ops);
621*0Sstevel@tonic-gate 	KCF_SPI_COPY_OPS(src_ops, dst_ops, object_ops);
622*0Sstevel@tonic-gate 	KCF_SPI_COPY_OPS(src_ops, dst_ops, key_ops);
623*0Sstevel@tonic-gate 	KCF_SPI_COPY_OPS(src_ops, dst_ops, provider_ops);
624*0Sstevel@tonic-gate 	KCF_SPI_COPY_OPS(src_ops, dst_ops, ctx_ops);
625*0Sstevel@tonic-gate }
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate /*
628*0Sstevel@tonic-gate  * Process the mechanism info structures specified by the provider
629*0Sstevel@tonic-gate  * during registration. A NULL crypto_provider_info_t indicates
630*0Sstevel@tonic-gate  * an already initialized provider descriptor.
631*0Sstevel@tonic-gate  *
632*0Sstevel@tonic-gate  * Mechanisms are not added to the kernel's mechanism table if the
633*0Sstevel@tonic-gate  * provider is a logical provider.
634*0Sstevel@tonic-gate  *
635*0Sstevel@tonic-gate  * Returns CRYPTO_SUCCESS on success, CRYPTO_ARGUMENTS if one
636*0Sstevel@tonic-gate  * of the specified mechanisms was malformed, or CRYPTO_HOST_MEMORY
637*0Sstevel@tonic-gate  * if the table of mechanisms is full.
638*0Sstevel@tonic-gate  */
639*0Sstevel@tonic-gate static int
640*0Sstevel@tonic-gate init_prov_mechs(crypto_provider_info_t *info, kcf_provider_desc_t *desc)
641*0Sstevel@tonic-gate {
642*0Sstevel@tonic-gate 	uint_t mech_idx;
643*0Sstevel@tonic-gate 	uint_t cleanup_idx;
644*0Sstevel@tonic-gate 	int err = CRYPTO_SUCCESS;
645*0Sstevel@tonic-gate 	kcf_prov_mech_desc_t *pmd;
646*0Sstevel@tonic-gate 	int desc_use_count = 0;
647*0Sstevel@tonic-gate 	int mcount = desc->pd_mech_list_count;
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate 	if (desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
650*0Sstevel@tonic-gate 		if (info != NULL) {
651*0Sstevel@tonic-gate 			ASSERT(info->pi_mechanisms != NULL);
652*0Sstevel@tonic-gate 			bcopy(info->pi_mechanisms, desc->pd_mechanisms,
653*0Sstevel@tonic-gate 			    sizeof (crypto_mech_info_t) * mcount);
654*0Sstevel@tonic-gate 		}
655*0Sstevel@tonic-gate 		return (CRYPTO_SUCCESS);
656*0Sstevel@tonic-gate 	}
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate 	/*
659*0Sstevel@tonic-gate 	 * Copy the mechanism list from the provider info to the provider
660*0Sstevel@tonic-gate 	 * descriptor. desc->pd_mechanisms has an extra crypto_mech_info_t
661*0Sstevel@tonic-gate 	 * element if the provider has random_ops since we keep an internal
662*0Sstevel@tonic-gate 	 * mechanism, SUN_RANDOM, in this case.
663*0Sstevel@tonic-gate 	 */
664*0Sstevel@tonic-gate 	if (info != NULL) {
665*0Sstevel@tonic-gate 		if (info->pi_ops_vector->random_ops != NULL) {
666*0Sstevel@tonic-gate 			crypto_mech_info_t *rand_mi;
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 			/*
669*0Sstevel@tonic-gate 			 * Need the following check as it is possible to have
670*0Sstevel@tonic-gate 			 * a provider that implements just random_ops and has
671*0Sstevel@tonic-gate 			 * pi_mechanisms == NULL.
672*0Sstevel@tonic-gate 			 */
673*0Sstevel@tonic-gate 			if (info->pi_mechanisms != NULL) {
674*0Sstevel@tonic-gate 				bcopy(info->pi_mechanisms, desc->pd_mechanisms,
675*0Sstevel@tonic-gate 				    sizeof (crypto_mech_info_t) * (mcount - 1));
676*0Sstevel@tonic-gate 			}
677*0Sstevel@tonic-gate 			rand_mi = &desc->pd_mechanisms[mcount - 1];
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 			bzero(rand_mi, sizeof (crypto_mech_info_t));
680*0Sstevel@tonic-gate 			(void) strncpy(rand_mi->cm_mech_name, SUN_RANDOM,
681*0Sstevel@tonic-gate 			    CRYPTO_MAX_MECH_NAME);
682*0Sstevel@tonic-gate 			rand_mi->cm_func_group_mask = CRYPTO_FG_RANDOM;
683*0Sstevel@tonic-gate 			/*
684*0Sstevel@tonic-gate 			 * What we really need here is a
685*0Sstevel@tonic-gate 			 * CRYPTO_KEYSIZE_NOT_APPLICABLE. We make do with the
686*0Sstevel@tonic-gate 			 * following for now.
687*0Sstevel@tonic-gate 			 */
688*0Sstevel@tonic-gate 			rand_mi->cm_keysize_unit = CRYPTO_KEYSIZE_UNIT_IN_BITS;
689*0Sstevel@tonic-gate 		} else {
690*0Sstevel@tonic-gate 			ASSERT(info->pi_mechanisms != NULL);
691*0Sstevel@tonic-gate 			bcopy(info->pi_mechanisms, desc->pd_mechanisms,
692*0Sstevel@tonic-gate 			    sizeof (crypto_mech_info_t) * mcount);
693*0Sstevel@tonic-gate 		}
694*0Sstevel@tonic-gate 	}
695*0Sstevel@tonic-gate 
696*0Sstevel@tonic-gate 	/*
697*0Sstevel@tonic-gate 	 * For each mechanism support by the provider, add the provider
698*0Sstevel@tonic-gate 	 * to the corresponding KCF mechanism mech_entry chain.
699*0Sstevel@tonic-gate 	 */
700*0Sstevel@tonic-gate 	for (mech_idx = 0; mech_idx < desc->pd_mech_list_count; mech_idx++) {
701*0Sstevel@tonic-gate 		crypto_mech_info_t *mi = &desc->pd_mechanisms[mech_idx];
702*0Sstevel@tonic-gate 
703*0Sstevel@tonic-gate 		if (mi->cm_keysize_unit != CRYPTO_KEYSIZE_UNIT_IN_BITS &&
704*0Sstevel@tonic-gate 		    mi->cm_keysize_unit != CRYPTO_KEYSIZE_UNIT_IN_BYTES) {
705*0Sstevel@tonic-gate 			err = CRYPTO_ARGUMENTS_BAD;
706*0Sstevel@tonic-gate 			break;
707*0Sstevel@tonic-gate 		}
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate 		if (kcf_add_mech_provider(mi, desc, &pmd) != KCF_SUCCESS)
710*0Sstevel@tonic-gate 			break;
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate 		if (pmd == NULL)
713*0Sstevel@tonic-gate 			continue;
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate 		/* The provider will be used for this mechanism */
716*0Sstevel@tonic-gate 		desc_use_count++;
717*0Sstevel@tonic-gate 	}
718*0Sstevel@tonic-gate 
719*0Sstevel@tonic-gate 	/*
720*0Sstevel@tonic-gate 	 * The provider will not be used for any mechanism. So, we fail its
721*0Sstevel@tonic-gate 	 * registration. Note that if at least one of the mechanisms from the
722*0Sstevel@tonic-gate 	 * provider can be used, we do it. This means there can be a overlap
723*0Sstevel@tonic-gate 	 * between the mechanisms offered by providers. The first one to
724*0Sstevel@tonic-gate 	 * register is used. Also, a policy to disable mechanisms of a provider
725*0Sstevel@tonic-gate 	 * will cause the provider to be not used for those mechanisms.
726*0Sstevel@tonic-gate 	 */
727*0Sstevel@tonic-gate 	if (desc_use_count == 0)
728*0Sstevel@tonic-gate 		return (CRYPTO_ARGUMENTS_BAD);
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 	if (err == KCF_SUCCESS)
731*0Sstevel@tonic-gate 		return (CRYPTO_SUCCESS);
732*0Sstevel@tonic-gate 
733*0Sstevel@tonic-gate 	/*
734*0Sstevel@tonic-gate 	 * An error occurred while adding the mechanism, cleanup
735*0Sstevel@tonic-gate 	 * and bail.
736*0Sstevel@tonic-gate 	 */
737*0Sstevel@tonic-gate 	for (cleanup_idx = 0; cleanup_idx < mech_idx; cleanup_idx++) {
738*0Sstevel@tonic-gate 		kcf_remove_mech_provider(
739*0Sstevel@tonic-gate 		    desc->pd_mechanisms[cleanup_idx].cm_mech_name, desc);
740*0Sstevel@tonic-gate 	}
741*0Sstevel@tonic-gate 
742*0Sstevel@tonic-gate 	if (err == KCF_MECH_TAB_FULL)
743*0Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 	return (CRYPTO_ARGUMENTS_BAD);
746*0Sstevel@tonic-gate }
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate /*
749*0Sstevel@tonic-gate  * Update routine for kstat. Only privileged users are allowed to
750*0Sstevel@tonic-gate  * access this information, since this information is sensitive.
751*0Sstevel@tonic-gate  * There are some cryptographic attacks (e.g. traffic analysis)
752*0Sstevel@tonic-gate  * which can use this information.
753*0Sstevel@tonic-gate  */
754*0Sstevel@tonic-gate static int
755*0Sstevel@tonic-gate kcf_prov_kstat_update(kstat_t *ksp, int rw)
756*0Sstevel@tonic-gate {
757*0Sstevel@tonic-gate 	kcf_prov_stats_t *ks_data;
758*0Sstevel@tonic-gate 	kcf_provider_desc_t *pd = (kcf_provider_desc_t *)ksp->ks_private;
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
761*0Sstevel@tonic-gate 		return (EACCES);
762*0Sstevel@tonic-gate 
763*0Sstevel@tonic-gate 	ks_data = ksp->ks_data;
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 	if (secpolicy_sys_config(CRED(), B_TRUE) != 0) {
766*0Sstevel@tonic-gate 		ks_data->ps_ops_total.value.ui64 = 0;
767*0Sstevel@tonic-gate 		ks_data->ps_ops_passed.value.ui64 = 0;
768*0Sstevel@tonic-gate 		ks_data->ps_ops_failed.value.ui64 = 0;
769*0Sstevel@tonic-gate 		ks_data->ps_ops_busy_rval.value.ui64 = 0;
770*0Sstevel@tonic-gate 	} else {
771*0Sstevel@tonic-gate 		ks_data->ps_ops_total.value.ui64 =
772*0Sstevel@tonic-gate 		    pd->pd_sched_info.ks_ndispatches;
773*0Sstevel@tonic-gate 		ks_data->ps_ops_failed.value.ui64 =
774*0Sstevel@tonic-gate 		    pd->pd_sched_info.ks_nfails;
775*0Sstevel@tonic-gate 		ks_data->ps_ops_busy_rval.value.ui64 =
776*0Sstevel@tonic-gate 		    pd->pd_sched_info.ks_nbusy_rval;
777*0Sstevel@tonic-gate 		ks_data->ps_ops_passed.value.ui64 =
778*0Sstevel@tonic-gate 		    pd->pd_sched_info.ks_ndispatches -
779*0Sstevel@tonic-gate 		    pd->pd_sched_info.ks_nfails -
780*0Sstevel@tonic-gate 		    pd->pd_sched_info.ks_nbusy_rval;
781*0Sstevel@tonic-gate 	}
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 	return (0);
784*0Sstevel@tonic-gate }
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate 
787*0Sstevel@tonic-gate /*
788*0Sstevel@tonic-gate  * Utility routine called from failure paths in crypto_register_provider()
789*0Sstevel@tonic-gate  * and from crypto_load_soft_disabled().
790*0Sstevel@tonic-gate  */
791*0Sstevel@tonic-gate void
792*0Sstevel@tonic-gate undo_register_provider(kcf_provider_desc_t *desc, boolean_t remove_prov)
793*0Sstevel@tonic-gate {
794*0Sstevel@tonic-gate 	uint_t mech_idx;
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate 	/* remove the provider from the mechanisms tables */
797*0Sstevel@tonic-gate 	for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
798*0Sstevel@tonic-gate 	    mech_idx++) {
799*0Sstevel@tonic-gate 		kcf_remove_mech_provider(
800*0Sstevel@tonic-gate 		    desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
801*0Sstevel@tonic-gate 	}
802*0Sstevel@tonic-gate 
803*0Sstevel@tonic-gate 	/* remove provider from providers table */
804*0Sstevel@tonic-gate 	if (remove_prov)
805*0Sstevel@tonic-gate 		(void) kcf_prov_tab_rem_provider(desc->pd_prov_id);
806*0Sstevel@tonic-gate }
807*0Sstevel@tonic-gate 
808*0Sstevel@tonic-gate /*
809*0Sstevel@tonic-gate  * Utility routine called from crypto_load_soft_disabled(). Callers
810*0Sstevel@tonic-gate  * should have done a prior undo_register_provider().
811*0Sstevel@tonic-gate  */
812*0Sstevel@tonic-gate void
813*0Sstevel@tonic-gate redo_register_provider(kcf_provider_desc_t *pd)
814*0Sstevel@tonic-gate {
815*0Sstevel@tonic-gate 	/* process the mechanisms supported by the provider */
816*0Sstevel@tonic-gate 	(void) init_prov_mechs(NULL, pd);
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate 	/*
819*0Sstevel@tonic-gate 	 * Hold provider in providers table. We should not call
820*0Sstevel@tonic-gate 	 * kcf_prov_tab_add_provider() here as the provider descriptor
821*0Sstevel@tonic-gate 	 * is still valid which means it has an entry in the provider
822*0Sstevel@tonic-gate 	 * table.
823*0Sstevel@tonic-gate 	 */
824*0Sstevel@tonic-gate 	KCF_PROV_REFHOLD(pd);
825*0Sstevel@tonic-gate 	KCF_PROV_IREFHOLD(pd);
826*0Sstevel@tonic-gate }
827*0Sstevel@tonic-gate 
828*0Sstevel@tonic-gate /*
829*0Sstevel@tonic-gate  * Add provider (p1) to another provider's array of providers (p2).
830*0Sstevel@tonic-gate  * Hardware and logical providers use this array to cross-reference
831*0Sstevel@tonic-gate  * each other.
832*0Sstevel@tonic-gate  */
833*0Sstevel@tonic-gate static void
834*0Sstevel@tonic-gate add_provider_to_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
835*0Sstevel@tonic-gate {
836*0Sstevel@tonic-gate 	kcf_provider_list_t *new;
837*0Sstevel@tonic-gate 
838*0Sstevel@tonic-gate 	new = kmem_alloc(sizeof (kcf_provider_list_t), KM_SLEEP);
839*0Sstevel@tonic-gate 	mutex_enter(&p2->pd_lock);
840*0Sstevel@tonic-gate 	new->pl_next = p2->pd_provider_list;
841*0Sstevel@tonic-gate 	p2->pd_provider_list = new;
842*0Sstevel@tonic-gate 	KCF_PROV_IREFHOLD(p1);
843*0Sstevel@tonic-gate 	new->pl_provider = p1;
844*0Sstevel@tonic-gate 	mutex_exit(&p2->pd_lock);
845*0Sstevel@tonic-gate }
846*0Sstevel@tonic-gate 
847*0Sstevel@tonic-gate /*
848*0Sstevel@tonic-gate  * Remove provider (p1) from another provider's array of providers (p2).
849*0Sstevel@tonic-gate  * Hardware and logical providers use this array to cross-reference
850*0Sstevel@tonic-gate  * each other.
851*0Sstevel@tonic-gate  */
852*0Sstevel@tonic-gate static void
853*0Sstevel@tonic-gate remove_provider_from_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
854*0Sstevel@tonic-gate {
855*0Sstevel@tonic-gate 
856*0Sstevel@tonic-gate 	kcf_provider_list_t *pl = NULL, **prev;
857*0Sstevel@tonic-gate 
858*0Sstevel@tonic-gate 	mutex_enter(&p2->pd_lock);
859*0Sstevel@tonic-gate 	for (pl = p2->pd_provider_list, prev = &p2->pd_provider_list;
860*0Sstevel@tonic-gate 	    pl != NULL; prev = &pl->pl_next, pl = pl->pl_next) {
861*0Sstevel@tonic-gate 		if (pl->pl_provider == p1) {
862*0Sstevel@tonic-gate 			break;
863*0Sstevel@tonic-gate 		}
864*0Sstevel@tonic-gate 	}
865*0Sstevel@tonic-gate 
866*0Sstevel@tonic-gate 	if (p1 == NULL) {
867*0Sstevel@tonic-gate 		mutex_exit(&p2->pd_lock);
868*0Sstevel@tonic-gate 		return;
869*0Sstevel@tonic-gate 	}
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 	/* detach and free kcf_provider_list structure */
872*0Sstevel@tonic-gate 	KCF_PROV_IREFRELE(p1);
873*0Sstevel@tonic-gate 	*prev = pl->pl_next;
874*0Sstevel@tonic-gate 	kmem_free(pl, sizeof (*pl));
875*0Sstevel@tonic-gate 	mutex_exit(&p2->pd_lock);
876*0Sstevel@tonic-gate }
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate /*
879*0Sstevel@tonic-gate  * Convert an array of logical provider handles (crypto_provider_id)
880*0Sstevel@tonic-gate  * stored in a crypto_provider_info structure into an array of provider
881*0Sstevel@tonic-gate  * descriptors (kcf_provider_desc_t) attached to a logical provider.
882*0Sstevel@tonic-gate  */
883*0Sstevel@tonic-gate static void
884*0Sstevel@tonic-gate process_logical_providers(crypto_provider_info_t *info, kcf_provider_desc_t *hp)
885*0Sstevel@tonic-gate {
886*0Sstevel@tonic-gate 	kcf_provider_desc_t *lp;
887*0Sstevel@tonic-gate 	crypto_provider_id_t handle;
888*0Sstevel@tonic-gate 	int count = info->pi_logical_provider_count;
889*0Sstevel@tonic-gate 	int i;
890*0Sstevel@tonic-gate 
891*0Sstevel@tonic-gate 	/* add hardware provider to each logical provider */
892*0Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
893*0Sstevel@tonic-gate 		handle = info->pi_logical_providers[i];
894*0Sstevel@tonic-gate 		lp = kcf_prov_tab_lookup((crypto_provider_id_t)handle);
895*0Sstevel@tonic-gate 		if (lp == NULL) {
896*0Sstevel@tonic-gate 			continue;
897*0Sstevel@tonic-gate 		}
898*0Sstevel@tonic-gate 		add_provider_to_array(hp, lp);
899*0Sstevel@tonic-gate 
900*0Sstevel@tonic-gate 		/*
901*0Sstevel@tonic-gate 		 * A hardware provider has to have the provider descriptor of
902*0Sstevel@tonic-gate 		 * every logical provider it belongs to, so it can be removed
903*0Sstevel@tonic-gate 		 * from the logical provider if the hardware provider
904*0Sstevel@tonic-gate 		 * unregisters from the framework.
905*0Sstevel@tonic-gate 		 */
906*0Sstevel@tonic-gate 		add_provider_to_array(lp, hp);
907*0Sstevel@tonic-gate 		KCF_PROV_REFRELE(lp);
908*0Sstevel@tonic-gate 	}
909*0Sstevel@tonic-gate }
910*0Sstevel@tonic-gate 
911*0Sstevel@tonic-gate /*
912*0Sstevel@tonic-gate  * This routine removes a provider from all of the logical or
913*0Sstevel@tonic-gate  * hardware providers it belongs to, and frees the provider's
914*0Sstevel@tonic-gate  * array of pointers to providers.
915*0Sstevel@tonic-gate  */
916*0Sstevel@tonic-gate static void
917*0Sstevel@tonic-gate remove_provider(kcf_provider_desc_t *pp)
918*0Sstevel@tonic-gate {
919*0Sstevel@tonic-gate 	kcf_provider_desc_t *p;
920*0Sstevel@tonic-gate 	kcf_provider_list_t *e, *next;
921*0Sstevel@tonic-gate 
922*0Sstevel@tonic-gate 	mutex_enter(&pp->pd_lock);
923*0Sstevel@tonic-gate 	for (e = pp->pd_provider_list; e != NULL; e = next) {
924*0Sstevel@tonic-gate 		p = e->pl_provider;
925*0Sstevel@tonic-gate 		remove_provider_from_array(pp, p);
926*0Sstevel@tonic-gate 		KCF_PROV_IREFRELE(p);
927*0Sstevel@tonic-gate 		next = e->pl_next;
928*0Sstevel@tonic-gate 		kmem_free(e, sizeof (*e));
929*0Sstevel@tonic-gate 	}
930*0Sstevel@tonic-gate 	pp->pd_provider_list = NULL;
931*0Sstevel@tonic-gate 	mutex_exit(&pp->pd_lock);
932*0Sstevel@tonic-gate }
933