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  * The ioctl interface for cryptographic commands.
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <sys/types.h>
34*0Sstevel@tonic-gate #include <sys/modctl.h>
35*0Sstevel@tonic-gate #include <sys/conf.h>
36*0Sstevel@tonic-gate #include <sys/stat.h>
37*0Sstevel@tonic-gate #include <sys/ddi.h>
38*0Sstevel@tonic-gate #include <sys/sunddi.h>
39*0Sstevel@tonic-gate #include <sys/kmem.h>
40*0Sstevel@tonic-gate #include <sys/errno.h>
41*0Sstevel@tonic-gate #include <sys/ksynch.h>
42*0Sstevel@tonic-gate #include <sys/file.h>
43*0Sstevel@tonic-gate #include <sys/open.h>
44*0Sstevel@tonic-gate #include <sys/cred.h>
45*0Sstevel@tonic-gate #include <sys/proc.h>
46*0Sstevel@tonic-gate #include <sys/task.h>
47*0Sstevel@tonic-gate #include <sys/mkdev.h>
48*0Sstevel@tonic-gate #include <sys/model.h>
49*0Sstevel@tonic-gate #include <sys/sysmacros.h>
50*0Sstevel@tonic-gate #include <sys/crypto/common.h>
51*0Sstevel@tonic-gate #include <sys/crypto/api.h>
52*0Sstevel@tonic-gate #include <sys/crypto/impl.h>
53*0Sstevel@tonic-gate #include <sys/crypto/sched_impl.h>
54*0Sstevel@tonic-gate #include <sys/crypto/ioctl.h>
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate /*
57*0Sstevel@tonic-gate  * Locking notes:
58*0Sstevel@tonic-gate  *
59*0Sstevel@tonic-gate  * crypto_lock protects the global array of minor structures.  It
60*0Sstevel@tonic-gate  * also protects the cm_refcnt member of each of these structures.
61*0Sstevel@tonic-gate  * The crypto_cv is used to signal decrements in the cm_refcnt,
62*0Sstevel@tonic-gate  * and is used with the global crypto_lock.
63*0Sstevel@tonic-gate  *
64*0Sstevel@tonic-gate  * Other fields in the minor structure are protected by the
65*0Sstevel@tonic-gate  * cm_lock member of the minor structure.
66*0Sstevel@tonic-gate  */
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate /*
69*0Sstevel@tonic-gate  * DDI entry points.
70*0Sstevel@tonic-gate  */
71*0Sstevel@tonic-gate static int crypto_attach(dev_info_t *, ddi_attach_cmd_t);
72*0Sstevel@tonic-gate static int crypto_detach(dev_info_t *, ddi_detach_cmd_t);
73*0Sstevel@tonic-gate static int crypto_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
74*0Sstevel@tonic-gate static int crypto_open(dev_t *, int, int, cred_t *);
75*0Sstevel@tonic-gate static int crypto_close(dev_t, int, int, cred_t *);
76*0Sstevel@tonic-gate static int crypto_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate static int cipher_init(dev_t, caddr_t, int, int (*)(kcf_provider_desc_t *,
79*0Sstevel@tonic-gate     crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
80*0Sstevel@tonic-gate     crypto_ctx_template_t, crypto_context_t *, crypto_call_req_t *));
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate static int common_digest(dev_t, caddr_t, int, int (*)(crypto_context_t,
83*0Sstevel@tonic-gate     crypto_data_t *, crypto_data_t *, crypto_call_req_t *));
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate static int cipher(dev_t, caddr_t, int, int (*)(crypto_context_t,
86*0Sstevel@tonic-gate     crypto_data_t *, crypto_data_t *, crypto_call_req_t *));
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate static int cipher_update(dev_t, caddr_t, int, int (*)(crypto_context_t,
89*0Sstevel@tonic-gate     crypto_data_t *, crypto_data_t *, crypto_call_req_t *));
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate static int common_final(dev_t, caddr_t, int, int (*)(crypto_context_t,
92*0Sstevel@tonic-gate     crypto_data_t *, crypto_call_req_t *));
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate static int sign_verify_init(dev_t, caddr_t, int, int (*)(kcf_provider_desc_t *,
95*0Sstevel@tonic-gate     crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
96*0Sstevel@tonic-gate     crypto_ctx_template_t, crypto_context_t *, crypto_call_req_t *));
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate static int sign_verify_update(dev_t dev, caddr_t arg, int mode,
99*0Sstevel@tonic-gate     int (*)(crypto_context_t, crypto_data_t *, crypto_call_req_t *));
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate static void crypto_initialize_rctl(void);
102*0Sstevel@tonic-gate static void crypto_release_provider_session(crypto_minor_t *,
103*0Sstevel@tonic-gate     crypto_provider_session_t *);
104*0Sstevel@tonic-gate static int crypto_buffer_check(size_t, kproject_t **);
105*0Sstevel@tonic-gate static int crypto_free_find_ctx(crypto_session_data_t *);
106*0Sstevel@tonic-gate static int crypto_get_provider_list(crypto_minor_t *, uint_t *,
107*0Sstevel@tonic-gate     crypto_provider_entry_t **, boolean_t);
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate /* number of minor numbers to allocate at a time */
110*0Sstevel@tonic-gate #define	CRYPTO_MINOR_CHUNK	16
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate /*
113*0Sstevel@tonic-gate  * There are two limits associated with kernel memory. The first,
114*0Sstevel@tonic-gate  * CRYPTO_MAX_BUFFER_LEN, is the maximum number of bytes that can be
115*0Sstevel@tonic-gate  * allocated for a single copyin/copyout buffer. The second limit is
116*0Sstevel@tonic-gate  * the total number of bytes that can be allocated by a process
117*0Sstevel@tonic-gate  * for copyin/copyout buffers. The latter is enforced by the
118*0Sstevel@tonic-gate  * project.max-crypto-memory resource control.
119*0Sstevel@tonic-gate  */
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate #define	CRYPTO_MAX_BUFFER_LEN	(2 * 1024 * 1024)
122*0Sstevel@tonic-gate #define	CRYPTO_MAX_FIND_COUNT	512
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate /*
125*0Sstevel@tonic-gate  * When a mechanism parameter length is less than CRYPTO_DEFERRED_LIMIT
126*0Sstevel@tonic-gate  * bytes, then the length is added to the next resource control check.
127*0Sstevel@tonic-gate  */
128*0Sstevel@tonic-gate #define	CRYPTO_DEFERRED_LIMIT	100
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate /* The session table grows by CRYPTO_SESSION_CHUNK increments */
131*0Sstevel@tonic-gate #define	CRYPTO_SESSION_CHUNK	100
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate size_t crypto_max_buffer_len = CRYPTO_MAX_BUFFER_LEN;
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate #define	INIT_RAW_CRYPTO_DATA(data, len)				\
136*0Sstevel@tonic-gate 	(data).cd_format = CRYPTO_DATA_RAW;			\
137*0Sstevel@tonic-gate 	(data).cd_raw.iov_base = kmem_alloc(len, KM_SLEEP);	\
138*0Sstevel@tonic-gate 	(data).cd_raw.iov_len = len;				\
139*0Sstevel@tonic-gate 	(data).cd_offset = 0;					\
140*0Sstevel@tonic-gate 	(data).cd_length = len;
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate static crypto_mech_type_t random_mech = CRYPTO_MECH_INVALID;
143*0Sstevel@tonic-gate static struct kmem_cache *crypto_session_cache;
144*0Sstevel@tonic-gate static crypto_minor_t **crypto_minors = NULL;
145*0Sstevel@tonic-gate static dev_info_t *crypto_dip = NULL;
146*0Sstevel@tonic-gate static minor_t crypto_minor_chunk = CRYPTO_MINOR_CHUNK;
147*0Sstevel@tonic-gate static minor_t crypto_minors_table_count = 0;
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate /*
150*0Sstevel@tonic-gate  * Minors are started from 1 because vmem_alloc()
151*0Sstevel@tonic-gate  * returns 0 in case of failure.
152*0Sstevel@tonic-gate  */
153*0Sstevel@tonic-gate static vmem_t *crypto_arena = NULL;	/* Arena for device minors */
154*0Sstevel@tonic-gate static minor_t crypto_minors_count = 0;
155*0Sstevel@tonic-gate static kmutex_t crypto_lock;
156*0Sstevel@tonic-gate static kmutex_t crypto_rctl_lock;
157*0Sstevel@tonic-gate static kcondvar_t crypto_cv;
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate #define	RETURN_LIST			B_TRUE
160*0Sstevel@tonic-gate #define	DONT_RETURN_LIST		B_FALSE
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate #define	CRYPTO_OPS_OFFSET(f)		offsetof(crypto_ops_t, f)
163*0Sstevel@tonic-gate #define	CRYPTO_DIGEST_OFFSET(f)		offsetof(crypto_digest_ops_t, f)
164*0Sstevel@tonic-gate #define	CRYPTO_CIPHER_OFFSET(f)		offsetof(crypto_cipher_ops_t, f)
165*0Sstevel@tonic-gate #define	CRYPTO_SIGN_OFFSET(f)		offsetof(crypto_sign_ops_t, f)
166*0Sstevel@tonic-gate #define	CRYPTO_VERIFY_OFFSET(f)		offsetof(crypto_verify_ops_t, f)
167*0Sstevel@tonic-gate #define	CRYPTO_RANDOM_OFFSET(f)		offsetof(crypto_random_number_ops_t, f)
168*0Sstevel@tonic-gate #define	CRYPTO_SESSION_OFFSET(f)	offsetof(crypto_session_ops_t, f)
169*0Sstevel@tonic-gate #define	CRYPTO_OBJECT_OFFSET(f)		offsetof(crypto_object_ops_t, f)
170*0Sstevel@tonic-gate #define	CRYPTO_KEY_OFFSET(f)		offsetof(crypto_key_ops_t, f)
171*0Sstevel@tonic-gate #define	CRYPTO_PROVIDER_OFFSET(f)	\
172*0Sstevel@tonic-gate 	offsetof(crypto_provider_management_ops_t, f)
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate #define	CRYPTO_CANCEL_CTX(spp) {	\
175*0Sstevel@tonic-gate 	crypto_cancel_ctx(*(spp));	\
176*0Sstevel@tonic-gate 	*(spp) = NULL;			\
177*0Sstevel@tonic-gate }
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate #define	CRYPTO_CANCEL_ALL_CTX(sp) {				\
180*0Sstevel@tonic-gate 	if ((sp)->sd_digest_ctx != NULL) {			\
181*0Sstevel@tonic-gate 		crypto_cancel_ctx((sp)->sd_digest_ctx);		\
182*0Sstevel@tonic-gate 		(sp)->sd_digest_ctx = NULL;			\
183*0Sstevel@tonic-gate 	}							\
184*0Sstevel@tonic-gate 	if ((sp)->sd_encr_ctx != NULL) {			\
185*0Sstevel@tonic-gate 		crypto_cancel_ctx((sp)->sd_encr_ctx);		\
186*0Sstevel@tonic-gate 		(sp)->sd_encr_ctx = NULL;			\
187*0Sstevel@tonic-gate 	}							\
188*0Sstevel@tonic-gate 	if ((sp)->sd_decr_ctx != NULL) {			\
189*0Sstevel@tonic-gate 		crypto_cancel_ctx((sp)->sd_decr_ctx);		\
190*0Sstevel@tonic-gate 		(sp)->sd_decr_ctx = NULL;			\
191*0Sstevel@tonic-gate 	}							\
192*0Sstevel@tonic-gate 	if ((sp)->sd_sign_ctx != NULL) {			\
193*0Sstevel@tonic-gate 		crypto_cancel_ctx((sp)->sd_sign_ctx);		\
194*0Sstevel@tonic-gate 		(sp)->sd_sign_ctx = NULL;			\
195*0Sstevel@tonic-gate 	}							\
196*0Sstevel@tonic-gate 	if ((sp)->sd_verify_ctx != NULL) {			\
197*0Sstevel@tonic-gate 		crypto_cancel_ctx((sp)->sd_verify_ctx);		\
198*0Sstevel@tonic-gate 		(sp)->sd_verify_ctx = NULL;			\
199*0Sstevel@tonic-gate 	}							\
200*0Sstevel@tonic-gate 	if ((sp)->sd_sign_recover_ctx != NULL) {		\
201*0Sstevel@tonic-gate 		crypto_cancel_ctx((sp)->sd_sign_recover_ctx);	\
202*0Sstevel@tonic-gate 		(sp)->sd_sign_recover_ctx = NULL;		\
203*0Sstevel@tonic-gate 	}							\
204*0Sstevel@tonic-gate 	if ((sp)->sd_verify_recover_ctx != NULL) {		\
205*0Sstevel@tonic-gate 		crypto_cancel_ctx((sp)->sd_verify_recover_ctx);	\
206*0Sstevel@tonic-gate 		(sp)->sd_verify_recover_ctx = NULL;		\
207*0Sstevel@tonic-gate 	}							\
208*0Sstevel@tonic-gate }
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate #define	CRYPTO_DECREMENT_RCTL(val, projp) {				\
211*0Sstevel@tonic-gate 	ASSERT(projp != NULL);						\
212*0Sstevel@tonic-gate 	(projp)->kpj_data.kpd_crypto_mem -= (val);			\
213*0Sstevel@tonic-gate 	project_rele(projp);						\
214*0Sstevel@tonic-gate }
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate /*
217*0Sstevel@tonic-gate  * Module linkage.
218*0Sstevel@tonic-gate  */
219*0Sstevel@tonic-gate static struct cb_ops cbops = {
220*0Sstevel@tonic-gate 	crypto_open,		/* cb_open */
221*0Sstevel@tonic-gate 	crypto_close,		/* cb_close */
222*0Sstevel@tonic-gate 	nodev,			/* cb_strategy */
223*0Sstevel@tonic-gate 	nodev,			/* cb_print */
224*0Sstevel@tonic-gate 	nodev,			/* cb_dump */
225*0Sstevel@tonic-gate 	nodev,			/* cb_read */
226*0Sstevel@tonic-gate 	nodev,			/* cb_write */
227*0Sstevel@tonic-gate 	crypto_ioctl,		/* cb_ioctl */
228*0Sstevel@tonic-gate 	nodev,			/* cb_devmap */
229*0Sstevel@tonic-gate 	nodev,			/* cb_mmap */
230*0Sstevel@tonic-gate 	nodev,			/* cb_segmap */
231*0Sstevel@tonic-gate 	nochpoll,		/* cb_chpoll */
232*0Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
233*0Sstevel@tonic-gate 	NULL,			/* cb_streamtab */
234*0Sstevel@tonic-gate 	D_MP,			/* cb_flag */
235*0Sstevel@tonic-gate 	CB_REV,			/* cb_rev */
236*0Sstevel@tonic-gate 	nodev,			/* cb_aread */
237*0Sstevel@tonic-gate 	nodev,			/* cb_awrite */
238*0Sstevel@tonic-gate };
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate static struct dev_ops devops = {
241*0Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
242*0Sstevel@tonic-gate 	0,			/* devo_refcnt */
243*0Sstevel@tonic-gate 	crypto_getinfo,		/* devo_getinfo */
244*0Sstevel@tonic-gate 	nulldev,		/* devo_identify */
245*0Sstevel@tonic-gate 	nulldev,		/* devo_probe */
246*0Sstevel@tonic-gate 	crypto_attach,		/* devo_attach */
247*0Sstevel@tonic-gate 	crypto_detach,		/* devo_detach */
248*0Sstevel@tonic-gate 	nodev,			/* devo_reset */
249*0Sstevel@tonic-gate 	&cbops,			/* devo_cb_ops */
250*0Sstevel@tonic-gate 	NULL,			/* devo_bus_ops */
251*0Sstevel@tonic-gate 	NULL,			/* devo_power */
252*0Sstevel@tonic-gate };
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate static struct modldrv modldrv = {
255*0Sstevel@tonic-gate 	&mod_driverops,					/* drv_modops */
256*0Sstevel@tonic-gate 	"Cryptographic Library Interface v%I%",	/* drv_linkinfo */
257*0Sstevel@tonic-gate 	&devops,
258*0Sstevel@tonic-gate };
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
261*0Sstevel@tonic-gate 	MODREV_1,		/* ml_rev */
262*0Sstevel@tonic-gate 	&modldrv,		/* ml_linkage */
263*0Sstevel@tonic-gate 	NULL
264*0Sstevel@tonic-gate };
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate /*
267*0Sstevel@tonic-gate  * DDI entry points.
268*0Sstevel@tonic-gate  */
269*0Sstevel@tonic-gate int
270*0Sstevel@tonic-gate _init(void)
271*0Sstevel@tonic-gate {
272*0Sstevel@tonic-gate 	return (mod_install(&modlinkage));
273*0Sstevel@tonic-gate }
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate int
276*0Sstevel@tonic-gate _fini(void)
277*0Sstevel@tonic-gate {
278*0Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
279*0Sstevel@tonic-gate }
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate int
282*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
283*0Sstevel@tonic-gate {
284*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
285*0Sstevel@tonic-gate }
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate /* ARGSUSED */
288*0Sstevel@tonic-gate static int
289*0Sstevel@tonic-gate crypto_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
290*0Sstevel@tonic-gate {
291*0Sstevel@tonic-gate 	switch (cmd) {
292*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
293*0Sstevel@tonic-gate 		*result = crypto_dip;
294*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
297*0Sstevel@tonic-gate 		*result = (void *)0;
298*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
299*0Sstevel@tonic-gate 	}
300*0Sstevel@tonic-gate 	return (DDI_FAILURE);
301*0Sstevel@tonic-gate }
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate static int
304*0Sstevel@tonic-gate crypto_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
305*0Sstevel@tonic-gate {
306*0Sstevel@tonic-gate 	if (cmd != DDI_ATTACH) {
307*0Sstevel@tonic-gate 		return (DDI_FAILURE);
308*0Sstevel@tonic-gate 	}
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 	if (ddi_get_instance(dip) != 0) {
311*0Sstevel@tonic-gate 		/* we only allow instance 0 to attach */
312*0Sstevel@tonic-gate 		return (DDI_FAILURE);
313*0Sstevel@tonic-gate 	}
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 	crypto_session_cache = kmem_cache_create("crypto_session_cache",
316*0Sstevel@tonic-gate 	    sizeof (crypto_session_data_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 	if (crypto_session_cache == NULL)
319*0Sstevel@tonic-gate 		return (DDI_FAILURE);
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	/* create the minor node */
322*0Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, "crypto", S_IFCHR, 0,
323*0Sstevel@tonic-gate 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
324*0Sstevel@tonic-gate 		kmem_cache_destroy(crypto_session_cache);
325*0Sstevel@tonic-gate 		crypto_session_cache = NULL;
326*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "crypto_attach: failed creating minor node");
327*0Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
328*0Sstevel@tonic-gate 		return (DDI_FAILURE);
329*0Sstevel@tonic-gate 	}
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 	mutex_init(&crypto_lock, NULL, MUTEX_DRIVER, NULL);
332*0Sstevel@tonic-gate 	mutex_init(&crypto_rctl_lock, NULL, MUTEX_DRIVER, NULL);
333*0Sstevel@tonic-gate 	cv_init(&crypto_cv, NULL, CV_DRIVER, NULL);
334*0Sstevel@tonic-gate 	crypto_dip = dip;
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	/* allocate integer space for minor numbers */
337*0Sstevel@tonic-gate 	crypto_arena = vmem_create("crypto", (void *)1,
338*0Sstevel@tonic-gate 	    CRYPTO_MINOR_CHUNK, 1, NULL, NULL, NULL, 0,
339*0Sstevel@tonic-gate 	    VM_SLEEP | VMC_IDENTIFIER);
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
342*0Sstevel@tonic-gate }
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate static int
345*0Sstevel@tonic-gate crypto_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
346*0Sstevel@tonic-gate {
347*0Sstevel@tonic-gate 	minor_t i;
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	if (cmd != DDI_DETACH)
350*0Sstevel@tonic-gate 		return (DDI_FAILURE);
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 	/* check if device is open */
353*0Sstevel@tonic-gate 	mutex_enter(&crypto_lock);
354*0Sstevel@tonic-gate 	for (i = 0; i < crypto_minors_table_count; i++) {
355*0Sstevel@tonic-gate 		if (crypto_minors[i] != NULL) {
356*0Sstevel@tonic-gate 			mutex_exit(&crypto_lock);
357*0Sstevel@tonic-gate 			return (DDI_FAILURE);
358*0Sstevel@tonic-gate 		}
359*0Sstevel@tonic-gate 	}
360*0Sstevel@tonic-gate 	mutex_exit(&crypto_lock);
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	crypto_dip = NULL;
363*0Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 	kmem_cache_destroy(crypto_session_cache);
366*0Sstevel@tonic-gate 	crypto_session_cache = NULL;
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	kmem_free(crypto_minors,
369*0Sstevel@tonic-gate 	    sizeof (crypto_minor_t *) * crypto_minors_table_count);
370*0Sstevel@tonic-gate 	crypto_minors = NULL;
371*0Sstevel@tonic-gate 	crypto_minors_table_count = 0;
372*0Sstevel@tonic-gate 	mutex_destroy(&crypto_lock);
373*0Sstevel@tonic-gate 	mutex_destroy(&crypto_rctl_lock);
374*0Sstevel@tonic-gate 	cv_destroy(&crypto_cv);
375*0Sstevel@tonic-gate 	vmem_destroy(crypto_arena);
376*0Sstevel@tonic-gate 	crypto_arena = NULL;
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
379*0Sstevel@tonic-gate }
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate /* ARGSUSED */
382*0Sstevel@tonic-gate static int
383*0Sstevel@tonic-gate crypto_open(dev_t *devp, int flag, int otyp, cred_t *credp)
384*0Sstevel@tonic-gate {
385*0Sstevel@tonic-gate 	crypto_minor_t *cm = NULL;
386*0Sstevel@tonic-gate 	minor_t mn;
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
389*0Sstevel@tonic-gate 		return (ENXIO);
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 	if (crypto_dip == NULL)
392*0Sstevel@tonic-gate 		return (ENXIO);
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	/* exclusive opens are not supported */
395*0Sstevel@tonic-gate 	if (flag & FEXCL)
396*0Sstevel@tonic-gate 		return (ENOTSUP);
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 	mutex_enter(&crypto_lock);
399*0Sstevel@tonic-gate again:
400*0Sstevel@tonic-gate 	/* grow the minors table if needed */
401*0Sstevel@tonic-gate 	if (crypto_minors_count >= crypto_minors_table_count) {
402*0Sstevel@tonic-gate 		crypto_minor_t **newtable;
403*0Sstevel@tonic-gate 		minor_t chunk = crypto_minor_chunk;
404*0Sstevel@tonic-gate 		minor_t saved_count;
405*0Sstevel@tonic-gate 		size_t new_size;
406*0Sstevel@tonic-gate 		ulong_t big_count;
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 		big_count = crypto_minors_count + chunk;
409*0Sstevel@tonic-gate 		if (big_count > MAXMIN) {
410*0Sstevel@tonic-gate 			mutex_exit(&crypto_lock);
411*0Sstevel@tonic-gate 			return (ENOMEM);
412*0Sstevel@tonic-gate 		}
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 		saved_count = crypto_minors_table_count;
415*0Sstevel@tonic-gate 		new_size = sizeof (crypto_minor_t *) *
416*0Sstevel@tonic-gate 		    (crypto_minors_table_count + chunk);
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 		mutex_exit(&crypto_lock);
419*0Sstevel@tonic-gate 		newtable = kmem_zalloc(new_size, KM_SLEEP);
420*0Sstevel@tonic-gate 		mutex_enter(&crypto_lock);
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 		/*
423*0Sstevel@tonic-gate 		 * Check if table grew while we were sleeping.
424*0Sstevel@tonic-gate 		 * The minors table never shrinks.
425*0Sstevel@tonic-gate 		 */
426*0Sstevel@tonic-gate 		if (crypto_minors_table_count > saved_count) {
427*0Sstevel@tonic-gate 			kmem_free(newtable, new_size);
428*0Sstevel@tonic-gate 			goto again;
429*0Sstevel@tonic-gate 		}
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 		/* we assume that bcopy() will return if count is 0 */
432*0Sstevel@tonic-gate 		bcopy(crypto_minors, newtable,
433*0Sstevel@tonic-gate 		    sizeof (crypto_minor_t *) * crypto_minors_table_count);
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 		kmem_free(crypto_minors,
436*0Sstevel@tonic-gate 		    sizeof (crypto_minor_t *) * crypto_minors_table_count);
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate 		/* grow the minors number space */
439*0Sstevel@tonic-gate 		if (crypto_minors_table_count != 0) {
440*0Sstevel@tonic-gate 			(void) vmem_add(crypto_arena,
441*0Sstevel@tonic-gate 			    (void *)(uintptr_t)(crypto_minors_table_count + 1),
442*0Sstevel@tonic-gate 			    crypto_minor_chunk, VM_SLEEP);
443*0Sstevel@tonic-gate 		}
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 		crypto_minors = newtable;
446*0Sstevel@tonic-gate 		crypto_minors_table_count += chunk;
447*0Sstevel@tonic-gate 	}
448*0Sstevel@tonic-gate 	mutex_exit(&crypto_lock);
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	/* allocate a new minor number starting with 1 */
451*0Sstevel@tonic-gate 	mn = (minor_t)(uintptr_t)vmem_alloc(crypto_arena, 1, VM_SLEEP);
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 	cm = kmem_zalloc(sizeof (crypto_minor_t), KM_SLEEP);
454*0Sstevel@tonic-gate 	mutex_init(&cm->cm_lock, NULL, MUTEX_DRIVER, NULL);
455*0Sstevel@tonic-gate 	cv_init(&cm->cm_cv, NULL, CV_DRIVER, NULL);
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 	mutex_enter(&crypto_lock);
458*0Sstevel@tonic-gate 	crypto_minors[mn - 1] = cm;
459*0Sstevel@tonic-gate 	crypto_minors_count++;
460*0Sstevel@tonic-gate 	mutex_exit(&crypto_lock);
461*0Sstevel@tonic-gate 
462*0Sstevel@tonic-gate 	*devp = makedevice(getmajor(*devp), mn);
463*0Sstevel@tonic-gate 
464*0Sstevel@tonic-gate 	return (0);
465*0Sstevel@tonic-gate }
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate /* ARGSUSED */
468*0Sstevel@tonic-gate static int
469*0Sstevel@tonic-gate crypto_close(dev_t dev, int flag, int otyp, cred_t *credp)
470*0Sstevel@tonic-gate {
471*0Sstevel@tonic-gate 	crypto_minor_t *cm = NULL;
472*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
473*0Sstevel@tonic-gate 	minor_t mn = getminor(dev);
474*0Sstevel@tonic-gate 	uint_t i;
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 	mutex_enter(&crypto_lock);
477*0Sstevel@tonic-gate 	if (mn > crypto_minors_table_count) {
478*0Sstevel@tonic-gate 		mutex_exit(&crypto_lock);
479*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "crypto_close: bad minor (too big) %d", mn);
480*0Sstevel@tonic-gate 		return (ENODEV);
481*0Sstevel@tonic-gate 	}
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 	while (((cm = crypto_minors[mn - 1]) != NULL) && (cm->cm_refcnt > 0)) {
484*0Sstevel@tonic-gate 		cv_wait(&crypto_cv, &crypto_lock);
485*0Sstevel@tonic-gate 	}
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 	if (cm == NULL) {
488*0Sstevel@tonic-gate 		mutex_exit(&crypto_lock);
489*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "crypto_close: duplicate close of minor %d",
490*0Sstevel@tonic-gate 		    getminor(dev));
491*0Sstevel@tonic-gate 		return (ENODEV);
492*0Sstevel@tonic-gate 	}
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 	/* take it out of the global table */
495*0Sstevel@tonic-gate 	crypto_minors[mn - 1] = NULL;
496*0Sstevel@tonic-gate 	crypto_minors_count--;
497*0Sstevel@tonic-gate 
498*0Sstevel@tonic-gate 	vmem_free(crypto_arena, (void *)(uintptr_t)mn, 1);
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 	mutex_enter(&cm->cm_lock);
501*0Sstevel@tonic-gate 	mutex_exit(&crypto_lock);
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 	/* free all session table entries starting with 1 */
504*0Sstevel@tonic-gate 	for (i = 1; i < cm->cm_session_table_count; i++) {
505*0Sstevel@tonic-gate 		if (cm->cm_session_table[i] == NULL)
506*0Sstevel@tonic-gate 			continue;
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate 		sp = cm->cm_session_table[i];
509*0Sstevel@tonic-gate 		ASSERT((sp->sd_flags & CRYPTO_SESSION_IS_BUSY) == 0);
510*0Sstevel@tonic-gate 		if (sp->sd_find_init_cookie != NULL) {
511*0Sstevel@tonic-gate 			(void) crypto_free_find_ctx(sp);
512*0Sstevel@tonic-gate 		}
513*0Sstevel@tonic-gate 		crypto_release_provider_session(cm, sp->sd_provider_session);
514*0Sstevel@tonic-gate 		KCF_PROV_REFRELE(sp->sd_provider);
515*0Sstevel@tonic-gate 		CRYPTO_CANCEL_ALL_CTX(sp);
516*0Sstevel@tonic-gate 		mutex_destroy(&sp->sd_lock);
517*0Sstevel@tonic-gate 		cv_destroy(&sp->sd_cv);
518*0Sstevel@tonic-gate 		kmem_cache_free(crypto_session_cache, sp);
519*0Sstevel@tonic-gate 		cm->cm_session_table[i] = NULL;
520*0Sstevel@tonic-gate 	}
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 	/* free the session table */
523*0Sstevel@tonic-gate 	if (cm->cm_session_table != NULL && cm->cm_session_table_count > 0)
524*0Sstevel@tonic-gate 		kmem_free(cm->cm_session_table, cm->cm_session_table_count *
525*0Sstevel@tonic-gate 		    sizeof (void *));
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 	if (cm->cm_session_table_count != 0) {
528*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
529*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(cm->cm_session_table_count *
530*0Sstevel@tonic-gate 		    sizeof (void *), cm->cm_projp);
531*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
532*0Sstevel@tonic-gate 	}
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	kcf_free_provider_tab(cm->cm_provider_count,
535*0Sstevel@tonic-gate 	    cm->cm_provider_array);
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 	mutex_destroy(&cm->cm_lock);
538*0Sstevel@tonic-gate 	cv_destroy(&cm->cm_cv);
539*0Sstevel@tonic-gate 	kmem_free(cm, sizeof (crypto_minor_t));
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate 	return (0);
542*0Sstevel@tonic-gate }
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate static crypto_minor_t *
545*0Sstevel@tonic-gate crypto_hold_minor(minor_t minor)
546*0Sstevel@tonic-gate {
547*0Sstevel@tonic-gate 	crypto_minor_t *cm = NULL;
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate 	mutex_enter(&crypto_lock);
550*0Sstevel@tonic-gate 	if ((minor <= crypto_minors_table_count) &&
551*0Sstevel@tonic-gate 	    ((cm = crypto_minors[minor - 1]) != NULL)) {
552*0Sstevel@tonic-gate 		cm->cm_refcnt++;
553*0Sstevel@tonic-gate 	}
554*0Sstevel@tonic-gate 	mutex_exit(&crypto_lock);
555*0Sstevel@tonic-gate 	return (cm);
556*0Sstevel@tonic-gate }
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate static void
559*0Sstevel@tonic-gate crypto_release_minor(crypto_minor_t *cm)
560*0Sstevel@tonic-gate {
561*0Sstevel@tonic-gate 	mutex_enter(&crypto_lock);
562*0Sstevel@tonic-gate 	cm->cm_refcnt--;
563*0Sstevel@tonic-gate 	if (cm->cm_refcnt == 0) {
564*0Sstevel@tonic-gate 		cv_broadcast(&crypto_cv);
565*0Sstevel@tonic-gate 	}
566*0Sstevel@tonic-gate 	mutex_exit(&crypto_lock);
567*0Sstevel@tonic-gate }
568*0Sstevel@tonic-gate 
569*0Sstevel@tonic-gate /*
570*0Sstevel@tonic-gate  *
571*0Sstevel@tonic-gate  */
572*0Sstevel@tonic-gate static void
573*0Sstevel@tonic-gate crypto_build_function_list(crypto_function_list_t *fl, kcf_provider_desc_t *pd)
574*0Sstevel@tonic-gate {
575*0Sstevel@tonic-gate 	crypto_ops_t *ops;
576*0Sstevel@tonic-gate 	crypto_digest_ops_t *digest_ops;
577*0Sstevel@tonic-gate 	crypto_cipher_ops_t *cipher_ops;
578*0Sstevel@tonic-gate 	crypto_mac_ops_t *mac_ops;
579*0Sstevel@tonic-gate 	crypto_sign_ops_t *sign_ops;
580*0Sstevel@tonic-gate 	crypto_verify_ops_t *verify_ops;
581*0Sstevel@tonic-gate 	crypto_dual_ops_t *dual_ops;
582*0Sstevel@tonic-gate 	crypto_random_number_ops_t *random_number_ops;
583*0Sstevel@tonic-gate 	crypto_session_ops_t *session_ops;
584*0Sstevel@tonic-gate 	crypto_object_ops_t *object_ops;
585*0Sstevel@tonic-gate 	crypto_key_ops_t *key_ops;
586*0Sstevel@tonic-gate 	crypto_provider_management_ops_t *provider_ops;
587*0Sstevel@tonic-gate 
588*0Sstevel@tonic-gate 	if ((ops = pd->pd_ops_vector) == NULL)
589*0Sstevel@tonic-gate 		return;
590*0Sstevel@tonic-gate 
591*0Sstevel@tonic-gate 	if ((digest_ops = ops->digest_ops) != NULL) {
592*0Sstevel@tonic-gate 		if (digest_ops->digest_init != NULL)
593*0Sstevel@tonic-gate 			fl->fl_digest_init = B_TRUE;
594*0Sstevel@tonic-gate 		if (digest_ops->digest != NULL)
595*0Sstevel@tonic-gate 			fl->fl_digest = B_TRUE;
596*0Sstevel@tonic-gate 		if (digest_ops->digest_update != NULL)
597*0Sstevel@tonic-gate 			fl->fl_digest_update = B_TRUE;
598*0Sstevel@tonic-gate 		if (digest_ops->digest_key != NULL)
599*0Sstevel@tonic-gate 			fl->fl_digest_key = B_TRUE;
600*0Sstevel@tonic-gate 		if (digest_ops->digest_final != NULL)
601*0Sstevel@tonic-gate 			fl->fl_digest_final = B_TRUE;
602*0Sstevel@tonic-gate 	}
603*0Sstevel@tonic-gate 	if ((cipher_ops = ops->cipher_ops) != NULL) {
604*0Sstevel@tonic-gate 		if (cipher_ops->encrypt_init != NULL)
605*0Sstevel@tonic-gate 			fl->fl_encrypt_init = B_TRUE;
606*0Sstevel@tonic-gate 		if (cipher_ops->encrypt != NULL)
607*0Sstevel@tonic-gate 			fl->fl_encrypt = B_TRUE;
608*0Sstevel@tonic-gate 		if (cipher_ops->encrypt_update != NULL)
609*0Sstevel@tonic-gate 			fl->fl_encrypt_update = B_TRUE;
610*0Sstevel@tonic-gate 		if (cipher_ops->encrypt_final != NULL)
611*0Sstevel@tonic-gate 			fl->fl_encrypt_final = B_TRUE;
612*0Sstevel@tonic-gate 		if (cipher_ops->decrypt_init != NULL)
613*0Sstevel@tonic-gate 			fl->fl_decrypt_init = B_TRUE;
614*0Sstevel@tonic-gate 		if (cipher_ops->decrypt != NULL)
615*0Sstevel@tonic-gate 			fl->fl_decrypt = B_TRUE;
616*0Sstevel@tonic-gate 		if (cipher_ops->decrypt_update != NULL)
617*0Sstevel@tonic-gate 			fl->fl_decrypt_update = B_TRUE;
618*0Sstevel@tonic-gate 		if (cipher_ops->decrypt_final != NULL)
619*0Sstevel@tonic-gate 			fl->fl_decrypt_final = B_TRUE;
620*0Sstevel@tonic-gate 	}
621*0Sstevel@tonic-gate 	if ((mac_ops = ops->mac_ops) != NULL) {
622*0Sstevel@tonic-gate 		if (mac_ops->mac_init != NULL)
623*0Sstevel@tonic-gate 			fl->fl_mac_init = B_TRUE;
624*0Sstevel@tonic-gate 		if (mac_ops->mac != NULL)
625*0Sstevel@tonic-gate 			fl->fl_mac = B_TRUE;
626*0Sstevel@tonic-gate 		if (mac_ops->mac_update != NULL)
627*0Sstevel@tonic-gate 			fl->fl_mac_update = B_TRUE;
628*0Sstevel@tonic-gate 		if (mac_ops->mac_final != NULL)
629*0Sstevel@tonic-gate 			fl->fl_mac_final = B_TRUE;
630*0Sstevel@tonic-gate 	}
631*0Sstevel@tonic-gate 	if ((sign_ops = ops->sign_ops) != NULL) {
632*0Sstevel@tonic-gate 		if (sign_ops->sign_init != NULL)
633*0Sstevel@tonic-gate 			fl->fl_sign_init = B_TRUE;
634*0Sstevel@tonic-gate 		if (sign_ops->sign != NULL)
635*0Sstevel@tonic-gate 			fl->fl_sign = B_TRUE;
636*0Sstevel@tonic-gate 		if (sign_ops->sign_update != NULL)
637*0Sstevel@tonic-gate 			fl->fl_sign_update = B_TRUE;
638*0Sstevel@tonic-gate 		if (sign_ops->sign_final != NULL)
639*0Sstevel@tonic-gate 			fl->fl_sign_final = B_TRUE;
640*0Sstevel@tonic-gate 		if (sign_ops->sign_recover_init != NULL)
641*0Sstevel@tonic-gate 			fl->fl_sign_recover_init = B_TRUE;
642*0Sstevel@tonic-gate 		if (sign_ops->sign_recover != NULL)
643*0Sstevel@tonic-gate 			fl->fl_sign_recover = B_TRUE;
644*0Sstevel@tonic-gate 	}
645*0Sstevel@tonic-gate 	if ((verify_ops = ops->verify_ops) != NULL) {
646*0Sstevel@tonic-gate 		if (verify_ops->verify_init != NULL)
647*0Sstevel@tonic-gate 			fl->fl_verify_init = B_TRUE;
648*0Sstevel@tonic-gate 		if (verify_ops->verify != NULL)
649*0Sstevel@tonic-gate 			fl->fl_verify = B_TRUE;
650*0Sstevel@tonic-gate 		if (verify_ops->verify_update != NULL)
651*0Sstevel@tonic-gate 			fl->fl_verify_update = B_TRUE;
652*0Sstevel@tonic-gate 		if (verify_ops->verify_final != NULL)
653*0Sstevel@tonic-gate 			fl->fl_verify_final = B_TRUE;
654*0Sstevel@tonic-gate 		if (verify_ops->verify_recover_init != NULL)
655*0Sstevel@tonic-gate 			fl->fl_verify_recover_init = B_TRUE;
656*0Sstevel@tonic-gate 		if (verify_ops->verify_recover != NULL)
657*0Sstevel@tonic-gate 			fl->fl_verify_recover = B_TRUE;
658*0Sstevel@tonic-gate 	}
659*0Sstevel@tonic-gate 	if ((dual_ops = ops->dual_ops) != NULL) {
660*0Sstevel@tonic-gate 		if (dual_ops->digest_encrypt_update != NULL)
661*0Sstevel@tonic-gate 			fl->fl_digest_encrypt_update = B_TRUE;
662*0Sstevel@tonic-gate 		if (dual_ops->decrypt_digest_update != NULL)
663*0Sstevel@tonic-gate 			fl->fl_decrypt_digest_update = B_TRUE;
664*0Sstevel@tonic-gate 		if (dual_ops->sign_encrypt_update != NULL)
665*0Sstevel@tonic-gate 			fl->fl_sign_encrypt_update = B_TRUE;
666*0Sstevel@tonic-gate 		if (dual_ops->decrypt_verify_update != NULL)
667*0Sstevel@tonic-gate 			fl->fl_decrypt_verify_update = B_TRUE;
668*0Sstevel@tonic-gate 	}
669*0Sstevel@tonic-gate 	if ((random_number_ops = ops->random_ops) != NULL) {
670*0Sstevel@tonic-gate 		if (random_number_ops->seed_random != NULL)
671*0Sstevel@tonic-gate 			fl->fl_seed_random = B_TRUE;
672*0Sstevel@tonic-gate 		if (random_number_ops->generate_random != NULL)
673*0Sstevel@tonic-gate 			fl->fl_generate_random = B_TRUE;
674*0Sstevel@tonic-gate 	}
675*0Sstevel@tonic-gate 	if ((session_ops = ops->session_ops) != NULL) {
676*0Sstevel@tonic-gate 		if (session_ops->session_open != NULL)
677*0Sstevel@tonic-gate 			fl->fl_session_open = B_TRUE;
678*0Sstevel@tonic-gate 		if (session_ops->session_close != NULL)
679*0Sstevel@tonic-gate 			fl->fl_session_close = B_TRUE;
680*0Sstevel@tonic-gate 		if (session_ops->session_login != NULL)
681*0Sstevel@tonic-gate 			fl->fl_session_login = B_TRUE;
682*0Sstevel@tonic-gate 		if (session_ops->session_logout != NULL)
683*0Sstevel@tonic-gate 			fl->fl_session_logout = B_TRUE;
684*0Sstevel@tonic-gate 	}
685*0Sstevel@tonic-gate 	if ((object_ops = ops->object_ops) != NULL) {
686*0Sstevel@tonic-gate 		if (object_ops->object_create != NULL)
687*0Sstevel@tonic-gate 			fl->fl_object_create = B_TRUE;
688*0Sstevel@tonic-gate 		if (object_ops->object_copy != NULL)
689*0Sstevel@tonic-gate 			fl->fl_object_copy = B_TRUE;
690*0Sstevel@tonic-gate 		if (object_ops->object_destroy != NULL)
691*0Sstevel@tonic-gate 			fl->fl_object_destroy = B_TRUE;
692*0Sstevel@tonic-gate 		if (object_ops->object_get_size != NULL)
693*0Sstevel@tonic-gate 			fl->fl_object_get_size = B_TRUE;
694*0Sstevel@tonic-gate 		if (object_ops->object_get_attribute_value != NULL)
695*0Sstevel@tonic-gate 			fl->fl_object_get_attribute_value = B_TRUE;
696*0Sstevel@tonic-gate 		if (object_ops->object_set_attribute_value != NULL)
697*0Sstevel@tonic-gate 			fl->fl_object_set_attribute_value = B_TRUE;
698*0Sstevel@tonic-gate 		if (object_ops->object_find_init != NULL)
699*0Sstevel@tonic-gate 			fl->fl_object_find_init = B_TRUE;
700*0Sstevel@tonic-gate 		if (object_ops->object_find != NULL)
701*0Sstevel@tonic-gate 			fl->fl_object_find = B_TRUE;
702*0Sstevel@tonic-gate 		if (object_ops->object_find_final != NULL)
703*0Sstevel@tonic-gate 			fl->fl_object_find_final = B_TRUE;
704*0Sstevel@tonic-gate 	}
705*0Sstevel@tonic-gate 	if ((key_ops = ops->key_ops) != NULL) {
706*0Sstevel@tonic-gate 		if (key_ops->key_generate != NULL)
707*0Sstevel@tonic-gate 			fl->fl_key_generate = B_TRUE;
708*0Sstevel@tonic-gate 		if (key_ops->key_generate_pair != NULL)
709*0Sstevel@tonic-gate 			fl->fl_key_generate_pair = B_TRUE;
710*0Sstevel@tonic-gate 		if (key_ops->key_wrap != NULL)
711*0Sstevel@tonic-gate 			fl->fl_key_wrap = B_TRUE;
712*0Sstevel@tonic-gate 		if (key_ops->key_unwrap != NULL)
713*0Sstevel@tonic-gate 			fl->fl_key_unwrap = B_TRUE;
714*0Sstevel@tonic-gate 		if (key_ops->key_derive != NULL)
715*0Sstevel@tonic-gate 			fl->fl_key_derive = B_TRUE;
716*0Sstevel@tonic-gate 	}
717*0Sstevel@tonic-gate 	if ((provider_ops = ops->provider_ops) != NULL) {
718*0Sstevel@tonic-gate 		if (provider_ops->init_token != NULL)
719*0Sstevel@tonic-gate 			fl->fl_init_token = B_TRUE;
720*0Sstevel@tonic-gate 		if (provider_ops->init_pin != NULL)
721*0Sstevel@tonic-gate 			fl->fl_init_pin = B_TRUE;
722*0Sstevel@tonic-gate 		if (provider_ops->set_pin != NULL)
723*0Sstevel@tonic-gate 			fl->fl_set_pin = B_TRUE;
724*0Sstevel@tonic-gate 	}
725*0Sstevel@tonic-gate }
726*0Sstevel@tonic-gate 
727*0Sstevel@tonic-gate /* ARGSUSED */
728*0Sstevel@tonic-gate static int
729*0Sstevel@tonic-gate get_function_list(dev_t dev, caddr_t arg, int mode, int *rval)
730*0Sstevel@tonic-gate {
731*0Sstevel@tonic-gate 	crypto_get_function_list_t get_function_list;
732*0Sstevel@tonic-gate 	crypto_minor_t *cm;
733*0Sstevel@tonic-gate 	crypto_provider_id_t provider_id;
734*0Sstevel@tonic-gate 	crypto_function_list_t *fl;
735*0Sstevel@tonic-gate 	kcf_provider_desc_t *provider;
736*0Sstevel@tonic-gate 	int rv;
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
739*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "get_function_list: failed holding minor");
740*0Sstevel@tonic-gate 		return (ENXIO);
741*0Sstevel@tonic-gate 	}
742*0Sstevel@tonic-gate 
743*0Sstevel@tonic-gate 	if (copyin(arg, &get_function_list, sizeof (get_function_list)) != 0) {
744*0Sstevel@tonic-gate 		crypto_release_minor(cm);
745*0Sstevel@tonic-gate 		return (EFAULT);
746*0Sstevel@tonic-gate 	}
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate 	/* initialize provider_array */
749*0Sstevel@tonic-gate 	if (cm->cm_provider_array == NULL) {
750*0Sstevel@tonic-gate 		rv = crypto_get_provider_list(cm, NULL, NULL, DONT_RETURN_LIST);
751*0Sstevel@tonic-gate 		if (rv != CRYPTO_SUCCESS) {
752*0Sstevel@tonic-gate 			goto release_minor;
753*0Sstevel@tonic-gate 		}
754*0Sstevel@tonic-gate 	}
755*0Sstevel@tonic-gate 
756*0Sstevel@tonic-gate 	provider_id = get_function_list.fl_provider_id;
757*0Sstevel@tonic-gate 	mutex_enter(&cm->cm_lock);
758*0Sstevel@tonic-gate 	/* index must be less than count of providers */
759*0Sstevel@tonic-gate 	if (provider_id >= cm->cm_provider_count) {
760*0Sstevel@tonic-gate 		mutex_exit(&cm->cm_lock);
761*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
762*0Sstevel@tonic-gate 		goto release_minor;
763*0Sstevel@tonic-gate 	}
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 	ASSERT(cm->cm_provider_array != NULL);
766*0Sstevel@tonic-gate 	provider = cm->cm_provider_array[provider_id];
767*0Sstevel@tonic-gate 	mutex_exit(&cm->cm_lock);
768*0Sstevel@tonic-gate 
769*0Sstevel@tonic-gate 	fl = &get_function_list.fl_list;
770*0Sstevel@tonic-gate 	bzero(fl, sizeof (crypto_function_list_t));
771*0Sstevel@tonic-gate 
772*0Sstevel@tonic-gate 	if (provider->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
773*0Sstevel@tonic-gate 		crypto_build_function_list(fl, provider);
774*0Sstevel@tonic-gate 	} else {
775*0Sstevel@tonic-gate 		kcf_provider_desc_t *prev = NULL, *pd;
776*0Sstevel@tonic-gate 
777*0Sstevel@tonic-gate 		mutex_enter(&provider->pd_lock);
778*0Sstevel@tonic-gate 		while (kcf_get_next_logical_provider_member(provider,
779*0Sstevel@tonic-gate 		    prev, &pd)) {
780*0Sstevel@tonic-gate 			prev = pd;
781*0Sstevel@tonic-gate 			crypto_build_function_list(fl, pd);
782*0Sstevel@tonic-gate 			KCF_PROV_REFRELE(pd);
783*0Sstevel@tonic-gate 		}
784*0Sstevel@tonic-gate 		mutex_exit(&provider->pd_lock);
785*0Sstevel@tonic-gate 	}
786*0Sstevel@tonic-gate 
787*0Sstevel@tonic-gate 	rv = CRYPTO_SUCCESS;
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate release_minor:
790*0Sstevel@tonic-gate 	crypto_release_minor(cm);
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate 	get_function_list.fl_return_value = rv;
793*0Sstevel@tonic-gate 
794*0Sstevel@tonic-gate 	if (copyout(&get_function_list, arg, sizeof (get_function_list)) != 0) {
795*0Sstevel@tonic-gate 		return (EFAULT);
796*0Sstevel@tonic-gate 	}
797*0Sstevel@tonic-gate 	return (0);
798*0Sstevel@tonic-gate }
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate /*
801*0Sstevel@tonic-gate  * This ioctl maps a PKCS#11 mechanism string into an internal number
802*0Sstevel@tonic-gate  * that is used by the kernel.  pn_internal_number is set to the
803*0Sstevel@tonic-gate  * internal number.
804*0Sstevel@tonic-gate  */
805*0Sstevel@tonic-gate /* ARGSUSED */
806*0Sstevel@tonic-gate static int
807*0Sstevel@tonic-gate get_mechanism_number(dev_t dev, caddr_t arg, int mode, int *rval)
808*0Sstevel@tonic-gate {
809*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_get_mechanism_number, get_number);
810*0Sstevel@tonic-gate 	crypto_mech_type_t number;
811*0Sstevel@tonic-gate 	size_t len;
812*0Sstevel@tonic-gate 	char *mechanism_name;
813*0Sstevel@tonic-gate 	int rv;
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate 	STRUCT_INIT(get_number, mode);
816*0Sstevel@tonic-gate 
817*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(get_number), STRUCT_SIZE(get_number)) != 0)
818*0Sstevel@tonic-gate 		return (EFAULT);
819*0Sstevel@tonic-gate 
820*0Sstevel@tonic-gate 	len = STRUCT_FGET(get_number, pn_mechanism_len);
821*0Sstevel@tonic-gate 	if (len == 0 || len > CRYPTO_MAX_MECH_NAME) {
822*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
823*0Sstevel@tonic-gate 		goto out;
824*0Sstevel@tonic-gate 	}
825*0Sstevel@tonic-gate 	mechanism_name = kmem_alloc(len, KM_SLEEP);
826*0Sstevel@tonic-gate 
827*0Sstevel@tonic-gate 	if (copyin(STRUCT_FGETP(get_number, pn_mechanism_string),
828*0Sstevel@tonic-gate 	    mechanism_name, len) != 0) {
829*0Sstevel@tonic-gate 		kmem_free(mechanism_name, len);
830*0Sstevel@tonic-gate 		return (EFAULT);
831*0Sstevel@tonic-gate 	}
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate 	/* get mechanism number from the core module */
834*0Sstevel@tonic-gate 	number = crypto_mech2id_common(mechanism_name, B_TRUE);
835*0Sstevel@tonic-gate 	kmem_free(mechanism_name, len);
836*0Sstevel@tonic-gate 	if (number == CRYPTO_MECH_INVALID) {
837*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
838*0Sstevel@tonic-gate 		goto out;
839*0Sstevel@tonic-gate 	}
840*0Sstevel@tonic-gate 
841*0Sstevel@tonic-gate 	bcopy((char *)&number, (char *)STRUCT_FADDR(get_number,
842*0Sstevel@tonic-gate 	    pn_internal_number), sizeof (number));
843*0Sstevel@tonic-gate 
844*0Sstevel@tonic-gate 	rv = CRYPTO_SUCCESS;
845*0Sstevel@tonic-gate out:
846*0Sstevel@tonic-gate 	STRUCT_FSET(get_number, pn_return_value, rv);
847*0Sstevel@tonic-gate 
848*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(get_number), arg,
849*0Sstevel@tonic-gate 	    STRUCT_SIZE(get_number)) != 0) {
850*0Sstevel@tonic-gate 		return (EFAULT);
851*0Sstevel@tonic-gate 	}
852*0Sstevel@tonic-gate 	return (0);
853*0Sstevel@tonic-gate }
854*0Sstevel@tonic-gate 
855*0Sstevel@tonic-gate /*
856*0Sstevel@tonic-gate  * Side-effects:
857*0Sstevel@tonic-gate  *  1. This routine stores provider descriptor pointers in an array
858*0Sstevel@tonic-gate  *     and increments each descriptor's reference count.  The array
859*0Sstevel@tonic-gate  *     is stored in per-minor number storage.
860*0Sstevel@tonic-gate  *  2. Destroys the old array and creates a new one every time
861*0Sstevel@tonic-gate  *     this routine is called.
862*0Sstevel@tonic-gate  */
863*0Sstevel@tonic-gate int
864*0Sstevel@tonic-gate crypto_get_provider_list(crypto_minor_t *cm, uint_t *count,
865*0Sstevel@tonic-gate     crypto_provider_entry_t **array, boolean_t return_slot_list)
866*0Sstevel@tonic-gate {
867*0Sstevel@tonic-gate 	kcf_provider_desc_t **provider_array;
868*0Sstevel@tonic-gate 	crypto_provider_entry_t *p = NULL;
869*0Sstevel@tonic-gate 	uint_t provider_count;
870*0Sstevel@tonic-gate 	int rval;
871*0Sstevel@tonic-gate 	int i;
872*0Sstevel@tonic-gate 
873*0Sstevel@tonic-gate 	/*
874*0Sstevel@tonic-gate 	 * Take snapshot of provider table returning only HW entries
875*0Sstevel@tonic-gate 	 * that are in a usable state. Also returns logical provider entries.
876*0Sstevel@tonic-gate 	 */
877*0Sstevel@tonic-gate 	rval =  kcf_get_slot_list(&provider_count, &provider_array, B_FALSE);
878*0Sstevel@tonic-gate 	if (rval != CRYPTO_SUCCESS)
879*0Sstevel@tonic-gate 		return (rval);
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 	/* allocate memory before taking cm->cm_lock */
882*0Sstevel@tonic-gate 	if (return_slot_list) {
883*0Sstevel@tonic-gate 		if (provider_count != 0) {
884*0Sstevel@tonic-gate 			p = kmem_alloc(provider_count *
885*0Sstevel@tonic-gate 			    sizeof (crypto_provider_entry_t), KM_SLEEP);
886*0Sstevel@tonic-gate 			for (i = 0; i < provider_count; i++) {
887*0Sstevel@tonic-gate 				p[i].pe_provider_id = i;
888*0Sstevel@tonic-gate 				p[i].pe_mechanism_count =
889*0Sstevel@tonic-gate 				    provider_array[i]->pd_mech_list_count;
890*0Sstevel@tonic-gate 			}
891*0Sstevel@tonic-gate 		}
892*0Sstevel@tonic-gate 		*array = p;
893*0Sstevel@tonic-gate 		*count = provider_count;
894*0Sstevel@tonic-gate 	}
895*0Sstevel@tonic-gate 
896*0Sstevel@tonic-gate 	/*
897*0Sstevel@tonic-gate 	 * Free existing array of providers and replace with new list.
898*0Sstevel@tonic-gate 	 */
899*0Sstevel@tonic-gate 	mutex_enter(&cm->cm_lock);
900*0Sstevel@tonic-gate 	if (cm->cm_provider_array != NULL) {
901*0Sstevel@tonic-gate 		ASSERT(cm->cm_provider_count > 0);
902*0Sstevel@tonic-gate 		kcf_free_provider_tab(cm->cm_provider_count,
903*0Sstevel@tonic-gate 		    cm->cm_provider_array);
904*0Sstevel@tonic-gate 	}
905*0Sstevel@tonic-gate 
906*0Sstevel@tonic-gate 	cm->cm_provider_array = provider_array;
907*0Sstevel@tonic-gate 	cm->cm_provider_count = provider_count;
908*0Sstevel@tonic-gate 	mutex_exit(&cm->cm_lock);
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
911*0Sstevel@tonic-gate }
912*0Sstevel@tonic-gate 
913*0Sstevel@tonic-gate /*
914*0Sstevel@tonic-gate  * This ioctl returns an array of crypto_provider_entry_t entries.
915*0Sstevel@tonic-gate  * This is how consumers learn which hardware providers are available.
916*0Sstevel@tonic-gate  */
917*0Sstevel@tonic-gate /* ARGSUSED */
918*0Sstevel@tonic-gate static int
919*0Sstevel@tonic-gate get_provider_list(dev_t dev, caddr_t arg, int mode, int *rval)
920*0Sstevel@tonic-gate {
921*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_get_provider_list, get_list);
922*0Sstevel@tonic-gate 	crypto_provider_entry_t *entries;
923*0Sstevel@tonic-gate 	crypto_minor_t *cm;
924*0Sstevel@tonic-gate 	size_t copyout_size;
925*0Sstevel@tonic-gate 	uint_t req_count;
926*0Sstevel@tonic-gate 	uint_t count;
927*0Sstevel@tonic-gate 	ulong_t offset;
928*0Sstevel@tonic-gate 	int rv;
929*0Sstevel@tonic-gate 
930*0Sstevel@tonic-gate 	STRUCT_INIT(get_list, mode);
931*0Sstevel@tonic-gate 
932*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
933*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "get_provider_list: failed holding minor");
934*0Sstevel@tonic-gate 		return (ENXIO);
935*0Sstevel@tonic-gate 	}
936*0Sstevel@tonic-gate 
937*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(get_list), STRUCT_SIZE(get_list)) != 0) {
938*0Sstevel@tonic-gate 		crypto_release_minor(cm);
939*0Sstevel@tonic-gate 		return (EFAULT);
940*0Sstevel@tonic-gate 	}
941*0Sstevel@tonic-gate 
942*0Sstevel@tonic-gate 	rv = crypto_get_provider_list(cm, &count, &entries, RETURN_LIST);
943*0Sstevel@tonic-gate 	if (rv != CRYPTO_SUCCESS) {
944*0Sstevel@tonic-gate 		crypto_release_minor(cm);
945*0Sstevel@tonic-gate 		STRUCT_FSET(get_list, pl_return_value, rv);
946*0Sstevel@tonic-gate 		if (copyout(STRUCT_BUF(get_list), arg,
947*0Sstevel@tonic-gate 		    STRUCT_SIZE(get_list)) != 0) {
948*0Sstevel@tonic-gate 			return (EFAULT);
949*0Sstevel@tonic-gate 		}
950*0Sstevel@tonic-gate 		return (0);
951*0Sstevel@tonic-gate 	}
952*0Sstevel@tonic-gate 	crypto_release_minor(cm);
953*0Sstevel@tonic-gate 
954*0Sstevel@tonic-gate 	/* Number of slots caller thinks we have */
955*0Sstevel@tonic-gate 	req_count = STRUCT_FGET(get_list, pl_count);
956*0Sstevel@tonic-gate 
957*0Sstevel@tonic-gate 	/* Check if only requesting number of slots */
958*0Sstevel@tonic-gate 	if (req_count == 0) {
959*0Sstevel@tonic-gate 
960*0Sstevel@tonic-gate 		STRUCT_FSET(get_list, pl_count, count);
961*0Sstevel@tonic-gate 		STRUCT_FSET(get_list, pl_return_value, CRYPTO_SUCCESS);
962*0Sstevel@tonic-gate 
963*0Sstevel@tonic-gate 		crypto_free_provider_list(entries, count);
964*0Sstevel@tonic-gate 		if (copyout(STRUCT_BUF(get_list), arg,
965*0Sstevel@tonic-gate 			STRUCT_SIZE(get_list)) != 0) {
966*0Sstevel@tonic-gate 			return (EFAULT);
967*0Sstevel@tonic-gate 		}
968*0Sstevel@tonic-gate 		return (0);
969*0Sstevel@tonic-gate 	}
970*0Sstevel@tonic-gate 
971*0Sstevel@tonic-gate 	/* check if buffer is too small */
972*0Sstevel@tonic-gate 	req_count = STRUCT_FGET(get_list, pl_count);
973*0Sstevel@tonic-gate 	if (count > req_count) {
974*0Sstevel@tonic-gate 		STRUCT_FSET(get_list, pl_count, count);
975*0Sstevel@tonic-gate 		STRUCT_FSET(get_list, pl_return_value, CRYPTO_BUFFER_TOO_SMALL);
976*0Sstevel@tonic-gate 		crypto_free_provider_list(entries, count);
977*0Sstevel@tonic-gate 		if (copyout(STRUCT_BUF(get_list), arg,
978*0Sstevel@tonic-gate 		    STRUCT_SIZE(get_list)) != 0) {
979*0Sstevel@tonic-gate 			return (EFAULT);
980*0Sstevel@tonic-gate 		}
981*0Sstevel@tonic-gate 		return (0);
982*0Sstevel@tonic-gate 	}
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate 	STRUCT_FSET(get_list, pl_count, count);
985*0Sstevel@tonic-gate 	STRUCT_FSET(get_list, pl_return_value, CRYPTO_SUCCESS);
986*0Sstevel@tonic-gate 
987*0Sstevel@tonic-gate 	copyout_size = count * sizeof (crypto_provider_entry_t);
988*0Sstevel@tonic-gate 
989*0Sstevel@tonic-gate 	/* copyout the first stuff */
990*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(get_list), arg, STRUCT_SIZE(get_list)) != 0) {
991*0Sstevel@tonic-gate 		crypto_free_provider_list(entries, count);
992*0Sstevel@tonic-gate 		return (EFAULT);
993*0Sstevel@tonic-gate 	}
994*0Sstevel@tonic-gate 
995*0Sstevel@tonic-gate 	if (count == 0) {
996*0Sstevel@tonic-gate 		crypto_free_provider_list(entries, count);
997*0Sstevel@tonic-gate 		return (0);
998*0Sstevel@tonic-gate 	}
999*0Sstevel@tonic-gate 
1000*0Sstevel@tonic-gate 	/* copyout entries */
1001*0Sstevel@tonic-gate 	offset = (ulong_t)STRUCT_FADDR(get_list, pl_list);
1002*0Sstevel@tonic-gate 	offset -= (ulong_t)STRUCT_BUF(get_list);
1003*0Sstevel@tonic-gate 	if (copyout(entries, arg + offset, copyout_size) != 0) {
1004*0Sstevel@tonic-gate 		crypto_free_provider_list(entries, count);
1005*0Sstevel@tonic-gate 		return (EFAULT);
1006*0Sstevel@tonic-gate 	}
1007*0Sstevel@tonic-gate 
1008*0Sstevel@tonic-gate 	crypto_free_provider_list(entries, count);
1009*0Sstevel@tonic-gate 	return (0);
1010*0Sstevel@tonic-gate }
1011*0Sstevel@tonic-gate 
1012*0Sstevel@tonic-gate static void
1013*0Sstevel@tonic-gate ext_to_provider_data(int mode, kcf_provider_desc_t *provider,
1014*0Sstevel@tonic-gate     crypto_provider_ext_info_t *ei, void *out)
1015*0Sstevel@tonic-gate {
1016*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_provider_data, pd);
1017*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_version, version);
1018*0Sstevel@tonic-gate 
1019*0Sstevel@tonic-gate 	STRUCT_INIT(pd, mode);
1020*0Sstevel@tonic-gate 	STRUCT_INIT(version, mode);
1021*0Sstevel@tonic-gate 
1022*0Sstevel@tonic-gate 	bcopy(provider->pd_description, STRUCT_FGET(pd, pd_prov_desc),
1023*0Sstevel@tonic-gate 	    CRYPTO_PROVIDER_DESCR_MAX_LEN);
1024*0Sstevel@tonic-gate 
1025*0Sstevel@tonic-gate 	bcopy(ei->ei_label, STRUCT_FGET(pd, pd_label), CRYPTO_EXT_SIZE_LABEL);
1026*0Sstevel@tonic-gate 	bcopy(ei->ei_manufacturerID, STRUCT_FGET(pd, pd_manufacturerID),
1027*0Sstevel@tonic-gate 	    CRYPTO_EXT_SIZE_MANUF);
1028*0Sstevel@tonic-gate 	bcopy(ei->ei_model, STRUCT_FGET(pd, pd_model), CRYPTO_EXT_SIZE_MODEL);
1029*0Sstevel@tonic-gate 	bcopy(ei->ei_serial_number, STRUCT_FGET(pd, pd_serial_number),
1030*0Sstevel@tonic-gate 	    CRYPTO_EXT_SIZE_SERIAL);
1031*0Sstevel@tonic-gate 	/*
1032*0Sstevel@tonic-gate 	 * We do not support ioctls for dual-function crypto operations yet.
1033*0Sstevel@tonic-gate 	 * So, we clear this flag as it might have been set by a provider.
1034*0Sstevel@tonic-gate 	 */
1035*0Sstevel@tonic-gate 	ei->ei_flags &= ~CRYPTO_EXTF_DUAL_CRYPTO_OPERATIONS;
1036*0Sstevel@tonic-gate 
1037*0Sstevel@tonic-gate 	STRUCT_FSET(pd, pd_flags, ei->ei_flags);
1038*0Sstevel@tonic-gate 	STRUCT_FSET(pd, pd_max_session_count, ei->ei_max_session_count);
1039*0Sstevel@tonic-gate 	STRUCT_FSET(pd, pd_session_count, (int)CRYPTO_UNAVAILABLE_INFO);
1040*0Sstevel@tonic-gate 	STRUCT_FSET(pd, pd_max_rw_session_count, ei->ei_max_session_count);
1041*0Sstevel@tonic-gate 	STRUCT_FSET(pd, pd_rw_session_count, (int)CRYPTO_UNAVAILABLE_INFO);
1042*0Sstevel@tonic-gate 	STRUCT_FSET(pd, pd_max_pin_len, ei->ei_max_pin_len);
1043*0Sstevel@tonic-gate 	STRUCT_FSET(pd, pd_min_pin_len, ei->ei_min_pin_len);
1044*0Sstevel@tonic-gate 	STRUCT_FSET(pd, pd_total_public_memory, ei->ei_total_public_memory);
1045*0Sstevel@tonic-gate 	STRUCT_FSET(pd, pd_free_public_memory, ei->ei_free_public_memory);
1046*0Sstevel@tonic-gate 	STRUCT_FSET(pd, pd_total_private_memory, ei->ei_total_private_memory);
1047*0Sstevel@tonic-gate 	STRUCT_FSET(pd, pd_free_private_memory, ei->ei_free_private_memory);
1048*0Sstevel@tonic-gate 	STRUCT_FSET(version, cv_major, ei->ei_hardware_version.cv_major);
1049*0Sstevel@tonic-gate 	STRUCT_FSET(version, cv_minor, ei->ei_hardware_version.cv_minor);
1050*0Sstevel@tonic-gate 	bcopy(STRUCT_BUF(version), STRUCT_FADDR(pd, pd_hardware_version),
1051*0Sstevel@tonic-gate 	    STRUCT_SIZE(version));
1052*0Sstevel@tonic-gate 	bcopy(STRUCT_BUF(version), STRUCT_FADDR(pd, pd_firmware_version),
1053*0Sstevel@tonic-gate 	    STRUCT_SIZE(version));
1054*0Sstevel@tonic-gate 	bcopy(ei->ei_time, STRUCT_FGET(pd, pd_time), CRYPTO_EXT_SIZE_TIME);
1055*0Sstevel@tonic-gate 	bcopy(STRUCT_BUF(pd), out, STRUCT_SIZE(pd));
1056*0Sstevel@tonic-gate }
1057*0Sstevel@tonic-gate 
1058*0Sstevel@tonic-gate /*
1059*0Sstevel@tonic-gate  * Utility routine to construct a crypto_provider_ext_info structure. Some
1060*0Sstevel@tonic-gate  * of the fields are constructed from information in the provider structure.
1061*0Sstevel@tonic-gate  * The rest of the fields have default values. We need to do this for
1062*0Sstevel@tonic-gate  * providers which do not support crypto_provider_management_ops routines.
1063*0Sstevel@tonic-gate  */
1064*0Sstevel@tonic-gate static void
1065*0Sstevel@tonic-gate fabricate_ext_info(kcf_provider_desc_t *provider,
1066*0Sstevel@tonic-gate     crypto_provider_ext_info_t *ei)
1067*0Sstevel@tonic-gate {
1068*0Sstevel@tonic-gate 	/* empty label */
1069*0Sstevel@tonic-gate 	(void) memset(ei->ei_label, ' ', CRYPTO_EXT_SIZE_LABEL);
1070*0Sstevel@tonic-gate 
1071*0Sstevel@tonic-gate 	(void) memset(ei->ei_manufacturerID, ' ', CRYPTO_EXT_SIZE_MANUF);
1072*0Sstevel@tonic-gate 	(void) strncpy((char *)ei->ei_manufacturerID, "Unknown", 7);
1073*0Sstevel@tonic-gate 
1074*0Sstevel@tonic-gate 	(void) memset(ei->ei_model, ' ', CRYPTO_EXT_SIZE_MODEL);
1075*0Sstevel@tonic-gate 	(void) strncpy((char *)ei->ei_model, "Unknown", 7);
1076*0Sstevel@tonic-gate 
1077*0Sstevel@tonic-gate 	(void) memset(ei->ei_serial_number, ' ', CRYPTO_EXT_SIZE_SERIAL);
1078*0Sstevel@tonic-gate 	(void) strncpy((char *)ei->ei_serial_number, "Unknown", 7);
1079*0Sstevel@tonic-gate 
1080*0Sstevel@tonic-gate 	if (KCF_PROV_RANDOM_OPS(provider) != NULL)
1081*0Sstevel@tonic-gate 		ei->ei_flags |= CRYPTO_EXTF_RNG;
1082*0Sstevel@tonic-gate 	if (KCF_PROV_DUAL_OPS(provider) != NULL)
1083*0Sstevel@tonic-gate 		ei->ei_flags |= CRYPTO_EXTF_DUAL_CRYPTO_OPERATIONS;
1084*0Sstevel@tonic-gate 
1085*0Sstevel@tonic-gate 	ei->ei_max_session_count = CRYPTO_UNAVAILABLE_INFO;
1086*0Sstevel@tonic-gate 	ei->ei_max_pin_len = 0;
1087*0Sstevel@tonic-gate 	ei->ei_min_pin_len = 0;
1088*0Sstevel@tonic-gate 	ei->ei_total_public_memory = CRYPTO_UNAVAILABLE_INFO;
1089*0Sstevel@tonic-gate 	ei->ei_free_public_memory = CRYPTO_UNAVAILABLE_INFO;
1090*0Sstevel@tonic-gate 	ei->ei_total_private_memory = CRYPTO_UNAVAILABLE_INFO;
1091*0Sstevel@tonic-gate 	ei->ei_free_private_memory = CRYPTO_UNAVAILABLE_INFO;
1092*0Sstevel@tonic-gate 	ei->ei_hardware_version.cv_major = 1;
1093*0Sstevel@tonic-gate 	ei->ei_hardware_version.cv_minor = 0;
1094*0Sstevel@tonic-gate 	ei->ei_firmware_version.cv_major = 1;
1095*0Sstevel@tonic-gate 	ei->ei_firmware_version.cv_minor = 0;
1096*0Sstevel@tonic-gate }
1097*0Sstevel@tonic-gate 
1098*0Sstevel@tonic-gate /* ARGSUSED */
1099*0Sstevel@tonic-gate static int
1100*0Sstevel@tonic-gate get_provider_info(dev_t dev, caddr_t arg, int mode, int *rval)
1101*0Sstevel@tonic-gate {
1102*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_get_provider_info, get_info);
1103*0Sstevel@tonic-gate 	kproject_t *projp;
1104*0Sstevel@tonic-gate 	crypto_minor_t *cm;
1105*0Sstevel@tonic-gate 	crypto_provider_id_t provider_id;
1106*0Sstevel@tonic-gate 	kcf_provider_desc_t *provider, *real_provider;
1107*0Sstevel@tonic-gate 	crypto_provider_ext_info_t *ext_info = NULL;
1108*0Sstevel@tonic-gate 	size_t need;
1109*0Sstevel@tonic-gate 	int error = 0;
1110*0Sstevel@tonic-gate 	int rv;
1111*0Sstevel@tonic-gate 	kcf_req_params_t params;
1112*0Sstevel@tonic-gate 
1113*0Sstevel@tonic-gate 	STRUCT_INIT(get_info, mode);
1114*0Sstevel@tonic-gate 
1115*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
1116*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "get_provider_info: failed holding minor");
1117*0Sstevel@tonic-gate 		return (ENXIO);
1118*0Sstevel@tonic-gate 	}
1119*0Sstevel@tonic-gate 
1120*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(get_info), STRUCT_SIZE(get_info)) != 0) {
1121*0Sstevel@tonic-gate 		crypto_release_minor(cm);
1122*0Sstevel@tonic-gate 		return (EFAULT);
1123*0Sstevel@tonic-gate 	}
1124*0Sstevel@tonic-gate 
1125*0Sstevel@tonic-gate 	need = sizeof (crypto_provider_ext_info_t);
1126*0Sstevel@tonic-gate 	if ((rv = crypto_buffer_check(need, &projp)) != CRYPTO_SUCCESS) {
1127*0Sstevel@tonic-gate 		need = 0;
1128*0Sstevel@tonic-gate 		goto release_minor;
1129*0Sstevel@tonic-gate 	}
1130*0Sstevel@tonic-gate 
1131*0Sstevel@tonic-gate 	/* initialize provider_array */
1132*0Sstevel@tonic-gate 	if (cm->cm_provider_array == NULL) {
1133*0Sstevel@tonic-gate 		rv = crypto_get_provider_list(cm, NULL, NULL, DONT_RETURN_LIST);
1134*0Sstevel@tonic-gate 		if (rv != CRYPTO_SUCCESS) {
1135*0Sstevel@tonic-gate 			goto release_minor;
1136*0Sstevel@tonic-gate 		}
1137*0Sstevel@tonic-gate 	}
1138*0Sstevel@tonic-gate 
1139*0Sstevel@tonic-gate 	ext_info = kmem_zalloc(need, KM_SLEEP);
1140*0Sstevel@tonic-gate 
1141*0Sstevel@tonic-gate 	provider_id = STRUCT_FGET(get_info, gi_provider_id);
1142*0Sstevel@tonic-gate 	mutex_enter(&cm->cm_lock);
1143*0Sstevel@tonic-gate 	/* index must be less than count of providers */
1144*0Sstevel@tonic-gate 	if (provider_id >= cm->cm_provider_count) {
1145*0Sstevel@tonic-gate 		mutex_exit(&cm->cm_lock);
1146*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
1147*0Sstevel@tonic-gate 		goto release_minor;
1148*0Sstevel@tonic-gate 	}
1149*0Sstevel@tonic-gate 
1150*0Sstevel@tonic-gate 	ASSERT(cm->cm_provider_array != NULL);
1151*0Sstevel@tonic-gate 	provider = cm->cm_provider_array[provider_id];
1152*0Sstevel@tonic-gate 	KCF_PROV_REFHOLD(provider);
1153*0Sstevel@tonic-gate 	mutex_exit(&cm->cm_lock);
1154*0Sstevel@tonic-gate 
1155*0Sstevel@tonic-gate 	(void) kcf_get_hardware_provider_nomech(
1156*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(provider_ops), CRYPTO_PROVIDER_OFFSET(ext_info),
1157*0Sstevel@tonic-gate 	    provider, &real_provider);
1158*0Sstevel@tonic-gate 
1159*0Sstevel@tonic-gate 	if (real_provider != NULL) {
1160*0Sstevel@tonic-gate 		ASSERT(real_provider == provider ||
1161*0Sstevel@tonic-gate 		    provider->pd_prov_type == CRYPTO_LOGICAL_PROVIDER);
1162*0Sstevel@tonic-gate 		KCF_WRAP_PROVMGMT_OPS_PARAMS(&params, KCF_OP_MGMT_EXTINFO,
1163*0Sstevel@tonic-gate 		    0, NULL, 0, NULL, 0, NULL, ext_info, provider);
1164*0Sstevel@tonic-gate 		rv = kcf_submit_request(real_provider, NULL, NULL, &params,
1165*0Sstevel@tonic-gate 		    B_FALSE);
1166*0Sstevel@tonic-gate 		ASSERT(rv != CRYPTO_NOT_SUPPORTED);
1167*0Sstevel@tonic-gate 	} else {
1168*0Sstevel@tonic-gate 		/* do the best we can */
1169*0Sstevel@tonic-gate 		fabricate_ext_info(provider, ext_info);
1170*0Sstevel@tonic-gate 		rv = CRYPTO_SUCCESS;
1171*0Sstevel@tonic-gate 	}
1172*0Sstevel@tonic-gate 	KCF_PROV_REFRELE(provider);
1173*0Sstevel@tonic-gate 
1174*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS) {
1175*0Sstevel@tonic-gate 		ext_to_provider_data(mode, provider, ext_info,
1176*0Sstevel@tonic-gate 		    STRUCT_FADDR(get_info, gi_provider_data));
1177*0Sstevel@tonic-gate 	}
1178*0Sstevel@tonic-gate 
1179*0Sstevel@tonic-gate release_minor:
1180*0Sstevel@tonic-gate 	if (need != 0) {
1181*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
1182*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(need, projp);
1183*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
1184*0Sstevel@tonic-gate 	}
1185*0Sstevel@tonic-gate 	crypto_release_minor(cm);
1186*0Sstevel@tonic-gate 
1187*0Sstevel@tonic-gate 	if (ext_info != NULL)
1188*0Sstevel@tonic-gate 		kmem_free(ext_info, sizeof (crypto_provider_ext_info_t));
1189*0Sstevel@tonic-gate 
1190*0Sstevel@tonic-gate 	if (error != 0)
1191*0Sstevel@tonic-gate 		return (error);
1192*0Sstevel@tonic-gate 
1193*0Sstevel@tonic-gate 	STRUCT_FSET(get_info, gi_return_value, rv);
1194*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(get_info), arg, STRUCT_SIZE(get_info)) != 0) {
1195*0Sstevel@tonic-gate 		return (EFAULT);
1196*0Sstevel@tonic-gate 	}
1197*0Sstevel@tonic-gate 	return (0);
1198*0Sstevel@tonic-gate }
1199*0Sstevel@tonic-gate 
1200*0Sstevel@tonic-gate /*
1201*0Sstevel@tonic-gate  * This ioctl returns an array of crypto_mech_name_t entries.
1202*0Sstevel@tonic-gate  * This is how consumers learn which mechanisms are permitted
1203*0Sstevel@tonic-gate  * by a provider.
1204*0Sstevel@tonic-gate  */
1205*0Sstevel@tonic-gate /* ARGSUSED */
1206*0Sstevel@tonic-gate static int
1207*0Sstevel@tonic-gate get_provider_mechanisms(dev_t dev, caddr_t arg, int mode, int *rval)
1208*0Sstevel@tonic-gate {
1209*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_get_provider_mechanisms, get_mechanisms);
1210*0Sstevel@tonic-gate 	crypto_mech_name_t *entries;
1211*0Sstevel@tonic-gate 	crypto_minor_t *cm;
1212*0Sstevel@tonic-gate 	size_t copyout_size;
1213*0Sstevel@tonic-gate 	uint_t req_count;
1214*0Sstevel@tonic-gate 	uint_t count;
1215*0Sstevel@tonic-gate 	ulong_t offset;
1216*0Sstevel@tonic-gate 	int err;
1217*0Sstevel@tonic-gate 
1218*0Sstevel@tonic-gate 	STRUCT_INIT(get_mechanisms, mode);
1219*0Sstevel@tonic-gate 
1220*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
1221*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
1222*0Sstevel@tonic-gate 		    "get_provider_mechanisms: failed holding minor");
1223*0Sstevel@tonic-gate 		return (ENXIO);
1224*0Sstevel@tonic-gate 	}
1225*0Sstevel@tonic-gate 
1226*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(get_mechanisms),
1227*0Sstevel@tonic-gate 	    STRUCT_SIZE(get_mechanisms)) != 0) {
1228*0Sstevel@tonic-gate 		crypto_release_minor(cm);
1229*0Sstevel@tonic-gate 		return (EFAULT);
1230*0Sstevel@tonic-gate 	}
1231*0Sstevel@tonic-gate 
1232*0Sstevel@tonic-gate 	/* get array of mechanisms from the core module */
1233*0Sstevel@tonic-gate 	if ((err = crypto_get_provider_mechanisms(cm,
1234*0Sstevel@tonic-gate 	    STRUCT_FGET(get_mechanisms, pm_provider_id),
1235*0Sstevel@tonic-gate 	    &count, &entries)) != 0) {
1236*0Sstevel@tonic-gate 		crypto_release_minor(cm);
1237*0Sstevel@tonic-gate 		STRUCT_FSET(get_mechanisms, pm_return_value, err);
1238*0Sstevel@tonic-gate 		if (copyout(STRUCT_BUF(get_mechanisms), arg,
1239*0Sstevel@tonic-gate 		    STRUCT_SIZE(get_mechanisms)) != 0) {
1240*0Sstevel@tonic-gate 			return (EFAULT);
1241*0Sstevel@tonic-gate 		}
1242*0Sstevel@tonic-gate 		return (0);
1243*0Sstevel@tonic-gate 	}
1244*0Sstevel@tonic-gate 	crypto_release_minor(cm);
1245*0Sstevel@tonic-gate 	/* Number of mechs caller thinks we have */
1246*0Sstevel@tonic-gate 	req_count = STRUCT_FGET(get_mechanisms, pm_count);
1247*0Sstevel@tonic-gate 
1248*0Sstevel@tonic-gate 	/* Check if caller is just requesting a count of mechanisms */
1249*0Sstevel@tonic-gate 	if (req_count == 0) {
1250*0Sstevel@tonic-gate 		STRUCT_FSET(get_mechanisms, pm_count, count);
1251*0Sstevel@tonic-gate 		STRUCT_FSET(get_mechanisms, pm_return_value, CRYPTO_SUCCESS);
1252*0Sstevel@tonic-gate 
1253*0Sstevel@tonic-gate 		crypto_free_mech_list(entries, count);
1254*0Sstevel@tonic-gate 		if (copyout(STRUCT_BUF(get_mechanisms), arg,
1255*0Sstevel@tonic-gate 		    STRUCT_SIZE(get_mechanisms)) != 0) {
1256*0Sstevel@tonic-gate 			return (EFAULT);
1257*0Sstevel@tonic-gate 		}
1258*0Sstevel@tonic-gate 		return (0);
1259*0Sstevel@tonic-gate 	}
1260*0Sstevel@tonic-gate 
1261*0Sstevel@tonic-gate 	/* check if buffer is too small */
1262*0Sstevel@tonic-gate 	if (count > req_count) {
1263*0Sstevel@tonic-gate 		STRUCT_FSET(get_mechanisms, pm_count, count);
1264*0Sstevel@tonic-gate 		STRUCT_FSET(get_mechanisms, pm_return_value,
1265*0Sstevel@tonic-gate 		    CRYPTO_BUFFER_TOO_SMALL);
1266*0Sstevel@tonic-gate 		crypto_free_mech_list(entries, count);
1267*0Sstevel@tonic-gate 		if (copyout(STRUCT_BUF(get_mechanisms), arg,
1268*0Sstevel@tonic-gate 		    STRUCT_SIZE(get_mechanisms)) != 0) {
1269*0Sstevel@tonic-gate 			return (EFAULT);
1270*0Sstevel@tonic-gate 		}
1271*0Sstevel@tonic-gate 		return (0);
1272*0Sstevel@tonic-gate 	}
1273*0Sstevel@tonic-gate 
1274*0Sstevel@tonic-gate 	STRUCT_FSET(get_mechanisms, pm_count, count);
1275*0Sstevel@tonic-gate 	STRUCT_FSET(get_mechanisms, pm_return_value, CRYPTO_SUCCESS);
1276*0Sstevel@tonic-gate 
1277*0Sstevel@tonic-gate 	copyout_size = count * sizeof (crypto_mech_name_t);
1278*0Sstevel@tonic-gate 
1279*0Sstevel@tonic-gate 	/* copyout the first stuff */
1280*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(get_mechanisms), arg,
1281*0Sstevel@tonic-gate 	    STRUCT_SIZE(get_mechanisms)) != 0) {
1282*0Sstevel@tonic-gate 		crypto_free_mech_list(entries, count);
1283*0Sstevel@tonic-gate 		return (EFAULT);
1284*0Sstevel@tonic-gate 	}
1285*0Sstevel@tonic-gate 
1286*0Sstevel@tonic-gate 	if (count == 0) {
1287*0Sstevel@tonic-gate 		return (0);
1288*0Sstevel@tonic-gate 	}
1289*0Sstevel@tonic-gate 
1290*0Sstevel@tonic-gate 	/* copyout entries */
1291*0Sstevel@tonic-gate 	offset = (ulong_t)STRUCT_FADDR(get_mechanisms, pm_list);
1292*0Sstevel@tonic-gate 	offset -= (ulong_t)STRUCT_BUF(get_mechanisms);
1293*0Sstevel@tonic-gate 	if (copyout(entries, arg + offset, copyout_size) != 0) {
1294*0Sstevel@tonic-gate 		crypto_free_mech_list(entries, count);
1295*0Sstevel@tonic-gate 		return (EFAULT);
1296*0Sstevel@tonic-gate 	}
1297*0Sstevel@tonic-gate 
1298*0Sstevel@tonic-gate 	crypto_free_mech_list(entries, count);
1299*0Sstevel@tonic-gate 	return (0);
1300*0Sstevel@tonic-gate }
1301*0Sstevel@tonic-gate 
1302*0Sstevel@tonic-gate /*
1303*0Sstevel@tonic-gate  * This ioctl returns information about a provider's mechanism.
1304*0Sstevel@tonic-gate  */
1305*0Sstevel@tonic-gate /* ARGSUSED */
1306*0Sstevel@tonic-gate static int
1307*0Sstevel@tonic-gate get_provider_mechanism_info(dev_t dev, caddr_t arg, int mode, int *rval)
1308*0Sstevel@tonic-gate {
1309*0Sstevel@tonic-gate 	crypto_get_provider_mechanism_info_t mechanism_info;
1310*0Sstevel@tonic-gate 	crypto_minor_t *cm;
1311*0Sstevel@tonic-gate 	kcf_provider_desc_t *pd;
1312*0Sstevel@tonic-gate 	crypto_mech_info_t *mi = NULL;
1313*0Sstevel@tonic-gate 	int rv = CRYPTO_SUCCESS;
1314*0Sstevel@tonic-gate 	int i;
1315*0Sstevel@tonic-gate 
1316*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
1317*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
1318*0Sstevel@tonic-gate 		    "get_provider_mechanism_info: failed holding minor");
1319*0Sstevel@tonic-gate 		return (ENXIO);
1320*0Sstevel@tonic-gate 	}
1321*0Sstevel@tonic-gate 
1322*0Sstevel@tonic-gate 	if (copyin(arg, &mechanism_info, sizeof (mechanism_info)) != 0) {
1323*0Sstevel@tonic-gate 		crypto_release_minor(cm);
1324*0Sstevel@tonic-gate 		return (EFAULT);
1325*0Sstevel@tonic-gate 	}
1326*0Sstevel@tonic-gate 
1327*0Sstevel@tonic-gate 	/* initialize provider table */
1328*0Sstevel@tonic-gate 	if (cm->cm_provider_array == NULL) {
1329*0Sstevel@tonic-gate 		rv = crypto_get_provider_list(cm, NULL, NULL, DONT_RETURN_LIST);
1330*0Sstevel@tonic-gate 		if (rv != CRYPTO_SUCCESS) {
1331*0Sstevel@tonic-gate 			mutex_enter(&cm->cm_lock);
1332*0Sstevel@tonic-gate 			goto fail;
1333*0Sstevel@tonic-gate 		}
1334*0Sstevel@tonic-gate 	}
1335*0Sstevel@tonic-gate 
1336*0Sstevel@tonic-gate 	/*
1337*0Sstevel@tonic-gate 	 * Provider ID must be less than the count of providers
1338*0Sstevel@tonic-gate 	 * obtained by calling get_provider_list().
1339*0Sstevel@tonic-gate 	 */
1340*0Sstevel@tonic-gate 	mutex_enter(&cm->cm_lock);
1341*0Sstevel@tonic-gate 	if (mechanism_info.mi_provider_id >= cm->cm_provider_count) {
1342*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
1343*0Sstevel@tonic-gate 		goto fail;
1344*0Sstevel@tonic-gate 	}
1345*0Sstevel@tonic-gate 
1346*0Sstevel@tonic-gate 	pd = cm->cm_provider_array[mechanism_info.mi_provider_id];
1347*0Sstevel@tonic-gate 
1348*0Sstevel@tonic-gate 	for (i = 0; i < pd->pd_mech_list_count; i++) {
1349*0Sstevel@tonic-gate 		if (strncmp(pd->pd_mechanisms[i].cm_mech_name,
1350*0Sstevel@tonic-gate 		    mechanism_info.mi_mechanism_name,
1351*0Sstevel@tonic-gate 		    CRYPTO_MAX_MECH_NAME) == 0) {
1352*0Sstevel@tonic-gate 			mi = &pd->pd_mechanisms[i];
1353*0Sstevel@tonic-gate 		}
1354*0Sstevel@tonic-gate 	}
1355*0Sstevel@tonic-gate 
1356*0Sstevel@tonic-gate 	if (mi == NULL) {
1357*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
1358*0Sstevel@tonic-gate 		goto fail;
1359*0Sstevel@tonic-gate 	}
1360*0Sstevel@tonic-gate 
1361*0Sstevel@tonic-gate 	mechanism_info.mi_min_key_size = mi->cm_min_key_length;
1362*0Sstevel@tonic-gate 	mechanism_info.mi_max_key_size = mi->cm_max_key_length;
1363*0Sstevel@tonic-gate 	mechanism_info.mi_flags = mi->cm_func_group_mask;
1364*0Sstevel@tonic-gate 
1365*0Sstevel@tonic-gate fail:
1366*0Sstevel@tonic-gate 	mutex_exit(&cm->cm_lock);
1367*0Sstevel@tonic-gate 	crypto_release_minor(cm);
1368*0Sstevel@tonic-gate 	mechanism_info.mi_return_value = rv;
1369*0Sstevel@tonic-gate 	if (copyout(&mechanism_info, arg, sizeof (mechanism_info)) != 0) {
1370*0Sstevel@tonic-gate 		return (EFAULT);
1371*0Sstevel@tonic-gate 	}
1372*0Sstevel@tonic-gate 
1373*0Sstevel@tonic-gate 	return (0);
1374*0Sstevel@tonic-gate }
1375*0Sstevel@tonic-gate 
1376*0Sstevel@tonic-gate /*
1377*0Sstevel@tonic-gate  * Every open of /dev/crypto multiplexes all PKCS#11 sessions across
1378*0Sstevel@tonic-gate  * a single session to each provider. Calls to open and close session
1379*0Sstevel@tonic-gate  * are not made to providers that do not support sessions. For these
1380*0Sstevel@tonic-gate  * providers, a session number of 0 is passed during subsequent operations,
1381*0Sstevel@tonic-gate  * and it is ignored by the provider.
1382*0Sstevel@tonic-gate  */
1383*0Sstevel@tonic-gate static int
1384*0Sstevel@tonic-gate crypto_get_provider_session(crypto_minor_t *cm,
1385*0Sstevel@tonic-gate     crypto_provider_id_t provider_index, crypto_provider_session_t **output_ps)
1386*0Sstevel@tonic-gate {
1387*0Sstevel@tonic-gate 	kcf_provider_desc_t *pd, *real_provider;
1388*0Sstevel@tonic-gate 	kcf_req_params_t params;
1389*0Sstevel@tonic-gate 	crypto_provider_session_t *ps, *new_ps;
1390*0Sstevel@tonic-gate 	crypto_session_id_t provider_session_id = 0;
1391*0Sstevel@tonic-gate 	int rv;
1392*0Sstevel@tonic-gate 
1393*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cm->cm_lock));
1394*0Sstevel@tonic-gate 
1395*0Sstevel@tonic-gate 	/* pd may be a logical provider */
1396*0Sstevel@tonic-gate 	pd = cm->cm_provider_array[provider_index];
1397*0Sstevel@tonic-gate 
1398*0Sstevel@tonic-gate again:
1399*0Sstevel@tonic-gate 	/*
1400*0Sstevel@tonic-gate 	 * Check if there is already a session to the provider.
1401*0Sstevel@tonic-gate 	 * Sessions may be to a logical provider or a real provider.
1402*0Sstevel@tonic-gate 	 */
1403*0Sstevel@tonic-gate 	for (ps = cm->cm_provider_session; ps != NULL; ps = ps->ps_next) {
1404*0Sstevel@tonic-gate 		if (ps->ps_provider == pd)
1405*0Sstevel@tonic-gate 			break;
1406*0Sstevel@tonic-gate 	}
1407*0Sstevel@tonic-gate 
1408*0Sstevel@tonic-gate 	/* found existing session */
1409*0Sstevel@tonic-gate 	if (ps != NULL) {
1410*0Sstevel@tonic-gate 		ps->ps_refcnt++;
1411*0Sstevel@tonic-gate 		*output_ps = ps;
1412*0Sstevel@tonic-gate 		return (CRYPTO_SUCCESS);
1413*0Sstevel@tonic-gate 	}
1414*0Sstevel@tonic-gate 	mutex_exit(&cm->cm_lock);
1415*0Sstevel@tonic-gate 
1416*0Sstevel@tonic-gate 	/* find a hardware provider that supports session ops */
1417*0Sstevel@tonic-gate 	(void) kcf_get_hardware_provider_nomech(CRYPTO_OPS_OFFSET(session_ops),
1418*0Sstevel@tonic-gate 	    CRYPTO_SESSION_OFFSET(session_open), pd, &real_provider);
1419*0Sstevel@tonic-gate 
1420*0Sstevel@tonic-gate 	if (real_provider != NULL) {
1421*0Sstevel@tonic-gate 		ASSERT(real_provider == pd ||
1422*0Sstevel@tonic-gate 		    pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER);
1423*0Sstevel@tonic-gate 		/* open session to provider */
1424*0Sstevel@tonic-gate 		KCF_WRAP_SESSION_OPS_PARAMS(&params, KCF_OP_SESSION_OPEN,
1425*0Sstevel@tonic-gate 		    &provider_session_id, 0, CRYPTO_USER, NULL, 0, pd);
1426*0Sstevel@tonic-gate 		rv = kcf_submit_request(real_provider, NULL, NULL, &params,
1427*0Sstevel@tonic-gate 		    B_FALSE);
1428*0Sstevel@tonic-gate 		if (rv != CRYPTO_SUCCESS) {
1429*0Sstevel@tonic-gate 			mutex_enter(&cm->cm_lock);
1430*0Sstevel@tonic-gate 			return (rv);
1431*0Sstevel@tonic-gate 		}
1432*0Sstevel@tonic-gate 	}
1433*0Sstevel@tonic-gate 
1434*0Sstevel@tonic-gate 	/* allocate crypto_provider_session structure */
1435*0Sstevel@tonic-gate 	new_ps = kmem_zalloc(sizeof (crypto_provider_session_t), KM_SLEEP);
1436*0Sstevel@tonic-gate 
1437*0Sstevel@tonic-gate 	/*
1438*0Sstevel@tonic-gate 	 * Check if someone opened a session to the provider
1439*0Sstevel@tonic-gate 	 * while we dropped the lock.
1440*0Sstevel@tonic-gate 	 */
1441*0Sstevel@tonic-gate 	mutex_enter(&cm->cm_lock);
1442*0Sstevel@tonic-gate 	for (ps = cm->cm_provider_session; ps != NULL; ps = ps->ps_next) {
1443*0Sstevel@tonic-gate 		if (ps->ps_provider == pd) {
1444*0Sstevel@tonic-gate 			mutex_exit(&cm->cm_lock);
1445*0Sstevel@tonic-gate 			kmem_free(new_ps, sizeof (crypto_provider_session_t));
1446*0Sstevel@tonic-gate 			if (real_provider != NULL) {
1447*0Sstevel@tonic-gate 				KCF_WRAP_SESSION_OPS_PARAMS(&params,
1448*0Sstevel@tonic-gate 				    KCF_OP_SESSION_CLOSE, NULL,
1449*0Sstevel@tonic-gate 				    provider_session_id, CRYPTO_USER, NULL, 0,
1450*0Sstevel@tonic-gate 				    pd);
1451*0Sstevel@tonic-gate 				(void) kcf_submit_request(real_provider, NULL,
1452*0Sstevel@tonic-gate 				    NULL, &params, B_FALSE);
1453*0Sstevel@tonic-gate 			}
1454*0Sstevel@tonic-gate 			mutex_enter(&cm->cm_lock);
1455*0Sstevel@tonic-gate 			goto again;
1456*0Sstevel@tonic-gate 
1457*0Sstevel@tonic-gate 		}
1458*0Sstevel@tonic-gate 	}
1459*0Sstevel@tonic-gate 
1460*0Sstevel@tonic-gate 	/* increment refcnt and attach to crypto_minor structure */
1461*0Sstevel@tonic-gate 	new_ps->ps_session = provider_session_id;
1462*0Sstevel@tonic-gate 	new_ps->ps_refcnt = 1;
1463*0Sstevel@tonic-gate 	KCF_PROV_REFHOLD(pd);
1464*0Sstevel@tonic-gate 	new_ps->ps_provider = pd;
1465*0Sstevel@tonic-gate 	if (real_provider != NULL) {
1466*0Sstevel@tonic-gate 		KCF_PROV_REFHOLD(real_provider);
1467*0Sstevel@tonic-gate 		new_ps->ps_real_provider = real_provider;
1468*0Sstevel@tonic-gate 	}
1469*0Sstevel@tonic-gate 	new_ps->ps_next = cm->cm_provider_session;
1470*0Sstevel@tonic-gate 	cm->cm_provider_session = new_ps;
1471*0Sstevel@tonic-gate 
1472*0Sstevel@tonic-gate 	*output_ps = new_ps;
1473*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
1474*0Sstevel@tonic-gate }
1475*0Sstevel@tonic-gate 
1476*0Sstevel@tonic-gate /*
1477*0Sstevel@tonic-gate  * Release a provider session.
1478*0Sstevel@tonic-gate  * If the reference count goes to zero, then close the session
1479*0Sstevel@tonic-gate  * to the provider.
1480*0Sstevel@tonic-gate  */
1481*0Sstevel@tonic-gate static void
1482*0Sstevel@tonic-gate crypto_release_provider_session(crypto_minor_t *cm,
1483*0Sstevel@tonic-gate     crypto_provider_session_t *provider_session)
1484*0Sstevel@tonic-gate {
1485*0Sstevel@tonic-gate 	kcf_req_params_t params;
1486*0Sstevel@tonic-gate 	crypto_provider_session_t *ps = NULL, **prev;
1487*0Sstevel@tonic-gate 
1488*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cm->cm_lock));
1489*0Sstevel@tonic-gate 
1490*0Sstevel@tonic-gate 	/* verify that provider_session is valid */
1491*0Sstevel@tonic-gate 	for (ps = cm->cm_provider_session, prev = &cm->cm_provider_session;
1492*0Sstevel@tonic-gate 	    ps != NULL; prev = &ps->ps_next, ps = ps->ps_next) {
1493*0Sstevel@tonic-gate 		if (ps == provider_session) {
1494*0Sstevel@tonic-gate 			break;
1495*0Sstevel@tonic-gate 		}
1496*0Sstevel@tonic-gate 	}
1497*0Sstevel@tonic-gate 
1498*0Sstevel@tonic-gate 	if (ps == NULL)
1499*0Sstevel@tonic-gate 		return;
1500*0Sstevel@tonic-gate 
1501*0Sstevel@tonic-gate 	ps->ps_refcnt--;
1502*0Sstevel@tonic-gate 
1503*0Sstevel@tonic-gate 	if (ps->ps_refcnt > 0)
1504*0Sstevel@tonic-gate 		return;
1505*0Sstevel@tonic-gate 
1506*0Sstevel@tonic-gate 	if (ps->ps_real_provider != NULL) {
1507*0Sstevel@tonic-gate 		/* close session with provider */
1508*0Sstevel@tonic-gate 		KCF_WRAP_SESSION_OPS_PARAMS(&params, KCF_OP_SESSION_CLOSE, NULL,
1509*0Sstevel@tonic-gate 		    ps->ps_session, CRYPTO_USER, NULL, 0, ps->ps_provider);
1510*0Sstevel@tonic-gate 		(void) kcf_submit_request(ps->ps_real_provider,
1511*0Sstevel@tonic-gate 		    NULL, NULL, &params, B_FALSE);
1512*0Sstevel@tonic-gate 		KCF_PROV_REFRELE(ps->ps_real_provider);
1513*0Sstevel@tonic-gate 	}
1514*0Sstevel@tonic-gate 	KCF_PROV_REFRELE(ps->ps_provider);
1515*0Sstevel@tonic-gate 	*prev = ps->ps_next;
1516*0Sstevel@tonic-gate 	kmem_free(ps, sizeof (*ps));
1517*0Sstevel@tonic-gate }
1518*0Sstevel@tonic-gate 
1519*0Sstevel@tonic-gate static int
1520*0Sstevel@tonic-gate grow_session_table(crypto_minor_t *cm)
1521*0Sstevel@tonic-gate {
1522*0Sstevel@tonic-gate 	crypto_session_data_t **session_table;
1523*0Sstevel@tonic-gate 	crypto_session_data_t **new;
1524*0Sstevel@tonic-gate 	uint_t session_table_count;
1525*0Sstevel@tonic-gate 	uint_t need;
1526*0Sstevel@tonic-gate 	size_t current_allocation;
1527*0Sstevel@tonic-gate 	size_t new_allocation;
1528*0Sstevel@tonic-gate 
1529*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cm->cm_lock));
1530*0Sstevel@tonic-gate 
1531*0Sstevel@tonic-gate 	session_table_count = cm->cm_session_table_count;
1532*0Sstevel@tonic-gate 	session_table = cm->cm_session_table;
1533*0Sstevel@tonic-gate 	need = session_table_count + CRYPTO_SESSION_CHUNK;
1534*0Sstevel@tonic-gate 
1535*0Sstevel@tonic-gate 	current_allocation = session_table_count * sizeof (void *);
1536*0Sstevel@tonic-gate 	new_allocation = need * sizeof (void *);
1537*0Sstevel@tonic-gate 
1538*0Sstevel@tonic-gate 	mutex_enter(&curproc->p_lock);
1539*0Sstevel@tonic-gate 	mutex_enter(&crypto_rctl_lock);
1540*0Sstevel@tonic-gate 
1541*0Sstevel@tonic-gate 	/* give back the current allocation */
1542*0Sstevel@tonic-gate 	if (cm->cm_projp != NULL) {
1543*0Sstevel@tonic-gate 		cm->cm_projp->kpj_data.kpd_crypto_mem -= current_allocation;
1544*0Sstevel@tonic-gate 	}
1545*0Sstevel@tonic-gate 
1546*0Sstevel@tonic-gate 	/*
1547*0Sstevel@tonic-gate 	 * Memory needed to grow the session table is checked
1548*0Sstevel@tonic-gate 	 * against the project.max-crypto-memory resource control.
1549*0Sstevel@tonic-gate 	 */
1550*0Sstevel@tonic-gate 	if (rctl_test(rc_project_crypto_mem,
1551*0Sstevel@tonic-gate 	    curproc->p_task->tk_proj->kpj_rctls, curproc,
1552*0Sstevel@tonic-gate 	    new_allocation, 0) & RCT_DENY) {
1553*0Sstevel@tonic-gate 		/* restore the current allocation */
1554*0Sstevel@tonic-gate 		if (cm->cm_projp != NULL) {
1555*0Sstevel@tonic-gate 			cm->cm_projp->kpj_data.kpd_crypto_mem +=
1556*0Sstevel@tonic-gate 			    current_allocation;
1557*0Sstevel@tonic-gate 		}
1558*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
1559*0Sstevel@tonic-gate 		mutex_exit(&curproc->p_lock);
1560*0Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
1561*0Sstevel@tonic-gate 	}
1562*0Sstevel@tonic-gate 	curproc->p_task->tk_proj->kpj_data.kpd_crypto_mem += new_allocation;
1563*0Sstevel@tonic-gate 
1564*0Sstevel@tonic-gate 	/* the process changed projects */
1565*0Sstevel@tonic-gate 	if (curproc->p_task->tk_proj != cm->cm_projp) {
1566*0Sstevel@tonic-gate 		if (cm->cm_projp != 0)
1567*0Sstevel@tonic-gate 			project_rele(cm->cm_projp);
1568*0Sstevel@tonic-gate 		(void) project_hold(curproc->p_task->tk_proj);
1569*0Sstevel@tonic-gate 		cm->cm_projp = curproc->p_task->tk_proj;
1570*0Sstevel@tonic-gate 	}
1571*0Sstevel@tonic-gate 	mutex_exit(&crypto_rctl_lock);
1572*0Sstevel@tonic-gate 	mutex_exit(&curproc->p_lock);
1573*0Sstevel@tonic-gate 
1574*0Sstevel@tonic-gate 	/* drop lock while we allocate memory */
1575*0Sstevel@tonic-gate 	mutex_exit(&cm->cm_lock);
1576*0Sstevel@tonic-gate 	new = kmem_zalloc(new_allocation, KM_SLEEP);
1577*0Sstevel@tonic-gate 	mutex_enter(&cm->cm_lock);
1578*0Sstevel@tonic-gate 
1579*0Sstevel@tonic-gate 	/* check if another thread increased the table size */
1580*0Sstevel@tonic-gate 	if (session_table_count != cm->cm_session_table_count) {
1581*0Sstevel@tonic-gate 		kmem_free(new, new_allocation);
1582*0Sstevel@tonic-gate 		return (CRYPTO_SUCCESS);
1583*0Sstevel@tonic-gate 	}
1584*0Sstevel@tonic-gate 
1585*0Sstevel@tonic-gate 	bcopy(session_table, new, current_allocation);
1586*0Sstevel@tonic-gate 	kmem_free(session_table, current_allocation);
1587*0Sstevel@tonic-gate 	cm->cm_session_table = new;
1588*0Sstevel@tonic-gate 	cm->cm_session_table_count += CRYPTO_SESSION_CHUNK;
1589*0Sstevel@tonic-gate 
1590*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
1591*0Sstevel@tonic-gate }
1592*0Sstevel@tonic-gate 
1593*0Sstevel@tonic-gate /*
1594*0Sstevel@tonic-gate  * Find unused entry in session table and return it's index.
1595*0Sstevel@tonic-gate  * Initialize session table entry.
1596*0Sstevel@tonic-gate  */
1597*0Sstevel@tonic-gate /* ARGSUSED */
1598*0Sstevel@tonic-gate static int
1599*0Sstevel@tonic-gate crypto_open_session(dev_t dev, uint_t flags, crypto_session_id_t *session_index,
1600*0Sstevel@tonic-gate     crypto_provider_id_t provider_id)
1601*0Sstevel@tonic-gate {
1602*0Sstevel@tonic-gate 	crypto_session_data_t **session_table;
1603*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
1604*0Sstevel@tonic-gate 	crypto_minor_t *cm;
1605*0Sstevel@tonic-gate 	uint_t session_table_count;
1606*0Sstevel@tonic-gate 	uint_t i;
1607*0Sstevel@tonic-gate 	int rv;
1608*0Sstevel@tonic-gate 	crypto_provider_session_t *ps;
1609*0Sstevel@tonic-gate 	kcf_provider_desc_t *provider;
1610*0Sstevel@tonic-gate 
1611*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
1612*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "crypto_open_session: failed holding minor");
1613*0Sstevel@tonic-gate 		return (CRYPTO_FAILED);
1614*0Sstevel@tonic-gate 	}
1615*0Sstevel@tonic-gate 
1616*0Sstevel@tonic-gate 	/* initialize provider_array */
1617*0Sstevel@tonic-gate 	if (cm->cm_provider_array == NULL) {
1618*0Sstevel@tonic-gate 		rv = crypto_get_provider_list(cm, NULL, NULL, DONT_RETURN_LIST);
1619*0Sstevel@tonic-gate 		if (rv != 0) {
1620*0Sstevel@tonic-gate 			crypto_release_minor(cm);
1621*0Sstevel@tonic-gate 			return (rv);
1622*0Sstevel@tonic-gate 		}
1623*0Sstevel@tonic-gate 	}
1624*0Sstevel@tonic-gate 
1625*0Sstevel@tonic-gate 	mutex_enter(&cm->cm_lock);
1626*0Sstevel@tonic-gate 	/* index must be less than count of providers */
1627*0Sstevel@tonic-gate 	if (provider_id >= cm->cm_provider_count) {
1628*0Sstevel@tonic-gate 		mutex_exit(&cm->cm_lock);
1629*0Sstevel@tonic-gate 		crypto_release_minor(cm);
1630*0Sstevel@tonic-gate 		return (CRYPTO_INVALID_PROVIDER_ID);
1631*0Sstevel@tonic-gate 	}
1632*0Sstevel@tonic-gate 	ASSERT(cm->cm_provider_array != NULL);
1633*0Sstevel@tonic-gate 
1634*0Sstevel@tonic-gate 	rv = crypto_get_provider_session(cm, provider_id, &ps);
1635*0Sstevel@tonic-gate 	if (rv != CRYPTO_SUCCESS) {
1636*0Sstevel@tonic-gate 		mutex_exit(&cm->cm_lock);
1637*0Sstevel@tonic-gate 		crypto_release_minor(cm);
1638*0Sstevel@tonic-gate 		return (rv);
1639*0Sstevel@tonic-gate 	}
1640*0Sstevel@tonic-gate 	provider = cm->cm_provider_array[provider_id];
1641*0Sstevel@tonic-gate 
1642*0Sstevel@tonic-gate again:
1643*0Sstevel@tonic-gate 	session_table_count = cm->cm_session_table_count;
1644*0Sstevel@tonic-gate 	session_table = cm->cm_session_table;
1645*0Sstevel@tonic-gate 
1646*0Sstevel@tonic-gate 	/* session handles start with 1 */
1647*0Sstevel@tonic-gate 	for (i = 1; i < session_table_count; i++) {
1648*0Sstevel@tonic-gate 		if (session_table[i] == NULL)
1649*0Sstevel@tonic-gate 			break;
1650*0Sstevel@tonic-gate 	}
1651*0Sstevel@tonic-gate 
1652*0Sstevel@tonic-gate 	if (i == session_table_count || session_table_count == 0) {
1653*0Sstevel@tonic-gate 		if ((rv = grow_session_table(cm)) != CRYPTO_SUCCESS) {
1654*0Sstevel@tonic-gate 			crypto_release_provider_session(cm, ps);
1655*0Sstevel@tonic-gate 			mutex_exit(&cm->cm_lock);
1656*0Sstevel@tonic-gate 			crypto_release_minor(cm);
1657*0Sstevel@tonic-gate 			return (rv);
1658*0Sstevel@tonic-gate 		}
1659*0Sstevel@tonic-gate 		goto again;
1660*0Sstevel@tonic-gate 	}
1661*0Sstevel@tonic-gate 
1662*0Sstevel@tonic-gate 	sp = kmem_cache_alloc(crypto_session_cache, KM_SLEEP);
1663*0Sstevel@tonic-gate 	sp->sd_flags = 0;
1664*0Sstevel@tonic-gate 	sp->sd_find_init_cookie = NULL;
1665*0Sstevel@tonic-gate 	sp->sd_digest_ctx = NULL;
1666*0Sstevel@tonic-gate 	sp->sd_encr_ctx = NULL;
1667*0Sstevel@tonic-gate 	sp->sd_decr_ctx = NULL;
1668*0Sstevel@tonic-gate 	sp->sd_sign_ctx = NULL;
1669*0Sstevel@tonic-gate 	sp->sd_verify_ctx = NULL;
1670*0Sstevel@tonic-gate 	sp->sd_sign_recover_ctx = NULL;
1671*0Sstevel@tonic-gate 	sp->sd_verify_recover_ctx = NULL;
1672*0Sstevel@tonic-gate 	mutex_init(&sp->sd_lock, NULL, MUTEX_DRIVER, NULL);
1673*0Sstevel@tonic-gate 	cv_init(&sp->sd_cv, NULL, CV_DRIVER, NULL);
1674*0Sstevel@tonic-gate 	KCF_PROV_REFHOLD(provider);
1675*0Sstevel@tonic-gate 	sp->sd_provider = provider;
1676*0Sstevel@tonic-gate 	sp->sd_provider_session = ps;
1677*0Sstevel@tonic-gate 	cm->cm_session_table[i] = sp;
1678*0Sstevel@tonic-gate 	mutex_exit(&cm->cm_lock);
1679*0Sstevel@tonic-gate 	crypto_release_minor(cm);
1680*0Sstevel@tonic-gate 	*session_index = i;
1681*0Sstevel@tonic-gate 
1682*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
1683*0Sstevel@tonic-gate }
1684*0Sstevel@tonic-gate 
1685*0Sstevel@tonic-gate /*
1686*0Sstevel@tonic-gate  * Close a session.
1687*0Sstevel@tonic-gate  */
1688*0Sstevel@tonic-gate static int
1689*0Sstevel@tonic-gate crypto_close_session(dev_t dev, crypto_session_id_t session_index)
1690*0Sstevel@tonic-gate {
1691*0Sstevel@tonic-gate 	crypto_session_data_t **session_table;
1692*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
1693*0Sstevel@tonic-gate 	crypto_minor_t *cm;
1694*0Sstevel@tonic-gate 
1695*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
1696*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "crypto_close_session: failed holding minor");
1697*0Sstevel@tonic-gate 		return (CRYPTO_FAILED);
1698*0Sstevel@tonic-gate 	}
1699*0Sstevel@tonic-gate 
1700*0Sstevel@tonic-gate 	mutex_enter(&cm->cm_lock);
1701*0Sstevel@tonic-gate 	session_table = cm->cm_session_table;
1702*0Sstevel@tonic-gate 
1703*0Sstevel@tonic-gate 	if ((session_index) == 0 ||
1704*0Sstevel@tonic-gate 	    (session_index >= cm->cm_session_table_count)) {
1705*0Sstevel@tonic-gate 		mutex_exit(&cm->cm_lock);
1706*0Sstevel@tonic-gate 		crypto_release_minor(cm);
1707*0Sstevel@tonic-gate 		return (CRYPTO_SESSION_HANDLE_INVALID);
1708*0Sstevel@tonic-gate 	}
1709*0Sstevel@tonic-gate 
1710*0Sstevel@tonic-gate 	sp = session_table[session_index];
1711*0Sstevel@tonic-gate 	if (sp == NULL) {
1712*0Sstevel@tonic-gate 		mutex_exit(&cm->cm_lock);
1713*0Sstevel@tonic-gate 		crypto_release_minor(cm);
1714*0Sstevel@tonic-gate 		return (CRYPTO_SESSION_HANDLE_INVALID);
1715*0Sstevel@tonic-gate 	}
1716*0Sstevel@tonic-gate 	/*
1717*0Sstevel@tonic-gate 	 * If session is in use, free it when the thread
1718*0Sstevel@tonic-gate 	 * finishes with the session.
1719*0Sstevel@tonic-gate 	 */
1720*0Sstevel@tonic-gate 	mutex_enter(&sp->sd_lock);
1721*0Sstevel@tonic-gate 	if (sp->sd_flags & CRYPTO_SESSION_IS_BUSY) {
1722*0Sstevel@tonic-gate 		sp->sd_flags |= CRYPTO_SESSION_IS_CLOSED;
1723*0Sstevel@tonic-gate 		mutex_exit(&sp->sd_lock);
1724*0Sstevel@tonic-gate 	} else {
1725*0Sstevel@tonic-gate 		if (sp->sd_find_init_cookie != NULL) {
1726*0Sstevel@tonic-gate 			(void) crypto_free_find_ctx(sp);
1727*0Sstevel@tonic-gate 		}
1728*0Sstevel@tonic-gate 
1729*0Sstevel@tonic-gate 		crypto_release_provider_session(cm, sp->sd_provider_session);
1730*0Sstevel@tonic-gate 		KCF_PROV_REFRELE(sp->sd_provider);
1731*0Sstevel@tonic-gate 		CRYPTO_CANCEL_ALL_CTX(sp);
1732*0Sstevel@tonic-gate 		mutex_destroy(&sp->sd_lock);
1733*0Sstevel@tonic-gate 		cv_destroy(&sp->sd_cv);
1734*0Sstevel@tonic-gate 		kmem_cache_free(crypto_session_cache, sp);
1735*0Sstevel@tonic-gate 		session_table[session_index] = NULL;
1736*0Sstevel@tonic-gate 	}
1737*0Sstevel@tonic-gate 
1738*0Sstevel@tonic-gate 	mutex_exit(&cm->cm_lock);
1739*0Sstevel@tonic-gate 	crypto_release_minor(cm);
1740*0Sstevel@tonic-gate 
1741*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
1742*0Sstevel@tonic-gate }
1743*0Sstevel@tonic-gate 
1744*0Sstevel@tonic-gate /*
1745*0Sstevel@tonic-gate  * This ioctl opens a session and returns the session ID in os_session.
1746*0Sstevel@tonic-gate  */
1747*0Sstevel@tonic-gate /* ARGSUSED */
1748*0Sstevel@tonic-gate static int
1749*0Sstevel@tonic-gate open_session(dev_t dev, caddr_t arg, int mode, int *rval)
1750*0Sstevel@tonic-gate {
1751*0Sstevel@tonic-gate 	crypto_open_session_t open_session;
1752*0Sstevel@tonic-gate 	crypto_session_id_t session;
1753*0Sstevel@tonic-gate 	int rv;
1754*0Sstevel@tonic-gate 
1755*0Sstevel@tonic-gate 	if (copyin(arg, &open_session, sizeof (open_session)) != 0)
1756*0Sstevel@tonic-gate 		return (EFAULT);
1757*0Sstevel@tonic-gate 
1758*0Sstevel@tonic-gate 	rv = crypto_open_session(dev, open_session.os_flags,
1759*0Sstevel@tonic-gate 	    &session, open_session.os_provider_id);
1760*0Sstevel@tonic-gate 	if (rv != CRYPTO_SUCCESS) {
1761*0Sstevel@tonic-gate 		open_session.os_return_value = rv;
1762*0Sstevel@tonic-gate 		if (copyout(&open_session, arg, sizeof (open_session)) != 0) {
1763*0Sstevel@tonic-gate 			return (EFAULT);
1764*0Sstevel@tonic-gate 		}
1765*0Sstevel@tonic-gate 		return (0);
1766*0Sstevel@tonic-gate 	}
1767*0Sstevel@tonic-gate 
1768*0Sstevel@tonic-gate 	open_session.os_session = session;
1769*0Sstevel@tonic-gate 	open_session.os_return_value = CRYPTO_SUCCESS;
1770*0Sstevel@tonic-gate 
1771*0Sstevel@tonic-gate 	if (copyout(&open_session, arg, sizeof (open_session)) != 0) {
1772*0Sstevel@tonic-gate 		return (EFAULT);
1773*0Sstevel@tonic-gate 	}
1774*0Sstevel@tonic-gate 	return (0);
1775*0Sstevel@tonic-gate }
1776*0Sstevel@tonic-gate 
1777*0Sstevel@tonic-gate /*
1778*0Sstevel@tonic-gate  * This ioctl closes a session.
1779*0Sstevel@tonic-gate  */
1780*0Sstevel@tonic-gate /* ARGSUSED */
1781*0Sstevel@tonic-gate static int
1782*0Sstevel@tonic-gate close_session(dev_t dev, caddr_t arg, int mode, int *rval)
1783*0Sstevel@tonic-gate {
1784*0Sstevel@tonic-gate 	crypto_close_session_t close_session;
1785*0Sstevel@tonic-gate 	int rv;
1786*0Sstevel@tonic-gate 
1787*0Sstevel@tonic-gate 	if (copyin(arg, &close_session, sizeof (close_session)) != 0)
1788*0Sstevel@tonic-gate 		return (EFAULT);
1789*0Sstevel@tonic-gate 
1790*0Sstevel@tonic-gate 	rv = crypto_close_session(dev, close_session.cs_session);
1791*0Sstevel@tonic-gate 	if (rv != CRYPTO_SUCCESS) {
1792*0Sstevel@tonic-gate 		close_session.cs_return_value = rv;
1793*0Sstevel@tonic-gate 		if (copyout(&close_session, arg, sizeof (close_session)) != 0) {
1794*0Sstevel@tonic-gate 			return (EFAULT);
1795*0Sstevel@tonic-gate 		}
1796*0Sstevel@tonic-gate 		return (0);
1797*0Sstevel@tonic-gate 	}
1798*0Sstevel@tonic-gate 
1799*0Sstevel@tonic-gate 	close_session.cs_return_value = CRYPTO_SUCCESS;
1800*0Sstevel@tonic-gate 
1801*0Sstevel@tonic-gate 	if (copyout(&close_session, arg, sizeof (close_session)) != 0) {
1802*0Sstevel@tonic-gate 		return (EFAULT);
1803*0Sstevel@tonic-gate 	}
1804*0Sstevel@tonic-gate 	return (0);
1805*0Sstevel@tonic-gate }
1806*0Sstevel@tonic-gate 
1807*0Sstevel@tonic-gate /*
1808*0Sstevel@tonic-gate  * Copy data model dependent mechanism structure into a kernel mechanism
1809*0Sstevel@tonic-gate  * structure.  Allocate param storage if necessary.
1810*0Sstevel@tonic-gate  */
1811*0Sstevel@tonic-gate static boolean_t
1812*0Sstevel@tonic-gate copyin_mech(int mode, crypto_mechanism_t *in_mech,
1813*0Sstevel@tonic-gate     crypto_mechanism_t *out_mech, size_t *out_rctl_bytes, size_t *out_carry,
1814*0Sstevel@tonic-gate     int *out_rv, int *out_error, kproject_t **projp)
1815*0Sstevel@tonic-gate {
1816*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_mechanism, mech);
1817*0Sstevel@tonic-gate 	caddr_t param;
1818*0Sstevel@tonic-gate 	size_t param_len;
1819*0Sstevel@tonic-gate 	size_t rctl_bytes = 0, carry = 0;
1820*0Sstevel@tonic-gate 	int error = 0;
1821*0Sstevel@tonic-gate 	int rv = 0;
1822*0Sstevel@tonic-gate 
1823*0Sstevel@tonic-gate 	STRUCT_INIT(mech, mode);
1824*0Sstevel@tonic-gate 	bcopy(in_mech, STRUCT_BUF(mech), STRUCT_SIZE(mech));
1825*0Sstevel@tonic-gate 	param = STRUCT_FGETP(mech, cm_param);
1826*0Sstevel@tonic-gate 	param_len = STRUCT_FGET(mech, cm_param_len);
1827*0Sstevel@tonic-gate 	out_mech->cm_type = STRUCT_FGET(mech, cm_type);
1828*0Sstevel@tonic-gate 	out_mech->cm_param = NULL;
1829*0Sstevel@tonic-gate 	out_mech->cm_param_len = 0;
1830*0Sstevel@tonic-gate 	if (param != NULL && param_len != 0) {
1831*0Sstevel@tonic-gate 		if (param_len > crypto_max_buffer_len) {
1832*0Sstevel@tonic-gate 			cmn_err(CE_NOTE, "copyin_mech: buffer greater than "
1833*0Sstevel@tonic-gate 			    "%ld bytes, pid = %d", crypto_max_buffer_len,
1834*0Sstevel@tonic-gate 			    curproc->p_pid);
1835*0Sstevel@tonic-gate 			rv = CRYPTO_ARGUMENTS_BAD;
1836*0Sstevel@tonic-gate 			goto out;
1837*0Sstevel@tonic-gate 		}
1838*0Sstevel@tonic-gate 
1839*0Sstevel@tonic-gate 		/*
1840*0Sstevel@tonic-gate 		 * Most calls to copyin_mech() are followed by a call to
1841*0Sstevel@tonic-gate 		 * copyin_key(), resulting in two resource control checks.
1842*0Sstevel@tonic-gate 		 * As an optimization, the resource control check is not
1843*0Sstevel@tonic-gate 		 * made in this function if the check is for less than
1844*0Sstevel@tonic-gate 		 * CRYPTO_DEFERRED_LIMIT bytes. The number of bytes that
1845*0Sstevel@tonic-gate 		 * would be checked is passed as an argument to copyin_key()
1846*0Sstevel@tonic-gate 		 * where the check is made, and the bytes are charged against
1847*0Sstevel@tonic-gate 		 * the project.max-crypto-memory resource control.
1848*0Sstevel@tonic-gate 		 */
1849*0Sstevel@tonic-gate 		if ((param_len > CRYPTO_DEFERRED_LIMIT) || out_carry == NULL) {
1850*0Sstevel@tonic-gate 			rv = crypto_buffer_check(param_len, projp);
1851*0Sstevel@tonic-gate 			if (rv != CRYPTO_SUCCESS) {
1852*0Sstevel@tonic-gate 				goto out;
1853*0Sstevel@tonic-gate 			}
1854*0Sstevel@tonic-gate 			rctl_bytes = param_len;
1855*0Sstevel@tonic-gate 		} else {
1856*0Sstevel@tonic-gate 			carry = param_len;
1857*0Sstevel@tonic-gate 		}
1858*0Sstevel@tonic-gate 		out_mech->cm_param = kmem_alloc(param_len, KM_SLEEP);
1859*0Sstevel@tonic-gate 		if (copyin((char *)param, out_mech->cm_param, param_len) != 0) {
1860*0Sstevel@tonic-gate 			kmem_free(out_mech->cm_param, param_len);
1861*0Sstevel@tonic-gate 			out_mech->cm_param = NULL;
1862*0Sstevel@tonic-gate 			error = EFAULT;
1863*0Sstevel@tonic-gate 			goto out;
1864*0Sstevel@tonic-gate 		}
1865*0Sstevel@tonic-gate 		out_mech->cm_param_len = param_len;
1866*0Sstevel@tonic-gate 	}
1867*0Sstevel@tonic-gate out:
1868*0Sstevel@tonic-gate 	*out_rctl_bytes = rctl_bytes;
1869*0Sstevel@tonic-gate 	*out_rv = rv;
1870*0Sstevel@tonic-gate 	*out_error = error;
1871*0Sstevel@tonic-gate 	if (out_carry != NULL)
1872*0Sstevel@tonic-gate 		*out_carry = carry;
1873*0Sstevel@tonic-gate 	return ((rv | error) ? B_FALSE : B_TRUE);
1874*0Sstevel@tonic-gate }
1875*0Sstevel@tonic-gate 
1876*0Sstevel@tonic-gate /*
1877*0Sstevel@tonic-gate  * Free key attributes when key type is CRYPTO_KEY_ATTR_LIST.
1878*0Sstevel@tonic-gate  * The crypto_key structure is not freed.
1879*0Sstevel@tonic-gate  */
1880*0Sstevel@tonic-gate static void
1881*0Sstevel@tonic-gate crypto_free_key_attributes(crypto_key_t *key)
1882*0Sstevel@tonic-gate {
1883*0Sstevel@tonic-gate 	crypto_object_attribute_t *attrs;
1884*0Sstevel@tonic-gate 	size_t len = 0;
1885*0Sstevel@tonic-gate 	int i;
1886*0Sstevel@tonic-gate 
1887*0Sstevel@tonic-gate 	ASSERT(key->ck_format == CRYPTO_KEY_ATTR_LIST);
1888*0Sstevel@tonic-gate 	if (key->ck_count == 0 || key->ck_attrs == NULL)
1889*0Sstevel@tonic-gate 		return;
1890*0Sstevel@tonic-gate 
1891*0Sstevel@tonic-gate 	/* compute the size of the container */
1892*0Sstevel@tonic-gate 	len = key->ck_count * sizeof (crypto_object_attribute_t);
1893*0Sstevel@tonic-gate 
1894*0Sstevel@tonic-gate 	/* total up the size of all attributes in the container */
1895*0Sstevel@tonic-gate 	for (i = 0; i < key->ck_count; i++) {
1896*0Sstevel@tonic-gate 		attrs = &key->ck_attrs[i];
1897*0Sstevel@tonic-gate 		if (attrs->oa_value_len != 0 &&
1898*0Sstevel@tonic-gate 		    attrs->oa_value != NULL) {
1899*0Sstevel@tonic-gate 			len += roundup(attrs->oa_value_len, sizeof (caddr_t));
1900*0Sstevel@tonic-gate 		}
1901*0Sstevel@tonic-gate 	}
1902*0Sstevel@tonic-gate 
1903*0Sstevel@tonic-gate 	bzero(key->ck_attrs, len);
1904*0Sstevel@tonic-gate 	kmem_free(key->ck_attrs, len);
1905*0Sstevel@tonic-gate }
1906*0Sstevel@tonic-gate 
1907*0Sstevel@tonic-gate /*
1908*0Sstevel@tonic-gate  * Frees allocated storage in the key structure, but doesn't free
1909*0Sstevel@tonic-gate  * the key structure.
1910*0Sstevel@tonic-gate  */
1911*0Sstevel@tonic-gate static void
1912*0Sstevel@tonic-gate free_crypto_key(crypto_key_t *key)
1913*0Sstevel@tonic-gate {
1914*0Sstevel@tonic-gate 	switch (key->ck_format) {
1915*0Sstevel@tonic-gate 	case CRYPTO_KEY_RAW: {
1916*0Sstevel@tonic-gate 		size_t len;
1917*0Sstevel@tonic-gate 
1918*0Sstevel@tonic-gate 		if (key->ck_length == 0 || key->ck_data == NULL)
1919*0Sstevel@tonic-gate 			break;
1920*0Sstevel@tonic-gate 
1921*0Sstevel@tonic-gate 		len = CRYPTO_BITS2BYTES(key->ck_length);
1922*0Sstevel@tonic-gate 		bzero(key->ck_data, len);
1923*0Sstevel@tonic-gate 		kmem_free(key->ck_data, len);
1924*0Sstevel@tonic-gate 		break;
1925*0Sstevel@tonic-gate 	}
1926*0Sstevel@tonic-gate 
1927*0Sstevel@tonic-gate 	case CRYPTO_KEY_ATTR_LIST:
1928*0Sstevel@tonic-gate 		crypto_free_key_attributes(key);
1929*0Sstevel@tonic-gate 		break;
1930*0Sstevel@tonic-gate 
1931*0Sstevel@tonic-gate 	default:
1932*0Sstevel@tonic-gate 		break;
1933*0Sstevel@tonic-gate 	}
1934*0Sstevel@tonic-gate }
1935*0Sstevel@tonic-gate 
1936*0Sstevel@tonic-gate /*
1937*0Sstevel@tonic-gate  * Copy in an array of crypto_object_attribute structures from user-space.
1938*0Sstevel@tonic-gate  * Kernel memory is allocated for the array and the value of each attribute
1939*0Sstevel@tonic-gate  * in the array.  Since unprivileged users can specify the size of attributes,
1940*0Sstevel@tonic-gate  * the amount of memory needed is charged against the
1941*0Sstevel@tonic-gate  * project.max-crypto-memory resource control.
1942*0Sstevel@tonic-gate  *
1943*0Sstevel@tonic-gate  * Attribute values are copied in from user-space if copyin_value is set to
1944*0Sstevel@tonic-gate  * B_TRUE.  This routine returns B_TRUE if the copyin was successful.
1945*0Sstevel@tonic-gate  */
1946*0Sstevel@tonic-gate static boolean_t
1947*0Sstevel@tonic-gate copyin_attributes(int mode, uint_t count, caddr_t oc_attributes,
1948*0Sstevel@tonic-gate     crypto_object_attribute_t **k_attrs_out, size_t *k_attrs_size_out,
1949*0Sstevel@tonic-gate     caddr_t *u_attrs_out, int *out_rv, int *out_error, size_t *out_rctl_bytes,
1950*0Sstevel@tonic-gate     size_t carry, boolean_t copyin_value, kproject_t **projp)
1951*0Sstevel@tonic-gate {
1952*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_attribute, oa);
1953*0Sstevel@tonic-gate 	crypto_object_attribute_t *k_attrs = NULL;
1954*0Sstevel@tonic-gate 	caddr_t attrs = NULL, ap, p, value;
1955*0Sstevel@tonic-gate 	caddr_t k_attrs_buf;
1956*0Sstevel@tonic-gate 	size_t k_attrs_len;
1957*0Sstevel@tonic-gate 	size_t k_attrs_buf_len = 0;
1958*0Sstevel@tonic-gate 	size_t k_attrs_total_len = 0;
1959*0Sstevel@tonic-gate 	size_t tmp_len;
1960*0Sstevel@tonic-gate 	size_t rctl_bytes = 0;
1961*0Sstevel@tonic-gate 	size_t len = 0;
1962*0Sstevel@tonic-gate 	size_t value_len;
1963*0Sstevel@tonic-gate 	int error = 0;
1964*0Sstevel@tonic-gate 	int rv = 0;
1965*0Sstevel@tonic-gate 	int i;
1966*0Sstevel@tonic-gate 
1967*0Sstevel@tonic-gate 	STRUCT_INIT(oa, mode);
1968*0Sstevel@tonic-gate 
1969*0Sstevel@tonic-gate 	if (count == 0) {
1970*0Sstevel@tonic-gate 		rv = CRYPTO_SUCCESS;
1971*0Sstevel@tonic-gate 		goto out;
1972*0Sstevel@tonic-gate 	}
1973*0Sstevel@tonic-gate 
1974*0Sstevel@tonic-gate 	if (count > CRYPTO_MAX_ATTRIBUTE_COUNT) {
1975*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
1976*0Sstevel@tonic-gate 		goto out;
1977*0Sstevel@tonic-gate 	}
1978*0Sstevel@tonic-gate 
1979*0Sstevel@tonic-gate 	/* compute size of crypto_object_attribute array */
1980*0Sstevel@tonic-gate 	len = count * STRUCT_SIZE(oa);
1981*0Sstevel@tonic-gate 
1982*0Sstevel@tonic-gate 	/* this allocation is not charged against the user's resource limit */
1983*0Sstevel@tonic-gate 	attrs = kmem_alloc(len, KM_SLEEP);
1984*0Sstevel@tonic-gate 	if (copyin(oc_attributes, attrs, len) != 0) {
1985*0Sstevel@tonic-gate 		error = EFAULT;
1986*0Sstevel@tonic-gate 		goto out;
1987*0Sstevel@tonic-gate 	}
1988*0Sstevel@tonic-gate 
1989*0Sstevel@tonic-gate 	/* figure out how much memory to allocate for all of the attributes */
1990*0Sstevel@tonic-gate 	ap = attrs;
1991*0Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
1992*0Sstevel@tonic-gate 		bcopy(ap, STRUCT_BUF(oa), STRUCT_SIZE(oa));
1993*0Sstevel@tonic-gate 		tmp_len = roundup(STRUCT_FGET(oa, oa_value_len),
1994*0Sstevel@tonic-gate 		    sizeof (caddr_t));
1995*0Sstevel@tonic-gate 		if (tmp_len > crypto_max_buffer_len) {
1996*0Sstevel@tonic-gate 			cmn_err(CE_NOTE, "copyin_attributes: buffer greater "
1997*0Sstevel@tonic-gate 			    "than %ld bytes, pid = %d", crypto_max_buffer_len,
1998*0Sstevel@tonic-gate 			    curproc->p_pid);
1999*0Sstevel@tonic-gate 			rv = CRYPTO_ARGUMENTS_BAD;
2000*0Sstevel@tonic-gate 			goto out;
2001*0Sstevel@tonic-gate 		}
2002*0Sstevel@tonic-gate 		if (STRUCT_FGETP(oa, oa_value) != NULL)
2003*0Sstevel@tonic-gate 			k_attrs_buf_len += tmp_len;
2004*0Sstevel@tonic-gate 		ap += STRUCT_SIZE(oa);
2005*0Sstevel@tonic-gate 	}
2006*0Sstevel@tonic-gate 
2007*0Sstevel@tonic-gate 	k_attrs_len = count * sizeof (crypto_object_attribute_t);
2008*0Sstevel@tonic-gate 	k_attrs_total_len = k_attrs_buf_len + k_attrs_len;
2009*0Sstevel@tonic-gate 	if ((k_attrs_total_len + carry) != 0) {
2010*0Sstevel@tonic-gate 		rv = crypto_buffer_check(k_attrs_total_len + carry, projp);
2011*0Sstevel@tonic-gate 		if (rv != CRYPTO_SUCCESS) {
2012*0Sstevel@tonic-gate 			goto out;
2013*0Sstevel@tonic-gate 		}
2014*0Sstevel@tonic-gate 	}
2015*0Sstevel@tonic-gate 	rctl_bytes = k_attrs_total_len + carry;
2016*0Sstevel@tonic-gate 
2017*0Sstevel@tonic-gate 	/* one big allocation for everything */
2018*0Sstevel@tonic-gate 	k_attrs = kmem_alloc(k_attrs_total_len, KM_SLEEP);
2019*0Sstevel@tonic-gate 	k_attrs_buf = (char *)k_attrs + k_attrs_len;
2020*0Sstevel@tonic-gate 
2021*0Sstevel@tonic-gate 	ap = attrs;
2022*0Sstevel@tonic-gate 	p = k_attrs_buf;
2023*0Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
2024*0Sstevel@tonic-gate 		bcopy(ap, STRUCT_BUF(oa), STRUCT_SIZE(oa));
2025*0Sstevel@tonic-gate 		k_attrs[i].oa_type = STRUCT_FGET(oa, oa_type);
2026*0Sstevel@tonic-gate 		value = STRUCT_FGETP(oa, oa_value);
2027*0Sstevel@tonic-gate 		value_len = STRUCT_FGET(oa, oa_value_len);
2028*0Sstevel@tonic-gate 		if (value != NULL && value_len != 0 && copyin_value) {
2029*0Sstevel@tonic-gate 			if (copyin(value, p, value_len) != 0) {
2030*0Sstevel@tonic-gate 				kmem_free(k_attrs, k_attrs_total_len);
2031*0Sstevel@tonic-gate 				k_attrs = NULL;
2032*0Sstevel@tonic-gate 				error = EFAULT;
2033*0Sstevel@tonic-gate 				goto out;
2034*0Sstevel@tonic-gate 			}
2035*0Sstevel@tonic-gate 		}
2036*0Sstevel@tonic-gate 
2037*0Sstevel@tonic-gate 		k_attrs[i].oa_value = (value == NULL) ? NULL : p;
2038*0Sstevel@tonic-gate 		k_attrs[i].oa_value_len = value_len;
2039*0Sstevel@tonic-gate 		ap += STRUCT_SIZE(oa);
2040*0Sstevel@tonic-gate 		p += roundup(value_len, sizeof (caddr_t));
2041*0Sstevel@tonic-gate 	}
2042*0Sstevel@tonic-gate out:
2043*0Sstevel@tonic-gate 	if (attrs != NULL) {
2044*0Sstevel@tonic-gate 		/*
2045*0Sstevel@tonic-gate 		 * Free the array if there is a failure or the caller
2046*0Sstevel@tonic-gate 		 * doesn't want the array to be returned.
2047*0Sstevel@tonic-gate 		 */
2048*0Sstevel@tonic-gate 		if (error != 0 || rv != CRYPTO_SUCCESS || u_attrs_out == NULL) {
2049*0Sstevel@tonic-gate 			kmem_free(attrs, len);
2050*0Sstevel@tonic-gate 			attrs = NULL;
2051*0Sstevel@tonic-gate 		}
2052*0Sstevel@tonic-gate 	}
2053*0Sstevel@tonic-gate 
2054*0Sstevel@tonic-gate 	if (u_attrs_out != NULL)
2055*0Sstevel@tonic-gate 		*u_attrs_out = attrs;
2056*0Sstevel@tonic-gate 	if (k_attrs_size_out != NULL)
2057*0Sstevel@tonic-gate 		*k_attrs_size_out = k_attrs_total_len;
2058*0Sstevel@tonic-gate 	*k_attrs_out = k_attrs;
2059*0Sstevel@tonic-gate 	*out_rctl_bytes = rctl_bytes;
2060*0Sstevel@tonic-gate 	*out_rv = rv;
2061*0Sstevel@tonic-gate 	*out_error = error;
2062*0Sstevel@tonic-gate 	return ((rv | error) ? B_FALSE : B_TRUE);
2063*0Sstevel@tonic-gate }
2064*0Sstevel@tonic-gate 
2065*0Sstevel@tonic-gate /*
2066*0Sstevel@tonic-gate  * Copy data model dependent raw key into a kernel key
2067*0Sstevel@tonic-gate  * structure.  Checks key length or attribute lengths against
2068*0Sstevel@tonic-gate  * resource controls before allocating memory.  Returns B_TRUE
2069*0Sstevel@tonic-gate  * if both error and rv are set to 0.
2070*0Sstevel@tonic-gate  */
2071*0Sstevel@tonic-gate static boolean_t
2072*0Sstevel@tonic-gate copyin_key(int mode, crypto_key_t *in_key, crypto_key_t *out_key,
2073*0Sstevel@tonic-gate     size_t *out_rctl_bytes, int *out_rv, int *out_error, size_t carry,
2074*0Sstevel@tonic-gate     kproject_t **projp)
2075*0Sstevel@tonic-gate {
2076*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_key, key);
2077*0Sstevel@tonic-gate 	crypto_object_attribute_t *k_attrs = NULL;
2078*0Sstevel@tonic-gate 	size_t key_bits;
2079*0Sstevel@tonic-gate 	size_t key_bytes = 0;
2080*0Sstevel@tonic-gate 	size_t rctl_bytes = 0;
2081*0Sstevel@tonic-gate 	int count;
2082*0Sstevel@tonic-gate 	int error = 0;
2083*0Sstevel@tonic-gate 	int rv = CRYPTO_SUCCESS;
2084*0Sstevel@tonic-gate 
2085*0Sstevel@tonic-gate 	STRUCT_INIT(key, mode);
2086*0Sstevel@tonic-gate 	bcopy(in_key, STRUCT_BUF(key), STRUCT_SIZE(key));
2087*0Sstevel@tonic-gate 	out_key->ck_format = STRUCT_FGET(key, ck_format);
2088*0Sstevel@tonic-gate 	switch (out_key->ck_format) {
2089*0Sstevel@tonic-gate 	case CRYPTO_KEY_RAW:
2090*0Sstevel@tonic-gate 		key_bits = STRUCT_FGET(key, ck_length);
2091*0Sstevel@tonic-gate 		if (key_bits != 0) {
2092*0Sstevel@tonic-gate 			key_bytes = CRYPTO_BITS2BYTES(key_bits);
2093*0Sstevel@tonic-gate 			if (key_bytes > crypto_max_buffer_len) {
2094*0Sstevel@tonic-gate 				cmn_err(CE_NOTE, "copyin_key: buffer greater "
2095*0Sstevel@tonic-gate 				    "than %ld bytes, pid = %d",
2096*0Sstevel@tonic-gate 				    crypto_max_buffer_len, curproc->p_pid);
2097*0Sstevel@tonic-gate 				rv = CRYPTO_ARGUMENTS_BAD;
2098*0Sstevel@tonic-gate 				goto out;
2099*0Sstevel@tonic-gate 			}
2100*0Sstevel@tonic-gate 
2101*0Sstevel@tonic-gate 			rv = crypto_buffer_check(key_bytes + carry, projp);
2102*0Sstevel@tonic-gate 			if (rv != CRYPTO_SUCCESS) {
2103*0Sstevel@tonic-gate 				goto out;
2104*0Sstevel@tonic-gate 			}
2105*0Sstevel@tonic-gate 			rctl_bytes = key_bytes + carry;
2106*0Sstevel@tonic-gate 
2107*0Sstevel@tonic-gate 			out_key->ck_data = kmem_alloc(key_bytes, KM_SLEEP);
2108*0Sstevel@tonic-gate 
2109*0Sstevel@tonic-gate 			if (copyin((char *)STRUCT_FGETP(key, ck_data),
2110*0Sstevel@tonic-gate 			    out_key->ck_data, key_bytes) != 0) {
2111*0Sstevel@tonic-gate 				kmem_free(out_key->ck_data, key_bytes);
2112*0Sstevel@tonic-gate 				out_key->ck_data = NULL;
2113*0Sstevel@tonic-gate 				out_key->ck_length = 0;
2114*0Sstevel@tonic-gate 				error = EFAULT;
2115*0Sstevel@tonic-gate 				goto out;
2116*0Sstevel@tonic-gate 			}
2117*0Sstevel@tonic-gate 		}
2118*0Sstevel@tonic-gate 		out_key->ck_length = key_bits;
2119*0Sstevel@tonic-gate 		break;
2120*0Sstevel@tonic-gate 
2121*0Sstevel@tonic-gate 	case CRYPTO_KEY_ATTR_LIST:
2122*0Sstevel@tonic-gate 		count = STRUCT_FGET(key, ck_count);
2123*0Sstevel@tonic-gate 
2124*0Sstevel@tonic-gate 		if (copyin_attributes(mode, count,
2125*0Sstevel@tonic-gate 		    (caddr_t)STRUCT_FGETP(key, ck_attrs), &k_attrs, NULL, NULL,
2126*0Sstevel@tonic-gate 		    &rv, &error, &rctl_bytes, carry, B_TRUE, projp)) {
2127*0Sstevel@tonic-gate 			out_key->ck_count = count;
2128*0Sstevel@tonic-gate 			out_key->ck_attrs = k_attrs;
2129*0Sstevel@tonic-gate 			k_attrs = NULL;
2130*0Sstevel@tonic-gate 		} else {
2131*0Sstevel@tonic-gate 			out_key->ck_count = 0;
2132*0Sstevel@tonic-gate 			out_key->ck_attrs = NULL;
2133*0Sstevel@tonic-gate 		}
2134*0Sstevel@tonic-gate 		break;
2135*0Sstevel@tonic-gate 
2136*0Sstevel@tonic-gate 	case CRYPTO_KEY_REFERENCE:
2137*0Sstevel@tonic-gate 		out_key->ck_obj_id = STRUCT_FGET(key, ck_obj_id);
2138*0Sstevel@tonic-gate 		break;
2139*0Sstevel@tonic-gate 
2140*0Sstevel@tonic-gate 	default:
2141*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
2142*0Sstevel@tonic-gate 	}
2143*0Sstevel@tonic-gate 
2144*0Sstevel@tonic-gate out:
2145*0Sstevel@tonic-gate 	*out_rctl_bytes = rctl_bytes;
2146*0Sstevel@tonic-gate 	*out_rv = rv;
2147*0Sstevel@tonic-gate 	*out_error = error;
2148*0Sstevel@tonic-gate 	return ((rv | error) ? B_FALSE : B_TRUE);
2149*0Sstevel@tonic-gate }
2150*0Sstevel@tonic-gate 
2151*0Sstevel@tonic-gate /*
2152*0Sstevel@tonic-gate  * This routine does two things:
2153*0Sstevel@tonic-gate  * 1. Given a crypto_minor structure and a session ID, it returns
2154*0Sstevel@tonic-gate  *    a valid session pointer.
2155*0Sstevel@tonic-gate  * 2. It checks that the provider, to which the session has been opened,
2156*0Sstevel@tonic-gate  *    has not been removed.
2157*0Sstevel@tonic-gate  */
2158*0Sstevel@tonic-gate static boolean_t
2159*0Sstevel@tonic-gate get_session_ptr(crypto_session_id_t i, crypto_minor_t *cm,
2160*0Sstevel@tonic-gate     crypto_session_data_t **session_ptr, int *out_error, int *out_rv)
2161*0Sstevel@tonic-gate {
2162*0Sstevel@tonic-gate 	crypto_session_data_t *sp = NULL;
2163*0Sstevel@tonic-gate 	int rv = CRYPTO_SESSION_HANDLE_INVALID;
2164*0Sstevel@tonic-gate 	int error = 0;
2165*0Sstevel@tonic-gate 
2166*0Sstevel@tonic-gate 	mutex_enter(&cm->cm_lock);
2167*0Sstevel@tonic-gate 	if ((i < cm->cm_session_table_count) &&
2168*0Sstevel@tonic-gate 	    (cm->cm_session_table[i] != NULL)) {
2169*0Sstevel@tonic-gate 		sp = cm->cm_session_table[i];
2170*0Sstevel@tonic-gate 		mutex_enter(&sp->sd_lock);
2171*0Sstevel@tonic-gate 		mutex_exit(&cm->cm_lock);
2172*0Sstevel@tonic-gate 		while (sp->sd_flags & CRYPTO_SESSION_IS_BUSY) {
2173*0Sstevel@tonic-gate 			if (cv_wait_sig(&sp->sd_cv, &sp->sd_lock) == 0) {
2174*0Sstevel@tonic-gate 				mutex_exit(&sp->sd_lock);
2175*0Sstevel@tonic-gate 				sp = NULL;
2176*0Sstevel@tonic-gate 				error = EINTR;
2177*0Sstevel@tonic-gate 				goto out;
2178*0Sstevel@tonic-gate 			}
2179*0Sstevel@tonic-gate 		}
2180*0Sstevel@tonic-gate 
2181*0Sstevel@tonic-gate 		if (sp->sd_flags & CRYPTO_SESSION_IS_CLOSED) {
2182*0Sstevel@tonic-gate 			mutex_exit(&sp->sd_lock);
2183*0Sstevel@tonic-gate 			sp = NULL;
2184*0Sstevel@tonic-gate 			goto out;
2185*0Sstevel@tonic-gate 		}
2186*0Sstevel@tonic-gate 
2187*0Sstevel@tonic-gate 		if (KCF_IS_PROV_REMOVED(sp->sd_provider)) {
2188*0Sstevel@tonic-gate 			mutex_exit(&sp->sd_lock);
2189*0Sstevel@tonic-gate 			sp = NULL;
2190*0Sstevel@tonic-gate 			rv = CRYPTO_DEVICE_ERROR;
2191*0Sstevel@tonic-gate 			goto out;
2192*0Sstevel@tonic-gate 		}
2193*0Sstevel@tonic-gate 
2194*0Sstevel@tonic-gate 		rv = CRYPTO_SUCCESS;
2195*0Sstevel@tonic-gate 		sp->sd_flags |= CRYPTO_SESSION_IS_BUSY;
2196*0Sstevel@tonic-gate 		mutex_exit(&sp->sd_lock);
2197*0Sstevel@tonic-gate 	} else {
2198*0Sstevel@tonic-gate 		mutex_exit(&cm->cm_lock);
2199*0Sstevel@tonic-gate 	}
2200*0Sstevel@tonic-gate out:
2201*0Sstevel@tonic-gate 	*session_ptr = sp;
2202*0Sstevel@tonic-gate 	*out_error = error;
2203*0Sstevel@tonic-gate 	*out_rv = rv;
2204*0Sstevel@tonic-gate 	return ((rv == CRYPTO_SUCCESS && error == 0) ? B_TRUE : B_FALSE);
2205*0Sstevel@tonic-gate }
2206*0Sstevel@tonic-gate 
2207*0Sstevel@tonic-gate #define	CRYPTO_SESSION_RELE(s) {			\
2208*0Sstevel@tonic-gate 	mutex_enter(&((s)->sd_lock));			\
2209*0Sstevel@tonic-gate 	(s)->sd_flags &= ~CRYPTO_SESSION_IS_BUSY;	\
2210*0Sstevel@tonic-gate 	cv_broadcast(&(s)->sd_cv);			\
2211*0Sstevel@tonic-gate 	mutex_exit(&((s)->sd_lock));			\
2212*0Sstevel@tonic-gate }
2213*0Sstevel@tonic-gate 
2214*0Sstevel@tonic-gate /* ARGSUSED */
2215*0Sstevel@tonic-gate static int
2216*0Sstevel@tonic-gate encrypt_init(dev_t dev, caddr_t arg, int mode, int *rval)
2217*0Sstevel@tonic-gate {
2218*0Sstevel@tonic-gate 	return (cipher_init(dev, arg, mode, crypto_encrypt_init_prov));
2219*0Sstevel@tonic-gate }
2220*0Sstevel@tonic-gate 
2221*0Sstevel@tonic-gate /* ARGSUSED */
2222*0Sstevel@tonic-gate static int
2223*0Sstevel@tonic-gate decrypt_init(dev_t dev, caddr_t arg, int mode, int *rval)
2224*0Sstevel@tonic-gate {
2225*0Sstevel@tonic-gate 	return (cipher_init(dev, arg, mode, crypto_decrypt_init_prov));
2226*0Sstevel@tonic-gate }
2227*0Sstevel@tonic-gate 
2228*0Sstevel@tonic-gate /*
2229*0Sstevel@tonic-gate  * ASSUMPTION: crypto_encrypt_init and crypto_decrypt_init
2230*0Sstevel@tonic-gate  * structures are identical except for field names.
2231*0Sstevel@tonic-gate  */
2232*0Sstevel@tonic-gate static int
2233*0Sstevel@tonic-gate cipher_init(dev_t dev, caddr_t arg, int mode, int (*init)(kcf_provider_desc_t *,
2234*0Sstevel@tonic-gate     crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
2235*0Sstevel@tonic-gate     crypto_ctx_template_t, crypto_context_t *, crypto_call_req_t *))
2236*0Sstevel@tonic-gate {
2237*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_encrypt_init, encrypt_init);
2238*0Sstevel@tonic-gate 	kproject_t *mech_projp, *key_projp;
2239*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
2240*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
2241*0Sstevel@tonic-gate 	crypto_mechanism_t mech;
2242*0Sstevel@tonic-gate 	crypto_key_t key;
2243*0Sstevel@tonic-gate 	crypto_minor_t *cm;
2244*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
2245*0Sstevel@tonic-gate 	crypto_context_t cc;
2246*0Sstevel@tonic-gate 	crypto_ctx_t **ctxpp;
2247*0Sstevel@tonic-gate 	size_t mech_rctl_bytes = 0;
2248*0Sstevel@tonic-gate 	size_t key_rctl_bytes = 0;
2249*0Sstevel@tonic-gate 	size_t carry;
2250*0Sstevel@tonic-gate 	offset_t offset;
2251*0Sstevel@tonic-gate 	int error = 0;
2252*0Sstevel@tonic-gate 	int rv;
2253*0Sstevel@tonic-gate 
2254*0Sstevel@tonic-gate 	STRUCT_INIT(encrypt_init, mode);
2255*0Sstevel@tonic-gate 
2256*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
2257*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "cipher_init: failed holding minor");
2258*0Sstevel@tonic-gate 		return (ENXIO);
2259*0Sstevel@tonic-gate 	}
2260*0Sstevel@tonic-gate 
2261*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(encrypt_init),
2262*0Sstevel@tonic-gate 	    STRUCT_SIZE(encrypt_init)) != 0) {
2263*0Sstevel@tonic-gate 		crypto_release_minor(cm);
2264*0Sstevel@tonic-gate 		return (EFAULT);
2265*0Sstevel@tonic-gate 	}
2266*0Sstevel@tonic-gate 
2267*0Sstevel@tonic-gate 	mech.cm_param = NULL;
2268*0Sstevel@tonic-gate 	bzero(&key, sizeof (crypto_key_t));
2269*0Sstevel@tonic-gate 
2270*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(encrypt_init, ei_session);
2271*0Sstevel@tonic-gate 
2272*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
2273*0Sstevel@tonic-gate 		goto release_minor;
2274*0Sstevel@tonic-gate 	}
2275*0Sstevel@tonic-gate 
2276*0Sstevel@tonic-gate 	if (!copyin_mech(mode, STRUCT_FADDR(encrypt_init, ei_mech), &mech,
2277*0Sstevel@tonic-gate 	    &mech_rctl_bytes, &carry, &rv, &error, &mech_projp)) {
2278*0Sstevel@tonic-gate 		goto out;
2279*0Sstevel@tonic-gate 	}
2280*0Sstevel@tonic-gate 
2281*0Sstevel@tonic-gate 	if (init == crypto_encrypt_init_prov)
2282*0Sstevel@tonic-gate 	    offset = CRYPTO_CIPHER_OFFSET(encrypt_init);
2283*0Sstevel@tonic-gate 	else
2284*0Sstevel@tonic-gate 	    offset = CRYPTO_CIPHER_OFFSET(decrypt_init);
2285*0Sstevel@tonic-gate 
2286*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider(mech.cm_type,
2287*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(cipher_ops), offset,
2288*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
2289*0Sstevel@tonic-gate 		goto out;
2290*0Sstevel@tonic-gate 	}
2291*0Sstevel@tonic-gate 
2292*0Sstevel@tonic-gate 	if (!copyin_key(mode, STRUCT_FADDR(encrypt_init, ei_key), &key,
2293*0Sstevel@tonic-gate 	    &key_rctl_bytes, &rv, &error, carry, &key_projp)) {
2294*0Sstevel@tonic-gate 		goto out;
2295*0Sstevel@tonic-gate 	}
2296*0Sstevel@tonic-gate 
2297*0Sstevel@tonic-gate 	rv = (init)(real_provider, sp->sd_provider_session->ps_session,
2298*0Sstevel@tonic-gate 	    &mech, &key, NULL, &cc, NULL);
2299*0Sstevel@tonic-gate 
2300*0Sstevel@tonic-gate 	/*
2301*0Sstevel@tonic-gate 	 * Check if a context already exists. If so, it means it is being
2302*0Sstevel@tonic-gate 	 * abandoned. So, cancel it to avoid leaking it.
2303*0Sstevel@tonic-gate 	 */
2304*0Sstevel@tonic-gate 	ctxpp = (init == crypto_encrypt_init_prov) ?
2305*0Sstevel@tonic-gate 	    &sp->sd_encr_ctx : &sp->sd_decr_ctx;
2306*0Sstevel@tonic-gate 
2307*0Sstevel@tonic-gate 	if (*ctxpp != NULL)
2308*0Sstevel@tonic-gate 		CRYPTO_CANCEL_CTX(ctxpp);
2309*0Sstevel@tonic-gate 	*ctxpp = (rv == CRYPTO_SUCCESS) ? cc : NULL;
2310*0Sstevel@tonic-gate out:
2311*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
2312*0Sstevel@tonic-gate 
2313*0Sstevel@tonic-gate release_minor:
2314*0Sstevel@tonic-gate 	mutex_enter(&crypto_rctl_lock);
2315*0Sstevel@tonic-gate 	if (mech_rctl_bytes != 0)
2316*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(mech_rctl_bytes, mech_projp);
2317*0Sstevel@tonic-gate 	if (key_rctl_bytes != 0)
2318*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(key_rctl_bytes, key_projp);
2319*0Sstevel@tonic-gate 	mutex_exit(&crypto_rctl_lock);
2320*0Sstevel@tonic-gate 	crypto_release_minor(cm);
2321*0Sstevel@tonic-gate 
2322*0Sstevel@tonic-gate 	if (mech.cm_param != NULL)
2323*0Sstevel@tonic-gate 		kmem_free(mech.cm_param, mech.cm_param_len);
2324*0Sstevel@tonic-gate 
2325*0Sstevel@tonic-gate 	free_crypto_key(&key);
2326*0Sstevel@tonic-gate 
2327*0Sstevel@tonic-gate 	if (error != 0)
2328*0Sstevel@tonic-gate 		return (error);
2329*0Sstevel@tonic-gate 
2330*0Sstevel@tonic-gate 	STRUCT_FSET(encrypt_init, ei_return_value, rv);
2331*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(encrypt_init), arg,
2332*0Sstevel@tonic-gate 	    STRUCT_SIZE(encrypt_init)) != 0) {
2333*0Sstevel@tonic-gate 		return (EFAULT);
2334*0Sstevel@tonic-gate 	}
2335*0Sstevel@tonic-gate 	return (0);
2336*0Sstevel@tonic-gate }
2337*0Sstevel@tonic-gate 
2338*0Sstevel@tonic-gate /* ARGSUSED */
2339*0Sstevel@tonic-gate static int
2340*0Sstevel@tonic-gate encrypt(dev_t dev, caddr_t arg, int mode, int *rval)
2341*0Sstevel@tonic-gate {
2342*0Sstevel@tonic-gate 	return (cipher(dev, arg, mode, crypto_encrypt_single));
2343*0Sstevel@tonic-gate }
2344*0Sstevel@tonic-gate 
2345*0Sstevel@tonic-gate /* ARGSUSED */
2346*0Sstevel@tonic-gate static int
2347*0Sstevel@tonic-gate decrypt(dev_t dev, caddr_t arg, int mode, int *rval)
2348*0Sstevel@tonic-gate {
2349*0Sstevel@tonic-gate 	return (cipher(dev, arg, mode, crypto_decrypt_single));
2350*0Sstevel@tonic-gate }
2351*0Sstevel@tonic-gate 
2352*0Sstevel@tonic-gate /*
2353*0Sstevel@tonic-gate  * ASSUMPTION: crypto_encrypt and crypto_decrypt structures
2354*0Sstevel@tonic-gate  * are identical except for field names.
2355*0Sstevel@tonic-gate  */
2356*0Sstevel@tonic-gate static int
2357*0Sstevel@tonic-gate cipher(dev_t dev, caddr_t arg, int mode,
2358*0Sstevel@tonic-gate     int (*single)(crypto_context_t, crypto_data_t *, crypto_data_t *,
2359*0Sstevel@tonic-gate     crypto_call_req_t *))
2360*0Sstevel@tonic-gate {
2361*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_encrypt, encrypt);
2362*0Sstevel@tonic-gate 	kproject_t *projp;
2363*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
2364*0Sstevel@tonic-gate 	crypto_minor_t *cm;
2365*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
2366*0Sstevel@tonic-gate 	crypto_ctx_t **ctxpp;
2367*0Sstevel@tonic-gate 	crypto_data_t data, encr;
2368*0Sstevel@tonic-gate 	size_t datalen, encrlen, need = 0;
2369*0Sstevel@tonic-gate 	char *encrbuf;
2370*0Sstevel@tonic-gate 	int error = 0;
2371*0Sstevel@tonic-gate 	int rv;
2372*0Sstevel@tonic-gate 
2373*0Sstevel@tonic-gate 	STRUCT_INIT(encrypt, mode);
2374*0Sstevel@tonic-gate 
2375*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
2376*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "cipher: failed holding minor");
2377*0Sstevel@tonic-gate 		return (ENXIO);
2378*0Sstevel@tonic-gate 	}
2379*0Sstevel@tonic-gate 
2380*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(encrypt), STRUCT_SIZE(encrypt)) != 0) {
2381*0Sstevel@tonic-gate 		crypto_release_minor(cm);
2382*0Sstevel@tonic-gate 		return (EFAULT);
2383*0Sstevel@tonic-gate 	}
2384*0Sstevel@tonic-gate 
2385*0Sstevel@tonic-gate 	data.cd_raw.iov_base = NULL;
2386*0Sstevel@tonic-gate 	encr.cd_raw.iov_base = NULL;
2387*0Sstevel@tonic-gate 
2388*0Sstevel@tonic-gate 	datalen = STRUCT_FGET(encrypt, ce_datalen);
2389*0Sstevel@tonic-gate 	encrlen = STRUCT_FGET(encrypt, ce_encrlen);
2390*0Sstevel@tonic-gate 
2391*0Sstevel@tonic-gate 	/*
2392*0Sstevel@tonic-gate 	 * Don't allocate output buffer unless both buffer pointer and
2393*0Sstevel@tonic-gate 	 * buffer length are not NULL or 0 (length).
2394*0Sstevel@tonic-gate 	 */
2395*0Sstevel@tonic-gate 	encrbuf = STRUCT_FGETP(encrypt, ce_encrbuf);
2396*0Sstevel@tonic-gate 	if (encrbuf == NULL || encrlen == 0) {
2397*0Sstevel@tonic-gate 		encrlen = 0;
2398*0Sstevel@tonic-gate 	}
2399*0Sstevel@tonic-gate 
2400*0Sstevel@tonic-gate 	if (datalen > crypto_max_buffer_len ||
2401*0Sstevel@tonic-gate 	    encrlen > crypto_max_buffer_len) {
2402*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "cipher: buffer greater than %ld bytes, "
2403*0Sstevel@tonic-gate 		    "pid = %d", crypto_max_buffer_len, curproc->p_pid);
2404*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
2405*0Sstevel@tonic-gate 		goto release_minor;
2406*0Sstevel@tonic-gate 	}
2407*0Sstevel@tonic-gate 
2408*0Sstevel@tonic-gate 	need = datalen + encrlen;
2409*0Sstevel@tonic-gate 	if ((rv = crypto_buffer_check(need, &projp)) != CRYPTO_SUCCESS) {
2410*0Sstevel@tonic-gate 		need = 0;
2411*0Sstevel@tonic-gate 		goto release_minor;
2412*0Sstevel@tonic-gate 	}
2413*0Sstevel@tonic-gate 
2414*0Sstevel@tonic-gate 	INIT_RAW_CRYPTO_DATA(data, datalen);
2415*0Sstevel@tonic-gate 	data.cd_miscdata = NULL;
2416*0Sstevel@tonic-gate 
2417*0Sstevel@tonic-gate 	if (datalen != 0 && copyin(STRUCT_FGETP(encrypt, ce_databuf),
2418*0Sstevel@tonic-gate 	    data.cd_raw.iov_base, datalen) != 0) {
2419*0Sstevel@tonic-gate 		error = EFAULT;
2420*0Sstevel@tonic-gate 		goto release_minor;
2421*0Sstevel@tonic-gate 	}
2422*0Sstevel@tonic-gate 
2423*0Sstevel@tonic-gate 	INIT_RAW_CRYPTO_DATA(encr, encrlen);
2424*0Sstevel@tonic-gate 
2425*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(encrypt, ce_session);
2426*0Sstevel@tonic-gate 
2427*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv))  {
2428*0Sstevel@tonic-gate 		goto release_minor;
2429*0Sstevel@tonic-gate 	}
2430*0Sstevel@tonic-gate 
2431*0Sstevel@tonic-gate 	ctxpp = (single == crypto_encrypt_single) ?
2432*0Sstevel@tonic-gate 	    &sp->sd_encr_ctx : &sp->sd_decr_ctx;
2433*0Sstevel@tonic-gate 
2434*0Sstevel@tonic-gate 	rv = (single)(*ctxpp, &data, &encr, NULL);
2435*0Sstevel@tonic-gate 	if (KCF_CONTEXT_DONE(rv))
2436*0Sstevel@tonic-gate 		*ctxpp = NULL;
2437*0Sstevel@tonic-gate 
2438*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
2439*0Sstevel@tonic-gate 
2440*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS) {
2441*0Sstevel@tonic-gate 		ASSERT(encr.cd_length <= encrlen);
2442*0Sstevel@tonic-gate 		if (encr.cd_length != 0 && copyout(encr.cd_raw.iov_base,
2443*0Sstevel@tonic-gate 		    encrbuf, encr.cd_length) != 0) {
2444*0Sstevel@tonic-gate 			error = EFAULT;
2445*0Sstevel@tonic-gate 			goto release_minor;
2446*0Sstevel@tonic-gate 		}
2447*0Sstevel@tonic-gate 		STRUCT_FSET(encrypt, ce_encrlen, encr.cd_length);
2448*0Sstevel@tonic-gate 	}
2449*0Sstevel@tonic-gate 
2450*0Sstevel@tonic-gate 	if (rv == CRYPTO_BUFFER_TOO_SMALL) {
2451*0Sstevel@tonic-gate 		/*
2452*0Sstevel@tonic-gate 		 * The providers return CRYPTO_BUFFER_TOO_SMALL even for case 1
2453*0Sstevel@tonic-gate 		 * of section 11.2 of the pkcs11 spec. We catch it here and
2454*0Sstevel@tonic-gate 		 * provide the correct pkcs11 return value.
2455*0Sstevel@tonic-gate 		 */
2456*0Sstevel@tonic-gate 		if (STRUCT_FGETP(encrypt, ce_encrbuf) == NULL)
2457*0Sstevel@tonic-gate 			rv = CRYPTO_SUCCESS;
2458*0Sstevel@tonic-gate 		STRUCT_FSET(encrypt, ce_encrlen, encr.cd_length);
2459*0Sstevel@tonic-gate 	}
2460*0Sstevel@tonic-gate 
2461*0Sstevel@tonic-gate release_minor:
2462*0Sstevel@tonic-gate 	if (need != 0) {
2463*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
2464*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(need, projp);
2465*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
2466*0Sstevel@tonic-gate 	}
2467*0Sstevel@tonic-gate 	crypto_release_minor(cm);
2468*0Sstevel@tonic-gate 
2469*0Sstevel@tonic-gate 	if (data.cd_raw.iov_base != NULL)
2470*0Sstevel@tonic-gate 		kmem_free(data.cd_raw.iov_base, datalen);
2471*0Sstevel@tonic-gate 
2472*0Sstevel@tonic-gate 	if (encr.cd_raw.iov_base != NULL)
2473*0Sstevel@tonic-gate 		kmem_free(encr.cd_raw.iov_base, encrlen);
2474*0Sstevel@tonic-gate 
2475*0Sstevel@tonic-gate 	if (error != 0)
2476*0Sstevel@tonic-gate 		return (error);
2477*0Sstevel@tonic-gate 
2478*0Sstevel@tonic-gate 	STRUCT_FSET(encrypt, ce_return_value, rv);
2479*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(encrypt), arg, STRUCT_SIZE(encrypt)) != 0) {
2480*0Sstevel@tonic-gate 		return (EFAULT);
2481*0Sstevel@tonic-gate 	}
2482*0Sstevel@tonic-gate 	return (0);
2483*0Sstevel@tonic-gate }
2484*0Sstevel@tonic-gate 
2485*0Sstevel@tonic-gate /* ARGSUSED */
2486*0Sstevel@tonic-gate static int
2487*0Sstevel@tonic-gate encrypt_update(dev_t dev, caddr_t arg, int mode, int *rval)
2488*0Sstevel@tonic-gate {
2489*0Sstevel@tonic-gate 	return (cipher_update(dev, arg, mode, crypto_encrypt_update));
2490*0Sstevel@tonic-gate }
2491*0Sstevel@tonic-gate 
2492*0Sstevel@tonic-gate /* ARGSUSED */
2493*0Sstevel@tonic-gate static int
2494*0Sstevel@tonic-gate decrypt_update(dev_t dev, caddr_t arg, int mode, int *rval)
2495*0Sstevel@tonic-gate {
2496*0Sstevel@tonic-gate 	return (cipher_update(dev, arg, mode, crypto_decrypt_update));
2497*0Sstevel@tonic-gate }
2498*0Sstevel@tonic-gate 
2499*0Sstevel@tonic-gate /*
2500*0Sstevel@tonic-gate  * ASSUMPTION: crypto_encrypt_update and crypto_decrypt_update
2501*0Sstevel@tonic-gate  * structures are identical except for field names.
2502*0Sstevel@tonic-gate  */
2503*0Sstevel@tonic-gate static int
2504*0Sstevel@tonic-gate cipher_update(dev_t dev, caddr_t arg, int mode,
2505*0Sstevel@tonic-gate     int (*update)(crypto_context_t, crypto_data_t *, crypto_data_t *,
2506*0Sstevel@tonic-gate     crypto_call_req_t *))
2507*0Sstevel@tonic-gate {
2508*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_encrypt_update, encrypt_update);
2509*0Sstevel@tonic-gate 	kproject_t *projp;
2510*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
2511*0Sstevel@tonic-gate 	crypto_minor_t *cm;
2512*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
2513*0Sstevel@tonic-gate 	crypto_ctx_t **ctxpp;
2514*0Sstevel@tonic-gate 	crypto_data_t data, encr;
2515*0Sstevel@tonic-gate 	size_t datalen, encrlen, need = 0;
2516*0Sstevel@tonic-gate 	char *encrbuf;
2517*0Sstevel@tonic-gate 	int error = 0;
2518*0Sstevel@tonic-gate 	int rv;
2519*0Sstevel@tonic-gate 
2520*0Sstevel@tonic-gate 	STRUCT_INIT(encrypt_update, mode);
2521*0Sstevel@tonic-gate 
2522*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
2523*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "cipher_update: failed holding minor");
2524*0Sstevel@tonic-gate 		return (ENXIO);
2525*0Sstevel@tonic-gate 	}
2526*0Sstevel@tonic-gate 
2527*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(encrypt_update),
2528*0Sstevel@tonic-gate 	    STRUCT_SIZE(encrypt_update)) != 0) {
2529*0Sstevel@tonic-gate 		crypto_release_minor(cm);
2530*0Sstevel@tonic-gate 		return (EFAULT);
2531*0Sstevel@tonic-gate 	}
2532*0Sstevel@tonic-gate 
2533*0Sstevel@tonic-gate 	data.cd_raw.iov_base = NULL;
2534*0Sstevel@tonic-gate 	encr.cd_raw.iov_base = NULL;
2535*0Sstevel@tonic-gate 
2536*0Sstevel@tonic-gate 	datalen = STRUCT_FGET(encrypt_update, eu_datalen);
2537*0Sstevel@tonic-gate 	encrlen = STRUCT_FGET(encrypt_update, eu_encrlen);
2538*0Sstevel@tonic-gate 
2539*0Sstevel@tonic-gate 	/*
2540*0Sstevel@tonic-gate 	 * Don't allocate output buffer unless both buffer pointer and
2541*0Sstevel@tonic-gate 	 * buffer length are not NULL or 0 (length).
2542*0Sstevel@tonic-gate 	 */
2543*0Sstevel@tonic-gate 	encrbuf = STRUCT_FGETP(encrypt_update, eu_encrbuf);
2544*0Sstevel@tonic-gate 	if (encrbuf == NULL || encrlen == 0) {
2545*0Sstevel@tonic-gate 		encrlen = 0;
2546*0Sstevel@tonic-gate 	}
2547*0Sstevel@tonic-gate 
2548*0Sstevel@tonic-gate 	if (datalen > crypto_max_buffer_len ||
2549*0Sstevel@tonic-gate 	    encrlen > crypto_max_buffer_len) {
2550*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "cipher_update: buffer greater than %ld "
2551*0Sstevel@tonic-gate 		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
2552*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
2553*0Sstevel@tonic-gate 		goto release_minor;
2554*0Sstevel@tonic-gate 	}
2555*0Sstevel@tonic-gate 
2556*0Sstevel@tonic-gate 	need = datalen + encrlen;
2557*0Sstevel@tonic-gate 	if ((rv = crypto_buffer_check(need, &projp)) != CRYPTO_SUCCESS) {
2558*0Sstevel@tonic-gate 		need = 0;
2559*0Sstevel@tonic-gate 		goto release_minor;
2560*0Sstevel@tonic-gate 	}
2561*0Sstevel@tonic-gate 
2562*0Sstevel@tonic-gate 	INIT_RAW_CRYPTO_DATA(data, datalen);
2563*0Sstevel@tonic-gate 	data.cd_miscdata = NULL;
2564*0Sstevel@tonic-gate 
2565*0Sstevel@tonic-gate 	if (datalen != 0 && copyin(STRUCT_FGETP(encrypt_update, eu_databuf),
2566*0Sstevel@tonic-gate 	    data.cd_raw.iov_base, datalen) != 0) {
2567*0Sstevel@tonic-gate 		error = EFAULT;
2568*0Sstevel@tonic-gate 		goto release_minor;
2569*0Sstevel@tonic-gate 	}
2570*0Sstevel@tonic-gate 
2571*0Sstevel@tonic-gate 	INIT_RAW_CRYPTO_DATA(encr, encrlen);
2572*0Sstevel@tonic-gate 
2573*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(encrypt_update, eu_session);
2574*0Sstevel@tonic-gate 
2575*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv))  {
2576*0Sstevel@tonic-gate 		goto release_minor;
2577*0Sstevel@tonic-gate 	}
2578*0Sstevel@tonic-gate 
2579*0Sstevel@tonic-gate 	ctxpp = (update == crypto_encrypt_update) ?
2580*0Sstevel@tonic-gate 	    &sp->sd_encr_ctx : &sp->sd_decr_ctx;
2581*0Sstevel@tonic-gate 
2582*0Sstevel@tonic-gate 	rv = (update)(*ctxpp, &data, &encr, NULL);
2583*0Sstevel@tonic-gate 
2584*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS || rv == CRYPTO_BUFFER_TOO_SMALL) {
2585*0Sstevel@tonic-gate 		if (rv == CRYPTO_SUCCESS) {
2586*0Sstevel@tonic-gate 			ASSERT(encr.cd_length <= encrlen);
2587*0Sstevel@tonic-gate 			if (encr.cd_length != 0 && copyout(encr.cd_raw.iov_base,
2588*0Sstevel@tonic-gate 			    encrbuf, encr.cd_length) != 0) {
2589*0Sstevel@tonic-gate 				error = EFAULT;
2590*0Sstevel@tonic-gate 				goto out;
2591*0Sstevel@tonic-gate 			}
2592*0Sstevel@tonic-gate 		} else {
2593*0Sstevel@tonic-gate 			/*
2594*0Sstevel@tonic-gate 			 * The providers return CRYPTO_BUFFER_TOO_SMALL even
2595*0Sstevel@tonic-gate 			 * for case 1 of section 11.2 of the pkcs11 spec.
2596*0Sstevel@tonic-gate 			 * We catch it here and provide the correct pkcs11
2597*0Sstevel@tonic-gate 			 * return value.
2598*0Sstevel@tonic-gate 			 */
2599*0Sstevel@tonic-gate 			if (STRUCT_FGETP(encrypt_update, eu_encrbuf) == NULL)
2600*0Sstevel@tonic-gate 				rv = CRYPTO_SUCCESS;
2601*0Sstevel@tonic-gate 		}
2602*0Sstevel@tonic-gate 		STRUCT_FSET(encrypt_update, eu_encrlen, encr.cd_length);
2603*0Sstevel@tonic-gate 	} else {
2604*0Sstevel@tonic-gate 		CRYPTO_CANCEL_CTX(ctxpp);
2605*0Sstevel@tonic-gate 	}
2606*0Sstevel@tonic-gate out:
2607*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
2608*0Sstevel@tonic-gate 
2609*0Sstevel@tonic-gate release_minor:
2610*0Sstevel@tonic-gate 	if (need != 0) {
2611*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
2612*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(need, projp);
2613*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
2614*0Sstevel@tonic-gate 	}
2615*0Sstevel@tonic-gate 	crypto_release_minor(cm);
2616*0Sstevel@tonic-gate 
2617*0Sstevel@tonic-gate 	if (data.cd_raw.iov_base != NULL)
2618*0Sstevel@tonic-gate 		kmem_free(data.cd_raw.iov_base, datalen);
2619*0Sstevel@tonic-gate 
2620*0Sstevel@tonic-gate 	if (encr.cd_raw.iov_base != NULL)
2621*0Sstevel@tonic-gate 		kmem_free(encr.cd_raw.iov_base, encrlen);
2622*0Sstevel@tonic-gate 
2623*0Sstevel@tonic-gate 	if (error != 0)
2624*0Sstevel@tonic-gate 		return (error);
2625*0Sstevel@tonic-gate 
2626*0Sstevel@tonic-gate 	STRUCT_FSET(encrypt_update, eu_return_value, rv);
2627*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(encrypt_update), arg,
2628*0Sstevel@tonic-gate 	    STRUCT_SIZE(encrypt_update)) != 0) {
2629*0Sstevel@tonic-gate 		return (EFAULT);
2630*0Sstevel@tonic-gate 	}
2631*0Sstevel@tonic-gate 	return (0);
2632*0Sstevel@tonic-gate }
2633*0Sstevel@tonic-gate 
2634*0Sstevel@tonic-gate /* ARGSUSED */
2635*0Sstevel@tonic-gate static int
2636*0Sstevel@tonic-gate encrypt_final(dev_t dev, caddr_t arg, int mode, int *rval)
2637*0Sstevel@tonic-gate {
2638*0Sstevel@tonic-gate 	return (common_final(dev, arg, mode, crypto_encrypt_final));
2639*0Sstevel@tonic-gate }
2640*0Sstevel@tonic-gate 
2641*0Sstevel@tonic-gate /* ARGSUSED */
2642*0Sstevel@tonic-gate static int
2643*0Sstevel@tonic-gate decrypt_final(dev_t dev, caddr_t arg, int mode, int *rval)
2644*0Sstevel@tonic-gate {
2645*0Sstevel@tonic-gate 	return (common_final(dev, arg, mode, crypto_decrypt_final));
2646*0Sstevel@tonic-gate }
2647*0Sstevel@tonic-gate 
2648*0Sstevel@tonic-gate /*
2649*0Sstevel@tonic-gate  * ASSUMPTION: crypto_encrypt_final, crypto_decrypt_final, crypto_sign_final,
2650*0Sstevel@tonic-gate  * and crypto_digest_final structures are identical except for field names.
2651*0Sstevel@tonic-gate  */
2652*0Sstevel@tonic-gate static int
2653*0Sstevel@tonic-gate common_final(dev_t dev, caddr_t arg, int mode,
2654*0Sstevel@tonic-gate     int (*final)(crypto_context_t, crypto_data_t *, crypto_call_req_t *))
2655*0Sstevel@tonic-gate {
2656*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_encrypt_final, encrypt_final);
2657*0Sstevel@tonic-gate 	kproject_t *projp;
2658*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
2659*0Sstevel@tonic-gate 	crypto_minor_t *cm;
2660*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
2661*0Sstevel@tonic-gate 	crypto_ctx_t **ctxpp;
2662*0Sstevel@tonic-gate 	crypto_data_t encr;
2663*0Sstevel@tonic-gate 	size_t encrlen, need = 0;
2664*0Sstevel@tonic-gate 	char *encrbuf;
2665*0Sstevel@tonic-gate 	int error = 0;
2666*0Sstevel@tonic-gate 	int rv;
2667*0Sstevel@tonic-gate 
2668*0Sstevel@tonic-gate 	STRUCT_INIT(encrypt_final, mode);
2669*0Sstevel@tonic-gate 
2670*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
2671*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "common_final: failed holding minor");
2672*0Sstevel@tonic-gate 		return (ENXIO);
2673*0Sstevel@tonic-gate 	}
2674*0Sstevel@tonic-gate 
2675*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(encrypt_final),
2676*0Sstevel@tonic-gate 	    STRUCT_SIZE(encrypt_final)) != 0) {
2677*0Sstevel@tonic-gate 		crypto_release_minor(cm);
2678*0Sstevel@tonic-gate 		return (EFAULT);
2679*0Sstevel@tonic-gate 	}
2680*0Sstevel@tonic-gate 
2681*0Sstevel@tonic-gate 	encr.cd_format = CRYPTO_DATA_RAW;
2682*0Sstevel@tonic-gate 	encr.cd_raw.iov_base = NULL;
2683*0Sstevel@tonic-gate 
2684*0Sstevel@tonic-gate 	encrlen = STRUCT_FGET(encrypt_final, ef_encrlen);
2685*0Sstevel@tonic-gate 
2686*0Sstevel@tonic-gate 	/*
2687*0Sstevel@tonic-gate 	 * Don't allocate output buffer unless both buffer pointer and
2688*0Sstevel@tonic-gate 	 * buffer length are not NULL or 0 (length).
2689*0Sstevel@tonic-gate 	 */
2690*0Sstevel@tonic-gate 	encrbuf = STRUCT_FGETP(encrypt_final, ef_encrbuf);
2691*0Sstevel@tonic-gate 	if (encrbuf == NULL || encrlen == 0) {
2692*0Sstevel@tonic-gate 		encrlen = 0;
2693*0Sstevel@tonic-gate 	}
2694*0Sstevel@tonic-gate 
2695*0Sstevel@tonic-gate 	if (encrlen > crypto_max_buffer_len) {
2696*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "common_final: buffer greater than %ld "
2697*0Sstevel@tonic-gate 		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
2698*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
2699*0Sstevel@tonic-gate 		goto release_minor;
2700*0Sstevel@tonic-gate 	}
2701*0Sstevel@tonic-gate 
2702*0Sstevel@tonic-gate 	if ((rv = crypto_buffer_check(encrlen, &projp)) != CRYPTO_SUCCESS) {
2703*0Sstevel@tonic-gate 		goto release_minor;
2704*0Sstevel@tonic-gate 	}
2705*0Sstevel@tonic-gate 	need = encrlen;
2706*0Sstevel@tonic-gate 	encr.cd_raw.iov_base = kmem_alloc(encrlen, KM_SLEEP);
2707*0Sstevel@tonic-gate 	encr.cd_raw.iov_len = encrlen;
2708*0Sstevel@tonic-gate 
2709*0Sstevel@tonic-gate 	encr.cd_offset = 0;
2710*0Sstevel@tonic-gate 	encr.cd_length = encrlen;
2711*0Sstevel@tonic-gate 
2712*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(encrypt_final, ef_session);
2713*0Sstevel@tonic-gate 
2714*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
2715*0Sstevel@tonic-gate 		goto release_minor;
2716*0Sstevel@tonic-gate 	}
2717*0Sstevel@tonic-gate 
2718*0Sstevel@tonic-gate 	ASSERT(final == crypto_encrypt_final ||
2719*0Sstevel@tonic-gate 	    final == crypto_decrypt_final || final == crypto_sign_final ||
2720*0Sstevel@tonic-gate 	    final == crypto_digest_final);
2721*0Sstevel@tonic-gate 
2722*0Sstevel@tonic-gate 	if (final == crypto_encrypt_final) {
2723*0Sstevel@tonic-gate 		ctxpp = &sp->sd_encr_ctx;
2724*0Sstevel@tonic-gate 	} else if (final == crypto_decrypt_final) {
2725*0Sstevel@tonic-gate 		ctxpp = &sp->sd_decr_ctx;
2726*0Sstevel@tonic-gate 	} else if (final == crypto_sign_final) {
2727*0Sstevel@tonic-gate 		ctxpp = &sp->sd_sign_ctx;
2728*0Sstevel@tonic-gate 	} else {
2729*0Sstevel@tonic-gate 		ctxpp = &sp->sd_digest_ctx;
2730*0Sstevel@tonic-gate 	}
2731*0Sstevel@tonic-gate 
2732*0Sstevel@tonic-gate 	rv = (final)(*ctxpp, &encr, NULL);
2733*0Sstevel@tonic-gate 	if (KCF_CONTEXT_DONE(rv))
2734*0Sstevel@tonic-gate 		*ctxpp = NULL;
2735*0Sstevel@tonic-gate 
2736*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
2737*0Sstevel@tonic-gate 
2738*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS) {
2739*0Sstevel@tonic-gate 		ASSERT(encr.cd_length <= encrlen);
2740*0Sstevel@tonic-gate 		if (encr.cd_length != 0 && copyout(encr.cd_raw.iov_base,
2741*0Sstevel@tonic-gate 		    encrbuf, encr.cd_length) != 0) {
2742*0Sstevel@tonic-gate 			error = EFAULT;
2743*0Sstevel@tonic-gate 			goto release_minor;
2744*0Sstevel@tonic-gate 		}
2745*0Sstevel@tonic-gate 		STRUCT_FSET(encrypt_final, ef_encrlen, encr.cd_length);
2746*0Sstevel@tonic-gate 	}
2747*0Sstevel@tonic-gate 
2748*0Sstevel@tonic-gate 	if (rv == CRYPTO_BUFFER_TOO_SMALL) {
2749*0Sstevel@tonic-gate 		/*
2750*0Sstevel@tonic-gate 		 * The providers return CRYPTO_BUFFER_TOO_SMALL even for case 1
2751*0Sstevel@tonic-gate 		 * of section 11.2 of the pkcs11 spec. We catch it here and
2752*0Sstevel@tonic-gate 		 * provide the correct pkcs11 return value.
2753*0Sstevel@tonic-gate 		 */
2754*0Sstevel@tonic-gate 		if (STRUCT_FGETP(encrypt_final, ef_encrbuf) == NULL)
2755*0Sstevel@tonic-gate 			rv = CRYPTO_SUCCESS;
2756*0Sstevel@tonic-gate 		STRUCT_FSET(encrypt_final, ef_encrlen, encr.cd_length);
2757*0Sstevel@tonic-gate 	}
2758*0Sstevel@tonic-gate 
2759*0Sstevel@tonic-gate release_minor:
2760*0Sstevel@tonic-gate 	if (need != 0) {
2761*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
2762*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(need, projp);
2763*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
2764*0Sstevel@tonic-gate 	}
2765*0Sstevel@tonic-gate 	crypto_release_minor(cm);
2766*0Sstevel@tonic-gate 
2767*0Sstevel@tonic-gate 	if (encr.cd_raw.iov_base != NULL)
2768*0Sstevel@tonic-gate 		kmem_free(encr.cd_raw.iov_base, encrlen);
2769*0Sstevel@tonic-gate 
2770*0Sstevel@tonic-gate 	if (error != 0)
2771*0Sstevel@tonic-gate 		return (error);
2772*0Sstevel@tonic-gate 
2773*0Sstevel@tonic-gate 	STRUCT_FSET(encrypt_final, ef_return_value, rv);
2774*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(encrypt_final), arg,
2775*0Sstevel@tonic-gate 	    STRUCT_SIZE(encrypt_final)) != 0) {
2776*0Sstevel@tonic-gate 		return (EFAULT);
2777*0Sstevel@tonic-gate 	}
2778*0Sstevel@tonic-gate 	return (0);
2779*0Sstevel@tonic-gate }
2780*0Sstevel@tonic-gate 
2781*0Sstevel@tonic-gate /* ARGSUSED */
2782*0Sstevel@tonic-gate static int
2783*0Sstevel@tonic-gate digest_init(dev_t dev, caddr_t arg, int mode, int *rval)
2784*0Sstevel@tonic-gate {
2785*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_digest_init, digest_init);
2786*0Sstevel@tonic-gate 	kproject_t *mech_projp;
2787*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
2788*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
2789*0Sstevel@tonic-gate 	crypto_mechanism_t mech;
2790*0Sstevel@tonic-gate 	crypto_minor_t *cm;
2791*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
2792*0Sstevel@tonic-gate 	crypto_context_t cc;
2793*0Sstevel@tonic-gate 	size_t rctl_bytes = 0;
2794*0Sstevel@tonic-gate 	int error = 0;
2795*0Sstevel@tonic-gate 	int rv;
2796*0Sstevel@tonic-gate 
2797*0Sstevel@tonic-gate 	STRUCT_INIT(digest_init, mode);
2798*0Sstevel@tonic-gate 
2799*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
2800*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "digest_init: failed holding minor");
2801*0Sstevel@tonic-gate 		return (ENXIO);
2802*0Sstevel@tonic-gate 	}
2803*0Sstevel@tonic-gate 
2804*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(digest_init),
2805*0Sstevel@tonic-gate 	    STRUCT_SIZE(digest_init)) != 0) {
2806*0Sstevel@tonic-gate 		crypto_release_minor(cm);
2807*0Sstevel@tonic-gate 		return (EFAULT);
2808*0Sstevel@tonic-gate 	}
2809*0Sstevel@tonic-gate 
2810*0Sstevel@tonic-gate 	mech.cm_param = NULL;
2811*0Sstevel@tonic-gate 
2812*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(digest_init, di_session);
2813*0Sstevel@tonic-gate 
2814*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv))  {
2815*0Sstevel@tonic-gate 		goto release_minor;
2816*0Sstevel@tonic-gate 	}
2817*0Sstevel@tonic-gate 
2818*0Sstevel@tonic-gate 	if (!copyin_mech(mode, STRUCT_FADDR(digest_init, di_mech), &mech,
2819*0Sstevel@tonic-gate 	    &rctl_bytes, NULL, &rv, &error, &mech_projp)) {
2820*0Sstevel@tonic-gate 		goto out;
2821*0Sstevel@tonic-gate 	}
2822*0Sstevel@tonic-gate 
2823*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider(mech.cm_type,
2824*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(digest_ops),
2825*0Sstevel@tonic-gate 	    CRYPTO_DIGEST_OFFSET(digest_init),
2826*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
2827*0Sstevel@tonic-gate 		goto out;
2828*0Sstevel@tonic-gate 	}
2829*0Sstevel@tonic-gate 
2830*0Sstevel@tonic-gate 	rv = crypto_digest_init_prov(real_provider,
2831*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, &mech, &cc, NULL);
2832*0Sstevel@tonic-gate 
2833*0Sstevel@tonic-gate 	/*
2834*0Sstevel@tonic-gate 	 * Check if a context already exists. If so, it means it is being
2835*0Sstevel@tonic-gate 	 * abandoned. So, cancel it to avoid leaking it.
2836*0Sstevel@tonic-gate 	 */
2837*0Sstevel@tonic-gate 	if (sp->sd_digest_ctx != NULL)
2838*0Sstevel@tonic-gate 		CRYPTO_CANCEL_CTX(&sp->sd_digest_ctx);
2839*0Sstevel@tonic-gate 	sp->sd_digest_ctx = (rv == CRYPTO_SUCCESS) ? cc : NULL;
2840*0Sstevel@tonic-gate out:
2841*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
2842*0Sstevel@tonic-gate 
2843*0Sstevel@tonic-gate release_minor:
2844*0Sstevel@tonic-gate 	if (rctl_bytes != 0) {
2845*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
2846*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(rctl_bytes, mech_projp);
2847*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
2848*0Sstevel@tonic-gate 	}
2849*0Sstevel@tonic-gate 	crypto_release_minor(cm);
2850*0Sstevel@tonic-gate 
2851*0Sstevel@tonic-gate 	if (mech.cm_param != NULL)
2852*0Sstevel@tonic-gate 		kmem_free(mech.cm_param, mech.cm_param_len);
2853*0Sstevel@tonic-gate 
2854*0Sstevel@tonic-gate 	if (error != 0)
2855*0Sstevel@tonic-gate 		return (error);
2856*0Sstevel@tonic-gate 
2857*0Sstevel@tonic-gate 	STRUCT_FSET(digest_init, di_return_value, rv);
2858*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(digest_init), arg,
2859*0Sstevel@tonic-gate 	    STRUCT_SIZE(digest_init)) != 0) {
2860*0Sstevel@tonic-gate 		return (EFAULT);
2861*0Sstevel@tonic-gate 	}
2862*0Sstevel@tonic-gate 	return (0);
2863*0Sstevel@tonic-gate }
2864*0Sstevel@tonic-gate 
2865*0Sstevel@tonic-gate /* ARGSUSED */
2866*0Sstevel@tonic-gate static int
2867*0Sstevel@tonic-gate digest_update(dev_t dev, caddr_t arg, int mode, int *rval)
2868*0Sstevel@tonic-gate {
2869*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_digest_update, digest_update);
2870*0Sstevel@tonic-gate 	kproject_t *projp;
2871*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
2872*0Sstevel@tonic-gate 	crypto_minor_t *cm;
2873*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
2874*0Sstevel@tonic-gate 	crypto_data_t data;
2875*0Sstevel@tonic-gate 	size_t datalen, need = 0;
2876*0Sstevel@tonic-gate 	int error = 0;
2877*0Sstevel@tonic-gate 	int rv;
2878*0Sstevel@tonic-gate 
2879*0Sstevel@tonic-gate 	STRUCT_INIT(digest_update, mode);
2880*0Sstevel@tonic-gate 
2881*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
2882*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "digest_update: failed holding minor");
2883*0Sstevel@tonic-gate 		return (ENXIO);
2884*0Sstevel@tonic-gate 	}
2885*0Sstevel@tonic-gate 
2886*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(digest_update),
2887*0Sstevel@tonic-gate 	    STRUCT_SIZE(digest_update)) != 0) {
2888*0Sstevel@tonic-gate 		crypto_release_minor(cm);
2889*0Sstevel@tonic-gate 		return (EFAULT);
2890*0Sstevel@tonic-gate 	}
2891*0Sstevel@tonic-gate 
2892*0Sstevel@tonic-gate 	data.cd_format = CRYPTO_DATA_RAW;
2893*0Sstevel@tonic-gate 	data.cd_raw.iov_base = NULL;
2894*0Sstevel@tonic-gate 
2895*0Sstevel@tonic-gate 	datalen = STRUCT_FGET(digest_update, du_datalen);
2896*0Sstevel@tonic-gate 	if (datalen > crypto_max_buffer_len) {
2897*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "digest_update: buffer greater than %ld "
2898*0Sstevel@tonic-gate 		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
2899*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
2900*0Sstevel@tonic-gate 		goto release_minor;
2901*0Sstevel@tonic-gate 	}
2902*0Sstevel@tonic-gate 
2903*0Sstevel@tonic-gate 	if ((rv = crypto_buffer_check(datalen, &projp)) != CRYPTO_SUCCESS) {
2904*0Sstevel@tonic-gate 		goto release_minor;
2905*0Sstevel@tonic-gate 	}
2906*0Sstevel@tonic-gate 	need = datalen;
2907*0Sstevel@tonic-gate 	data.cd_raw.iov_base = kmem_alloc(datalen, KM_SLEEP);
2908*0Sstevel@tonic-gate 	data.cd_raw.iov_len = datalen;
2909*0Sstevel@tonic-gate 
2910*0Sstevel@tonic-gate 	if (datalen != 0 && copyin(STRUCT_FGETP(digest_update, du_databuf),
2911*0Sstevel@tonic-gate 	    data.cd_raw.iov_base, datalen) != 0) {
2912*0Sstevel@tonic-gate 		error = EFAULT;
2913*0Sstevel@tonic-gate 		goto release_minor;
2914*0Sstevel@tonic-gate 	}
2915*0Sstevel@tonic-gate 
2916*0Sstevel@tonic-gate 	data.cd_offset = 0;
2917*0Sstevel@tonic-gate 	data.cd_length = datalen;
2918*0Sstevel@tonic-gate 
2919*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(digest_update, du_session);
2920*0Sstevel@tonic-gate 
2921*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv))  {
2922*0Sstevel@tonic-gate 		goto release_minor;
2923*0Sstevel@tonic-gate 	}
2924*0Sstevel@tonic-gate 
2925*0Sstevel@tonic-gate 	rv = crypto_digest_update(sp->sd_digest_ctx, &data, NULL);
2926*0Sstevel@tonic-gate 	if (rv != CRYPTO_SUCCESS)
2927*0Sstevel@tonic-gate 		CRYPTO_CANCEL_CTX(&sp->sd_digest_ctx);
2928*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
2929*0Sstevel@tonic-gate 
2930*0Sstevel@tonic-gate release_minor:
2931*0Sstevel@tonic-gate 	if (need != 0) {
2932*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
2933*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(need, projp);
2934*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
2935*0Sstevel@tonic-gate 	}
2936*0Sstevel@tonic-gate 	crypto_release_minor(cm);
2937*0Sstevel@tonic-gate 
2938*0Sstevel@tonic-gate 	if (data.cd_raw.iov_base != NULL)
2939*0Sstevel@tonic-gate 		kmem_free(data.cd_raw.iov_base, datalen);
2940*0Sstevel@tonic-gate 
2941*0Sstevel@tonic-gate 	if (error != 0)
2942*0Sstevel@tonic-gate 		return (error);
2943*0Sstevel@tonic-gate 
2944*0Sstevel@tonic-gate 	STRUCT_FSET(digest_update, du_return_value, rv);
2945*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(digest_update), arg,
2946*0Sstevel@tonic-gate 	    STRUCT_SIZE(digest_update)) != 0) {
2947*0Sstevel@tonic-gate 		return (EFAULT);
2948*0Sstevel@tonic-gate 	}
2949*0Sstevel@tonic-gate 	return (0);
2950*0Sstevel@tonic-gate }
2951*0Sstevel@tonic-gate 
2952*0Sstevel@tonic-gate /* ARGSUSED */
2953*0Sstevel@tonic-gate static int
2954*0Sstevel@tonic-gate digest_key(dev_t dev, caddr_t arg, int mode, int *rval)
2955*0Sstevel@tonic-gate {
2956*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_digest_key, digest_key);
2957*0Sstevel@tonic-gate 	kproject_t *projp;
2958*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
2959*0Sstevel@tonic-gate 	crypto_key_t key;
2960*0Sstevel@tonic-gate 	crypto_minor_t *cm;
2961*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
2962*0Sstevel@tonic-gate 	size_t rctl_bytes = 0;
2963*0Sstevel@tonic-gate 	int error = 0;
2964*0Sstevel@tonic-gate 	int rv;
2965*0Sstevel@tonic-gate 
2966*0Sstevel@tonic-gate 	STRUCT_INIT(digest_key, mode);
2967*0Sstevel@tonic-gate 
2968*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
2969*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "digest_key: failed holding minor");
2970*0Sstevel@tonic-gate 		return (ENXIO);
2971*0Sstevel@tonic-gate 	}
2972*0Sstevel@tonic-gate 
2973*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(digest_key), STRUCT_SIZE(digest_key)) != 0) {
2974*0Sstevel@tonic-gate 		crypto_release_minor(cm);
2975*0Sstevel@tonic-gate 		return (EFAULT);
2976*0Sstevel@tonic-gate 	}
2977*0Sstevel@tonic-gate 
2978*0Sstevel@tonic-gate 	bzero(&key, sizeof (crypto_key_t));
2979*0Sstevel@tonic-gate 
2980*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(digest_key, dk_session);
2981*0Sstevel@tonic-gate 
2982*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv))  {
2983*0Sstevel@tonic-gate 		goto release_minor;
2984*0Sstevel@tonic-gate 	}
2985*0Sstevel@tonic-gate 
2986*0Sstevel@tonic-gate 	if (!copyin_key(mode, STRUCT_FADDR(digest_key, dk_key), &key,
2987*0Sstevel@tonic-gate 	    &rctl_bytes, &rv, &error, 0, &projp)) {
2988*0Sstevel@tonic-gate 		goto out;
2989*0Sstevel@tonic-gate 	}
2990*0Sstevel@tonic-gate 
2991*0Sstevel@tonic-gate 	rv = crypto_digest_key_prov(sp->sd_digest_ctx, &key, NULL);
2992*0Sstevel@tonic-gate 	if (rv != CRYPTO_SUCCESS)
2993*0Sstevel@tonic-gate 		CRYPTO_CANCEL_CTX(&sp->sd_digest_ctx);
2994*0Sstevel@tonic-gate out:
2995*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
2996*0Sstevel@tonic-gate 
2997*0Sstevel@tonic-gate release_minor:
2998*0Sstevel@tonic-gate 	if (rctl_bytes != 0) {
2999*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
3000*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(rctl_bytes, projp);
3001*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
3002*0Sstevel@tonic-gate 	}
3003*0Sstevel@tonic-gate 	crypto_release_minor(cm);
3004*0Sstevel@tonic-gate 
3005*0Sstevel@tonic-gate 	free_crypto_key(&key);
3006*0Sstevel@tonic-gate 
3007*0Sstevel@tonic-gate 	if (error != 0)
3008*0Sstevel@tonic-gate 		return (error);
3009*0Sstevel@tonic-gate 
3010*0Sstevel@tonic-gate 	STRUCT_FSET(digest_key, dk_return_value, rv);
3011*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(digest_key), arg,
3012*0Sstevel@tonic-gate 	    STRUCT_SIZE(digest_key)) != 0) {
3013*0Sstevel@tonic-gate 		return (EFAULT);
3014*0Sstevel@tonic-gate 	}
3015*0Sstevel@tonic-gate 	return (0);
3016*0Sstevel@tonic-gate }
3017*0Sstevel@tonic-gate 
3018*0Sstevel@tonic-gate /* ARGSUSED */
3019*0Sstevel@tonic-gate static int
3020*0Sstevel@tonic-gate digest_final(dev_t dev, caddr_t arg, int mode, int *rval)
3021*0Sstevel@tonic-gate {
3022*0Sstevel@tonic-gate 	return (common_final(dev, arg, mode, crypto_digest_final));
3023*0Sstevel@tonic-gate }
3024*0Sstevel@tonic-gate 
3025*0Sstevel@tonic-gate /* ARGSUSED */
3026*0Sstevel@tonic-gate static int
3027*0Sstevel@tonic-gate digest(dev_t dev, caddr_t arg, int mode, int *rval)
3028*0Sstevel@tonic-gate {
3029*0Sstevel@tonic-gate 	return (common_digest(dev, arg, mode, crypto_digest_single));
3030*0Sstevel@tonic-gate }
3031*0Sstevel@tonic-gate 
3032*0Sstevel@tonic-gate /*
3033*0Sstevel@tonic-gate  * ASSUMPTION: crypto_digest, crypto_sign, crypto_sign_recover,
3034*0Sstevel@tonic-gate  * and crypto_verify_recover are identical except for field names.
3035*0Sstevel@tonic-gate  */
3036*0Sstevel@tonic-gate static int
3037*0Sstevel@tonic-gate common_digest(dev_t dev, caddr_t arg, int mode,
3038*0Sstevel@tonic-gate     int (*single)(crypto_context_t, crypto_data_t *, crypto_data_t *,
3039*0Sstevel@tonic-gate     crypto_call_req_t *))
3040*0Sstevel@tonic-gate {
3041*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_digest, crypto_digest);
3042*0Sstevel@tonic-gate 	kproject_t *projp;
3043*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
3044*0Sstevel@tonic-gate 	crypto_minor_t *cm;
3045*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
3046*0Sstevel@tonic-gate 	crypto_data_t data, digest;
3047*0Sstevel@tonic-gate 	crypto_ctx_t **ctxpp;
3048*0Sstevel@tonic-gate 	size_t datalen, digestlen, need = 0;
3049*0Sstevel@tonic-gate 	char *digestbuf;
3050*0Sstevel@tonic-gate 	int error = 0;
3051*0Sstevel@tonic-gate 	int rv;
3052*0Sstevel@tonic-gate 
3053*0Sstevel@tonic-gate 	STRUCT_INIT(crypto_digest, mode);
3054*0Sstevel@tonic-gate 
3055*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3056*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "common_digest: failed holding minor");
3057*0Sstevel@tonic-gate 		return (ENXIO);
3058*0Sstevel@tonic-gate 	}
3059*0Sstevel@tonic-gate 
3060*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(crypto_digest),
3061*0Sstevel@tonic-gate 	    STRUCT_SIZE(crypto_digest)) != 0) {
3062*0Sstevel@tonic-gate 		crypto_release_minor(cm);
3063*0Sstevel@tonic-gate 		return (EFAULT);
3064*0Sstevel@tonic-gate 	}
3065*0Sstevel@tonic-gate 
3066*0Sstevel@tonic-gate 	data.cd_raw.iov_base = NULL;
3067*0Sstevel@tonic-gate 	digest.cd_raw.iov_base = NULL;
3068*0Sstevel@tonic-gate 
3069*0Sstevel@tonic-gate 	datalen = STRUCT_FGET(crypto_digest, cd_datalen);
3070*0Sstevel@tonic-gate 	digestlen = STRUCT_FGET(crypto_digest, cd_digestlen);
3071*0Sstevel@tonic-gate 
3072*0Sstevel@tonic-gate 	/*
3073*0Sstevel@tonic-gate 	 * Don't allocate output buffer unless both buffer pointer and
3074*0Sstevel@tonic-gate 	 * buffer length are not NULL or 0 (length).
3075*0Sstevel@tonic-gate 	 */
3076*0Sstevel@tonic-gate 	digestbuf = STRUCT_FGETP(crypto_digest, cd_digestbuf);
3077*0Sstevel@tonic-gate 	if (digestbuf == NULL || digestlen == 0) {
3078*0Sstevel@tonic-gate 		digestlen = 0;
3079*0Sstevel@tonic-gate 	}
3080*0Sstevel@tonic-gate 
3081*0Sstevel@tonic-gate 	if (datalen > crypto_max_buffer_len ||
3082*0Sstevel@tonic-gate 	    digestlen > crypto_max_buffer_len) {
3083*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "common_digest: buffer greater than %ld "
3084*0Sstevel@tonic-gate 		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
3085*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
3086*0Sstevel@tonic-gate 		goto release_minor;
3087*0Sstevel@tonic-gate 	}
3088*0Sstevel@tonic-gate 
3089*0Sstevel@tonic-gate 	need = datalen + digestlen;
3090*0Sstevel@tonic-gate 	if ((rv = crypto_buffer_check(need, &projp)) != CRYPTO_SUCCESS) {
3091*0Sstevel@tonic-gate 		need = 0;
3092*0Sstevel@tonic-gate 		goto release_minor;
3093*0Sstevel@tonic-gate 	}
3094*0Sstevel@tonic-gate 
3095*0Sstevel@tonic-gate 	INIT_RAW_CRYPTO_DATA(data, datalen);
3096*0Sstevel@tonic-gate 
3097*0Sstevel@tonic-gate 	if (datalen != 0 && copyin(STRUCT_FGETP(crypto_digest, cd_databuf),
3098*0Sstevel@tonic-gate 	    data.cd_raw.iov_base, datalen) != 0) {
3099*0Sstevel@tonic-gate 		error = EFAULT;
3100*0Sstevel@tonic-gate 		goto release_minor;
3101*0Sstevel@tonic-gate 	}
3102*0Sstevel@tonic-gate 
3103*0Sstevel@tonic-gate 	INIT_RAW_CRYPTO_DATA(digest, digestlen);
3104*0Sstevel@tonic-gate 
3105*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(crypto_digest, cd_session);
3106*0Sstevel@tonic-gate 
3107*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv))  {
3108*0Sstevel@tonic-gate 		goto release_minor;
3109*0Sstevel@tonic-gate 	}
3110*0Sstevel@tonic-gate 
3111*0Sstevel@tonic-gate 	ASSERT(single == crypto_digest_single ||
3112*0Sstevel@tonic-gate 	    single == crypto_sign_single ||
3113*0Sstevel@tonic-gate 	    single == crypto_verify_recover_single ||
3114*0Sstevel@tonic-gate 	    single == crypto_sign_recover_single);
3115*0Sstevel@tonic-gate 
3116*0Sstevel@tonic-gate 	if (single == crypto_digest_single) {
3117*0Sstevel@tonic-gate 		ctxpp = &sp->sd_digest_ctx;
3118*0Sstevel@tonic-gate 	} else if (single == crypto_sign_single) {
3119*0Sstevel@tonic-gate 		ctxpp = &sp->sd_sign_ctx;
3120*0Sstevel@tonic-gate 	} else if (single == crypto_verify_recover_single) {
3121*0Sstevel@tonic-gate 		ctxpp = &sp->sd_verify_recover_ctx;
3122*0Sstevel@tonic-gate 	} else {
3123*0Sstevel@tonic-gate 		ctxpp = &sp->sd_sign_recover_ctx;
3124*0Sstevel@tonic-gate 	}
3125*0Sstevel@tonic-gate 	rv = (single)(*ctxpp, &data, &digest, NULL);
3126*0Sstevel@tonic-gate 	if (KCF_CONTEXT_DONE(rv))
3127*0Sstevel@tonic-gate 		*ctxpp = NULL;
3128*0Sstevel@tonic-gate 
3129*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
3130*0Sstevel@tonic-gate 
3131*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS) {
3132*0Sstevel@tonic-gate 		ASSERT(digest.cd_length <= digestlen);
3133*0Sstevel@tonic-gate 		if (digest.cd_length != 0 && copyout(digest.cd_raw.iov_base,
3134*0Sstevel@tonic-gate 		    digestbuf, digest.cd_length) != 0) {
3135*0Sstevel@tonic-gate 			error = EFAULT;
3136*0Sstevel@tonic-gate 			goto release_minor;
3137*0Sstevel@tonic-gate 		}
3138*0Sstevel@tonic-gate 		STRUCT_FSET(crypto_digest, cd_digestlen, digest.cd_length);
3139*0Sstevel@tonic-gate 	}
3140*0Sstevel@tonic-gate 
3141*0Sstevel@tonic-gate 	if (rv == CRYPTO_BUFFER_TOO_SMALL) {
3142*0Sstevel@tonic-gate 		/*
3143*0Sstevel@tonic-gate 		 * The providers return CRYPTO_BUFFER_TOO_SMALL even for case 1
3144*0Sstevel@tonic-gate 		 * of section 11.2 of the pkcs11 spec. We catch it here and
3145*0Sstevel@tonic-gate 		 * provide the correct pkcs11 return value.
3146*0Sstevel@tonic-gate 		 */
3147*0Sstevel@tonic-gate 		if (STRUCT_FGETP(crypto_digest, cd_digestbuf) == NULL)
3148*0Sstevel@tonic-gate 			rv = CRYPTO_SUCCESS;
3149*0Sstevel@tonic-gate 		STRUCT_FSET(crypto_digest, cd_digestlen, digest.cd_length);
3150*0Sstevel@tonic-gate 	}
3151*0Sstevel@tonic-gate 
3152*0Sstevel@tonic-gate release_minor:
3153*0Sstevel@tonic-gate 	if (need != 0) {
3154*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
3155*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(need, projp);
3156*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
3157*0Sstevel@tonic-gate 	}
3158*0Sstevel@tonic-gate 	crypto_release_minor(cm);
3159*0Sstevel@tonic-gate 
3160*0Sstevel@tonic-gate 	if (data.cd_raw.iov_base != NULL)
3161*0Sstevel@tonic-gate 		kmem_free(data.cd_raw.iov_base, datalen);
3162*0Sstevel@tonic-gate 
3163*0Sstevel@tonic-gate 	if (digest.cd_raw.iov_base != NULL)
3164*0Sstevel@tonic-gate 		kmem_free(digest.cd_raw.iov_base, digestlen);
3165*0Sstevel@tonic-gate 
3166*0Sstevel@tonic-gate 	if (error != 0)
3167*0Sstevel@tonic-gate 		return (error);
3168*0Sstevel@tonic-gate 
3169*0Sstevel@tonic-gate 	STRUCT_FSET(crypto_digest, cd_return_value, rv);
3170*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(crypto_digest), arg,
3171*0Sstevel@tonic-gate 	    STRUCT_SIZE(crypto_digest)) != 0) {
3172*0Sstevel@tonic-gate 		return (EFAULT);
3173*0Sstevel@tonic-gate 	}
3174*0Sstevel@tonic-gate 	return (0);
3175*0Sstevel@tonic-gate }
3176*0Sstevel@tonic-gate 
3177*0Sstevel@tonic-gate /*
3178*0Sstevel@tonic-gate  * A helper function that does what the name suggests.
3179*0Sstevel@tonic-gate  * Returns 0 on success and non-zero otherwise.
3180*0Sstevel@tonic-gate  * On failure, out_pin is set to 0.
3181*0Sstevel@tonic-gate  */
3182*0Sstevel@tonic-gate int
3183*0Sstevel@tonic-gate get_pin_and_session_ptr(char *in_pin, char **out_pin, size_t pin_len,
3184*0Sstevel@tonic-gate     crypto_minor_t *cm, crypto_session_id_t sid, crypto_session_data_t **sp,
3185*0Sstevel@tonic-gate     int *rv, int *error)
3186*0Sstevel@tonic-gate {
3187*0Sstevel@tonic-gate 	char *tmp_pin = NULL;
3188*0Sstevel@tonic-gate 	int tmp_error = 0, tmp_rv = 0;
3189*0Sstevel@tonic-gate 
3190*0Sstevel@tonic-gate 	if (pin_len > KCF_MAX_PIN_LEN) {
3191*0Sstevel@tonic-gate 		tmp_rv = CRYPTO_PIN_LEN_RANGE;
3192*0Sstevel@tonic-gate 		goto out;
3193*0Sstevel@tonic-gate 	}
3194*0Sstevel@tonic-gate 	tmp_pin = kmem_alloc(pin_len, KM_SLEEP);
3195*0Sstevel@tonic-gate 
3196*0Sstevel@tonic-gate 	if (pin_len != 0 && copyin(in_pin, tmp_pin, pin_len) != 0) {
3197*0Sstevel@tonic-gate 		tmp_error = EFAULT;
3198*0Sstevel@tonic-gate 		goto out;
3199*0Sstevel@tonic-gate 	}
3200*0Sstevel@tonic-gate 
3201*0Sstevel@tonic-gate 	(void) get_session_ptr(sid, cm, sp, &tmp_error, &tmp_rv);
3202*0Sstevel@tonic-gate out:
3203*0Sstevel@tonic-gate 	*out_pin = tmp_pin;
3204*0Sstevel@tonic-gate 	*rv = tmp_rv;
3205*0Sstevel@tonic-gate 	*error = tmp_error;
3206*0Sstevel@tonic-gate 	return (tmp_rv | tmp_error);
3207*0Sstevel@tonic-gate }
3208*0Sstevel@tonic-gate 
3209*0Sstevel@tonic-gate /* ARGSUSED */
3210*0Sstevel@tonic-gate static int
3211*0Sstevel@tonic-gate set_pin(dev_t dev, caddr_t arg, int mode, int *rval)
3212*0Sstevel@tonic-gate {
3213*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_set_pin, set_pin);
3214*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
3215*0Sstevel@tonic-gate 	kcf_req_params_t params;
3216*0Sstevel@tonic-gate 	crypto_minor_t *cm;
3217*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
3218*0Sstevel@tonic-gate 	char *old_pin = NULL;
3219*0Sstevel@tonic-gate 	char *new_pin = NULL;
3220*0Sstevel@tonic-gate 	size_t old_pin_len;
3221*0Sstevel@tonic-gate 	size_t new_pin_len;
3222*0Sstevel@tonic-gate 	int error = 0;
3223*0Sstevel@tonic-gate 	int rv;
3224*0Sstevel@tonic-gate 
3225*0Sstevel@tonic-gate 	STRUCT_INIT(set_pin, mode);
3226*0Sstevel@tonic-gate 
3227*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3228*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "set_pin: failed holding minor");
3229*0Sstevel@tonic-gate 		return (ENXIO);
3230*0Sstevel@tonic-gate 	}
3231*0Sstevel@tonic-gate 
3232*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(set_pin),
3233*0Sstevel@tonic-gate 	    STRUCT_SIZE(set_pin)) != 0) {
3234*0Sstevel@tonic-gate 		crypto_release_minor(cm);
3235*0Sstevel@tonic-gate 		return (EFAULT);
3236*0Sstevel@tonic-gate 	}
3237*0Sstevel@tonic-gate 
3238*0Sstevel@tonic-gate 	old_pin_len = STRUCT_FGET(set_pin, sp_old_len);
3239*0Sstevel@tonic-gate 
3240*0Sstevel@tonic-gate 	if (get_pin_and_session_ptr(STRUCT_FGETP(set_pin, sp_old_pin),
3241*0Sstevel@tonic-gate 	    &old_pin, old_pin_len, cm, STRUCT_FGET(set_pin, sp_session),
3242*0Sstevel@tonic-gate 	    &sp, &rv, &error) != 0)
3243*0Sstevel@tonic-gate 		goto release_minor;
3244*0Sstevel@tonic-gate 
3245*0Sstevel@tonic-gate 	new_pin_len = STRUCT_FGET(set_pin, sp_new_len);
3246*0Sstevel@tonic-gate 	if (new_pin_len > KCF_MAX_PIN_LEN) {
3247*0Sstevel@tonic-gate 		rv = CRYPTO_PIN_LEN_RANGE;
3248*0Sstevel@tonic-gate 		goto out;
3249*0Sstevel@tonic-gate 	}
3250*0Sstevel@tonic-gate 	new_pin = kmem_alloc(new_pin_len, KM_SLEEP);
3251*0Sstevel@tonic-gate 
3252*0Sstevel@tonic-gate 	if (new_pin_len != 0 && copyin(STRUCT_FGETP(set_pin, sp_new_pin),
3253*0Sstevel@tonic-gate 	    new_pin, new_pin_len) != 0) {
3254*0Sstevel@tonic-gate 		error = EFAULT;
3255*0Sstevel@tonic-gate 		goto out;
3256*0Sstevel@tonic-gate 	}
3257*0Sstevel@tonic-gate 
3258*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider_nomech(
3259*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(provider_ops), CRYPTO_PROVIDER_OFFSET(set_pin),
3260*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
3261*0Sstevel@tonic-gate 		goto out;
3262*0Sstevel@tonic-gate 	}
3263*0Sstevel@tonic-gate 
3264*0Sstevel@tonic-gate 	KCF_WRAP_PROVMGMT_OPS_PARAMS(&params, KCF_OP_MGMT_SETPIN,
3265*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, old_pin, old_pin_len,
3266*0Sstevel@tonic-gate 	    new_pin, new_pin_len, NULL, NULL, real_provider);
3267*0Sstevel@tonic-gate 
3268*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
3269*0Sstevel@tonic-gate 
3270*0Sstevel@tonic-gate out:
3271*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
3272*0Sstevel@tonic-gate 
3273*0Sstevel@tonic-gate release_minor:
3274*0Sstevel@tonic-gate 	crypto_release_minor(cm);
3275*0Sstevel@tonic-gate 
3276*0Sstevel@tonic-gate 	if (old_pin != NULL) {
3277*0Sstevel@tonic-gate 		bzero(old_pin, old_pin_len);
3278*0Sstevel@tonic-gate 		kmem_free(old_pin, old_pin_len);
3279*0Sstevel@tonic-gate 	}
3280*0Sstevel@tonic-gate 
3281*0Sstevel@tonic-gate 	if (new_pin != NULL) {
3282*0Sstevel@tonic-gate 		bzero(new_pin, new_pin_len);
3283*0Sstevel@tonic-gate 		kmem_free(new_pin, new_pin_len);
3284*0Sstevel@tonic-gate 	}
3285*0Sstevel@tonic-gate 
3286*0Sstevel@tonic-gate 	if (error != 0)
3287*0Sstevel@tonic-gate 		return (error);
3288*0Sstevel@tonic-gate 
3289*0Sstevel@tonic-gate 	STRUCT_FSET(set_pin, sp_return_value, rv);
3290*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(set_pin), arg, STRUCT_SIZE(set_pin)) != 0) {
3291*0Sstevel@tonic-gate 		return (EFAULT);
3292*0Sstevel@tonic-gate 	}
3293*0Sstevel@tonic-gate 	return (0);
3294*0Sstevel@tonic-gate }
3295*0Sstevel@tonic-gate 
3296*0Sstevel@tonic-gate /* ARGSUSED */
3297*0Sstevel@tonic-gate static int
3298*0Sstevel@tonic-gate login(dev_t dev, caddr_t arg, int mode, int *rval)
3299*0Sstevel@tonic-gate {
3300*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_login, login);
3301*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
3302*0Sstevel@tonic-gate 	kcf_req_params_t params;
3303*0Sstevel@tonic-gate 	crypto_minor_t *cm;
3304*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
3305*0Sstevel@tonic-gate 	size_t pin_len;
3306*0Sstevel@tonic-gate 	char *pin;
3307*0Sstevel@tonic-gate 	uint_t user_type;
3308*0Sstevel@tonic-gate 	int error = 0;
3309*0Sstevel@tonic-gate 	int rv;
3310*0Sstevel@tonic-gate 
3311*0Sstevel@tonic-gate 	STRUCT_INIT(login, mode);
3312*0Sstevel@tonic-gate 
3313*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3314*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "login: failed holding minor");
3315*0Sstevel@tonic-gate 		return (ENXIO);
3316*0Sstevel@tonic-gate 	}
3317*0Sstevel@tonic-gate 
3318*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(login), STRUCT_SIZE(login)) != 0) {
3319*0Sstevel@tonic-gate 		crypto_release_minor(cm);
3320*0Sstevel@tonic-gate 		return (EFAULT);
3321*0Sstevel@tonic-gate 	}
3322*0Sstevel@tonic-gate 
3323*0Sstevel@tonic-gate 	user_type = STRUCT_FGET(login, co_user_type);
3324*0Sstevel@tonic-gate 
3325*0Sstevel@tonic-gate 	pin_len = STRUCT_FGET(login, co_pin_len);
3326*0Sstevel@tonic-gate 
3327*0Sstevel@tonic-gate 	if (get_pin_and_session_ptr(STRUCT_FGETP(login, co_pin),
3328*0Sstevel@tonic-gate 	    &pin, pin_len, cm, STRUCT_FGET(login, co_session),
3329*0Sstevel@tonic-gate 	    &sp, &rv, &error) != 0) {
3330*0Sstevel@tonic-gate 		if (rv == CRYPTO_PIN_LEN_RANGE)
3331*0Sstevel@tonic-gate 			rv = CRYPTO_PIN_INCORRECT;
3332*0Sstevel@tonic-gate 		goto release_minor;
3333*0Sstevel@tonic-gate 	}
3334*0Sstevel@tonic-gate 
3335*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider_nomech(
3336*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(session_ops),
3337*0Sstevel@tonic-gate 	    CRYPTO_SESSION_OFFSET(session_login),
3338*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
3339*0Sstevel@tonic-gate 		goto out;
3340*0Sstevel@tonic-gate 	}
3341*0Sstevel@tonic-gate 
3342*0Sstevel@tonic-gate 	KCF_WRAP_SESSION_OPS_PARAMS(&params, KCF_OP_SESSION_LOGIN, NULL,
3343*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, user_type, pin, pin_len,
3344*0Sstevel@tonic-gate 	    real_provider);
3345*0Sstevel@tonic-gate 
3346*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
3347*0Sstevel@tonic-gate 
3348*0Sstevel@tonic-gate out:
3349*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
3350*0Sstevel@tonic-gate 
3351*0Sstevel@tonic-gate release_minor:
3352*0Sstevel@tonic-gate 	crypto_release_minor(cm);
3353*0Sstevel@tonic-gate 
3354*0Sstevel@tonic-gate 	if (pin != NULL) {
3355*0Sstevel@tonic-gate 		bzero(pin, pin_len);
3356*0Sstevel@tonic-gate 		kmem_free(pin, pin_len);
3357*0Sstevel@tonic-gate 	}
3358*0Sstevel@tonic-gate 
3359*0Sstevel@tonic-gate 	if (error != 0)
3360*0Sstevel@tonic-gate 		return (error);
3361*0Sstevel@tonic-gate 
3362*0Sstevel@tonic-gate 	STRUCT_FSET(login, co_return_value, rv);
3363*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(login), arg, STRUCT_SIZE(login)) != 0) {
3364*0Sstevel@tonic-gate 		return (EFAULT);
3365*0Sstevel@tonic-gate 	}
3366*0Sstevel@tonic-gate 	return (0);
3367*0Sstevel@tonic-gate }
3368*0Sstevel@tonic-gate 
3369*0Sstevel@tonic-gate /* ARGSUSED */
3370*0Sstevel@tonic-gate static int
3371*0Sstevel@tonic-gate logout(dev_t dev, caddr_t arg, int mode, int *rval)
3372*0Sstevel@tonic-gate {
3373*0Sstevel@tonic-gate 	crypto_logout_t logout;
3374*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
3375*0Sstevel@tonic-gate 	kcf_req_params_t params;
3376*0Sstevel@tonic-gate 	crypto_minor_t *cm;
3377*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
3378*0Sstevel@tonic-gate 	int error = 0;
3379*0Sstevel@tonic-gate 	int rv;
3380*0Sstevel@tonic-gate 
3381*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3382*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "logout: failed holding minor");
3383*0Sstevel@tonic-gate 		return (ENXIO);
3384*0Sstevel@tonic-gate 	}
3385*0Sstevel@tonic-gate 
3386*0Sstevel@tonic-gate 	if (copyin(arg, &logout, sizeof (logout)) != 0) {
3387*0Sstevel@tonic-gate 		crypto_release_minor(cm);
3388*0Sstevel@tonic-gate 		return (EFAULT);
3389*0Sstevel@tonic-gate 	}
3390*0Sstevel@tonic-gate 
3391*0Sstevel@tonic-gate 	if (!get_session_ptr(logout.cl_session, cm, &sp, &error, &rv))  {
3392*0Sstevel@tonic-gate 		goto release_minor;
3393*0Sstevel@tonic-gate 	}
3394*0Sstevel@tonic-gate 
3395*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider_nomech(
3396*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(session_ops),
3397*0Sstevel@tonic-gate 	    CRYPTO_SESSION_OFFSET(session_logout),
3398*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
3399*0Sstevel@tonic-gate 		goto out;
3400*0Sstevel@tonic-gate 	}
3401*0Sstevel@tonic-gate 
3402*0Sstevel@tonic-gate 	KCF_WRAP_SESSION_OPS_PARAMS(&params, KCF_OP_SESSION_LOGOUT, NULL,
3403*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, 0, NULL, 0, real_provider);
3404*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
3405*0Sstevel@tonic-gate 
3406*0Sstevel@tonic-gate out:
3407*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
3408*0Sstevel@tonic-gate 
3409*0Sstevel@tonic-gate release_minor:
3410*0Sstevel@tonic-gate 	crypto_release_minor(cm);
3411*0Sstevel@tonic-gate 
3412*0Sstevel@tonic-gate 	if (error != 0)
3413*0Sstevel@tonic-gate 		return (error);
3414*0Sstevel@tonic-gate 
3415*0Sstevel@tonic-gate 	logout.cl_return_value = rv;
3416*0Sstevel@tonic-gate 	if (copyout(&logout, arg, sizeof (logout)) != 0) {
3417*0Sstevel@tonic-gate 		return (EFAULT);
3418*0Sstevel@tonic-gate 	}
3419*0Sstevel@tonic-gate 	return (0);
3420*0Sstevel@tonic-gate }
3421*0Sstevel@tonic-gate 
3422*0Sstevel@tonic-gate /* ARGSUSED */
3423*0Sstevel@tonic-gate static int
3424*0Sstevel@tonic-gate sign_init(dev_t dev, caddr_t arg, int mode, int *rval)
3425*0Sstevel@tonic-gate {
3426*0Sstevel@tonic-gate 	return (sign_verify_init(dev, arg, mode, crypto_sign_init_prov));
3427*0Sstevel@tonic-gate }
3428*0Sstevel@tonic-gate 
3429*0Sstevel@tonic-gate /* ARGSUSED */
3430*0Sstevel@tonic-gate static int
3431*0Sstevel@tonic-gate sign_recover_init(dev_t dev, caddr_t arg, int mode, int *rval)
3432*0Sstevel@tonic-gate {
3433*0Sstevel@tonic-gate 	return (sign_verify_init(dev, arg, mode,
3434*0Sstevel@tonic-gate 	    crypto_sign_recover_init_prov));
3435*0Sstevel@tonic-gate }
3436*0Sstevel@tonic-gate 
3437*0Sstevel@tonic-gate /* ARGSUSED */
3438*0Sstevel@tonic-gate static int
3439*0Sstevel@tonic-gate verify_init(dev_t dev, caddr_t arg, int mode, int *rval)
3440*0Sstevel@tonic-gate {
3441*0Sstevel@tonic-gate 	return (sign_verify_init(dev, arg, mode, crypto_verify_init_prov));
3442*0Sstevel@tonic-gate }
3443*0Sstevel@tonic-gate 
3444*0Sstevel@tonic-gate /* ARGSUSED */
3445*0Sstevel@tonic-gate static int
3446*0Sstevel@tonic-gate verify_recover_init(dev_t dev, caddr_t arg, int mode, int *rval)
3447*0Sstevel@tonic-gate {
3448*0Sstevel@tonic-gate 	return (sign_verify_init(dev, arg, mode,
3449*0Sstevel@tonic-gate 	    crypto_verify_recover_init_prov));
3450*0Sstevel@tonic-gate }
3451*0Sstevel@tonic-gate 
3452*0Sstevel@tonic-gate /*
3453*0Sstevel@tonic-gate  * ASSUMPTION: crypto_sign_init, crypto_verify_init, crypto_sign_recover_init,
3454*0Sstevel@tonic-gate  * and crypto_verify_recover_init structures are identical
3455*0Sstevel@tonic-gate  * except for field names.
3456*0Sstevel@tonic-gate  */
3457*0Sstevel@tonic-gate static int
3458*0Sstevel@tonic-gate sign_verify_init(dev_t dev, caddr_t arg, int mode,
3459*0Sstevel@tonic-gate     int (*init)(kcf_provider_desc_t *, crypto_session_id_t,
3460*0Sstevel@tonic-gate     crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
3461*0Sstevel@tonic-gate     crypto_context_t *, crypto_call_req_t *))
3462*0Sstevel@tonic-gate {
3463*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_sign_init, sign_init);
3464*0Sstevel@tonic-gate 	kproject_t *mech_projp, *key_projp;
3465*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
3466*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
3467*0Sstevel@tonic-gate 	crypto_mechanism_t mech;
3468*0Sstevel@tonic-gate 	crypto_key_t key;
3469*0Sstevel@tonic-gate 	crypto_minor_t *cm;
3470*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
3471*0Sstevel@tonic-gate 	crypto_context_t cc;
3472*0Sstevel@tonic-gate 	crypto_ctx_t **ctxpp;
3473*0Sstevel@tonic-gate 	size_t mech_rctl_bytes = 0;
3474*0Sstevel@tonic-gate 	size_t key_rctl_bytes = 0;
3475*0Sstevel@tonic-gate 	size_t carry;
3476*0Sstevel@tonic-gate 	offset_t offset_1, offset_2;
3477*0Sstevel@tonic-gate 	int error = 0;
3478*0Sstevel@tonic-gate 	int rv;
3479*0Sstevel@tonic-gate 
3480*0Sstevel@tonic-gate 	STRUCT_INIT(sign_init, mode);
3481*0Sstevel@tonic-gate 
3482*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3483*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "sign_verify_init: failed holding minor");
3484*0Sstevel@tonic-gate 		return (ENXIO);
3485*0Sstevel@tonic-gate 	}
3486*0Sstevel@tonic-gate 
3487*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(sign_init), STRUCT_SIZE(sign_init)) != 0) {
3488*0Sstevel@tonic-gate 		crypto_release_minor(cm);
3489*0Sstevel@tonic-gate 		return (EFAULT);
3490*0Sstevel@tonic-gate 	}
3491*0Sstevel@tonic-gate 
3492*0Sstevel@tonic-gate 	mech.cm_param = NULL;
3493*0Sstevel@tonic-gate 	bzero(&key, sizeof (key));
3494*0Sstevel@tonic-gate 
3495*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(sign_init, si_session);
3496*0Sstevel@tonic-gate 
3497*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
3498*0Sstevel@tonic-gate 		goto release_minor;
3499*0Sstevel@tonic-gate 	}
3500*0Sstevel@tonic-gate 
3501*0Sstevel@tonic-gate 	if (!copyin_mech(mode, STRUCT_FADDR(sign_init, si_mech), &mech,
3502*0Sstevel@tonic-gate 	    &mech_rctl_bytes, &carry, &rv, &error, &mech_projp)) {
3503*0Sstevel@tonic-gate 		goto out;
3504*0Sstevel@tonic-gate 	}
3505*0Sstevel@tonic-gate 
3506*0Sstevel@tonic-gate 	ASSERT(init == crypto_sign_init_prov ||
3507*0Sstevel@tonic-gate 	    init == crypto_verify_init_prov ||
3508*0Sstevel@tonic-gate 	    init == crypto_sign_recover_init_prov ||
3509*0Sstevel@tonic-gate 	    init == crypto_verify_recover_init_prov);
3510*0Sstevel@tonic-gate 
3511*0Sstevel@tonic-gate 	if (init == crypto_sign_init_prov) {
3512*0Sstevel@tonic-gate 		offset_1 = CRYPTO_OPS_OFFSET(sign_ops);
3513*0Sstevel@tonic-gate 		offset_2 = CRYPTO_SIGN_OFFSET(sign_init);
3514*0Sstevel@tonic-gate 		ctxpp = &sp->sd_sign_ctx;
3515*0Sstevel@tonic-gate 	} else if (init == crypto_verify_init_prov) {
3516*0Sstevel@tonic-gate 		offset_1 = CRYPTO_OPS_OFFSET(verify_ops);
3517*0Sstevel@tonic-gate 		offset_2 = CRYPTO_VERIFY_OFFSET(verify_init);
3518*0Sstevel@tonic-gate 		ctxpp = &sp->sd_verify_ctx;
3519*0Sstevel@tonic-gate 	} else if (init == crypto_sign_recover_init_prov) {
3520*0Sstevel@tonic-gate 		offset_1 = CRYPTO_OPS_OFFSET(sign_ops);
3521*0Sstevel@tonic-gate 		offset_2 = CRYPTO_SIGN_OFFSET(sign_recover_init);
3522*0Sstevel@tonic-gate 		ctxpp = &sp->sd_sign_recover_ctx;
3523*0Sstevel@tonic-gate 	} else {
3524*0Sstevel@tonic-gate 		offset_1 = CRYPTO_OPS_OFFSET(verify_ops);
3525*0Sstevel@tonic-gate 		offset_2 = CRYPTO_VERIFY_OFFSET(verify_recover_init);
3526*0Sstevel@tonic-gate 		ctxpp = &sp->sd_verify_recover_ctx;
3527*0Sstevel@tonic-gate 	}
3528*0Sstevel@tonic-gate 
3529*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider(mech.cm_type, offset_1,
3530*0Sstevel@tonic-gate 	    offset_2, sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
3531*0Sstevel@tonic-gate 		goto out;
3532*0Sstevel@tonic-gate 	}
3533*0Sstevel@tonic-gate 
3534*0Sstevel@tonic-gate 	if (!copyin_key(mode, STRUCT_FADDR(sign_init, si_key), &key,
3535*0Sstevel@tonic-gate 	    &key_rctl_bytes, &rv, &error, carry, &key_projp)) {
3536*0Sstevel@tonic-gate 		goto out;
3537*0Sstevel@tonic-gate 	}
3538*0Sstevel@tonic-gate 
3539*0Sstevel@tonic-gate 	rv = (init)(real_provider, sp->sd_provider_session->ps_session,
3540*0Sstevel@tonic-gate 	    &mech, &key, NULL, &cc, NULL);
3541*0Sstevel@tonic-gate 
3542*0Sstevel@tonic-gate 	/*
3543*0Sstevel@tonic-gate 	 * Check if a context already exists. If so, it means it is being
3544*0Sstevel@tonic-gate 	 * abandoned. So, cancel it to avoid leaking it.
3545*0Sstevel@tonic-gate 	 */
3546*0Sstevel@tonic-gate 	if (*ctxpp != NULL)
3547*0Sstevel@tonic-gate 		CRYPTO_CANCEL_CTX(ctxpp);
3548*0Sstevel@tonic-gate 	*ctxpp = (rv == CRYPTO_SUCCESS) ? cc : NULL;
3549*0Sstevel@tonic-gate 
3550*0Sstevel@tonic-gate out:
3551*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
3552*0Sstevel@tonic-gate 
3553*0Sstevel@tonic-gate release_minor:
3554*0Sstevel@tonic-gate 	mutex_enter(&crypto_rctl_lock);
3555*0Sstevel@tonic-gate 	if (mech_rctl_bytes != 0)
3556*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(mech_rctl_bytes, mech_projp);
3557*0Sstevel@tonic-gate 	if (key_rctl_bytes != 0)
3558*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(key_rctl_bytes, key_projp);
3559*0Sstevel@tonic-gate 	mutex_exit(&crypto_rctl_lock);
3560*0Sstevel@tonic-gate 	crypto_release_minor(cm);
3561*0Sstevel@tonic-gate 
3562*0Sstevel@tonic-gate 	if (mech.cm_param != NULL)
3563*0Sstevel@tonic-gate 		kmem_free(mech.cm_param, mech.cm_param_len);
3564*0Sstevel@tonic-gate 
3565*0Sstevel@tonic-gate 	free_crypto_key(&key);
3566*0Sstevel@tonic-gate 
3567*0Sstevel@tonic-gate 	if (error != 0)
3568*0Sstevel@tonic-gate 		return (error);
3569*0Sstevel@tonic-gate 
3570*0Sstevel@tonic-gate 	STRUCT_FSET(sign_init, si_return_value, rv);
3571*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(sign_init), arg, STRUCT_SIZE(sign_init)) != 0) {
3572*0Sstevel@tonic-gate 		return (EFAULT);
3573*0Sstevel@tonic-gate 	}
3574*0Sstevel@tonic-gate 	return (0);
3575*0Sstevel@tonic-gate }
3576*0Sstevel@tonic-gate 
3577*0Sstevel@tonic-gate /* ARGSUSED */
3578*0Sstevel@tonic-gate static int
3579*0Sstevel@tonic-gate sign(dev_t dev, caddr_t arg, int mode, int *rval)
3580*0Sstevel@tonic-gate {
3581*0Sstevel@tonic-gate 	return (common_digest(dev, arg, mode, crypto_sign_single));
3582*0Sstevel@tonic-gate }
3583*0Sstevel@tonic-gate 
3584*0Sstevel@tonic-gate /* ARGSUSED */
3585*0Sstevel@tonic-gate static int
3586*0Sstevel@tonic-gate sign_recover(dev_t dev, caddr_t arg, int mode, int *rval)
3587*0Sstevel@tonic-gate {
3588*0Sstevel@tonic-gate 	return (common_digest(dev, arg, mode, crypto_sign_recover_single));
3589*0Sstevel@tonic-gate }
3590*0Sstevel@tonic-gate 
3591*0Sstevel@tonic-gate /* ARGSUSED */
3592*0Sstevel@tonic-gate static int
3593*0Sstevel@tonic-gate verify(dev_t dev, caddr_t arg, int mode, int *rval)
3594*0Sstevel@tonic-gate {
3595*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_verify, verify);
3596*0Sstevel@tonic-gate 	kproject_t *projp;
3597*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
3598*0Sstevel@tonic-gate 	crypto_minor_t *cm;
3599*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
3600*0Sstevel@tonic-gate 	crypto_data_t data, sign;
3601*0Sstevel@tonic-gate 	size_t datalen, signlen, need = 0;
3602*0Sstevel@tonic-gate 	int error = 0;
3603*0Sstevel@tonic-gate 	int rv;
3604*0Sstevel@tonic-gate 
3605*0Sstevel@tonic-gate 	STRUCT_INIT(verify, mode);
3606*0Sstevel@tonic-gate 
3607*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3608*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "verify: failed holding minor");
3609*0Sstevel@tonic-gate 		return (ENXIO);
3610*0Sstevel@tonic-gate 	}
3611*0Sstevel@tonic-gate 
3612*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(verify), STRUCT_SIZE(verify)) != 0) {
3613*0Sstevel@tonic-gate 		crypto_release_minor(cm);
3614*0Sstevel@tonic-gate 		return (EFAULT);
3615*0Sstevel@tonic-gate 	}
3616*0Sstevel@tonic-gate 
3617*0Sstevel@tonic-gate 	data.cd_raw.iov_base = NULL;
3618*0Sstevel@tonic-gate 	sign.cd_raw.iov_base = NULL;
3619*0Sstevel@tonic-gate 
3620*0Sstevel@tonic-gate 	datalen = STRUCT_FGET(verify, cv_datalen);
3621*0Sstevel@tonic-gate 	signlen = STRUCT_FGET(verify, cv_signlen);
3622*0Sstevel@tonic-gate 	if (datalen > crypto_max_buffer_len ||
3623*0Sstevel@tonic-gate 	    signlen > crypto_max_buffer_len) {
3624*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "verify: buffer greater than %ld bytes, "
3625*0Sstevel@tonic-gate 		"pid = %d", crypto_max_buffer_len, curproc->p_pid);
3626*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
3627*0Sstevel@tonic-gate 		goto release_minor;
3628*0Sstevel@tonic-gate 	}
3629*0Sstevel@tonic-gate 
3630*0Sstevel@tonic-gate 	need = datalen + signlen;
3631*0Sstevel@tonic-gate 	if ((rv = crypto_buffer_check(need, &projp)) != CRYPTO_SUCCESS) {
3632*0Sstevel@tonic-gate 		need = 0;
3633*0Sstevel@tonic-gate 		goto release_minor;
3634*0Sstevel@tonic-gate 	}
3635*0Sstevel@tonic-gate 
3636*0Sstevel@tonic-gate 	INIT_RAW_CRYPTO_DATA(data, datalen);
3637*0Sstevel@tonic-gate 	INIT_RAW_CRYPTO_DATA(sign, signlen);
3638*0Sstevel@tonic-gate 
3639*0Sstevel@tonic-gate 	if (datalen != 0 && copyin(STRUCT_FGETP(verify, cv_databuf),
3640*0Sstevel@tonic-gate 	    data.cd_raw.iov_base, datalen) != 0) {
3641*0Sstevel@tonic-gate 		error = EFAULT;
3642*0Sstevel@tonic-gate 		goto release_minor;
3643*0Sstevel@tonic-gate 	}
3644*0Sstevel@tonic-gate 
3645*0Sstevel@tonic-gate 	if (signlen != 0 && copyin(STRUCT_FGETP(verify, cv_signbuf),
3646*0Sstevel@tonic-gate 	    sign.cd_raw.iov_base, signlen) != 0) {
3647*0Sstevel@tonic-gate 		error = EFAULT;
3648*0Sstevel@tonic-gate 		goto release_minor;
3649*0Sstevel@tonic-gate 	}
3650*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(verify, cv_session);
3651*0Sstevel@tonic-gate 
3652*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
3653*0Sstevel@tonic-gate 		goto release_minor;
3654*0Sstevel@tonic-gate 	}
3655*0Sstevel@tonic-gate 
3656*0Sstevel@tonic-gate 	rv = crypto_verify_single(sp->sd_verify_ctx, &data, &sign, NULL);
3657*0Sstevel@tonic-gate 	if (KCF_CONTEXT_DONE(rv))
3658*0Sstevel@tonic-gate 		sp->sd_verify_ctx = NULL;
3659*0Sstevel@tonic-gate 
3660*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
3661*0Sstevel@tonic-gate 
3662*0Sstevel@tonic-gate release_minor:
3663*0Sstevel@tonic-gate 	if (need != 0) {
3664*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
3665*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(need, projp);
3666*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
3667*0Sstevel@tonic-gate 	}
3668*0Sstevel@tonic-gate 	crypto_release_minor(cm);
3669*0Sstevel@tonic-gate 
3670*0Sstevel@tonic-gate 	if (data.cd_raw.iov_base != NULL)
3671*0Sstevel@tonic-gate 		kmem_free(data.cd_raw.iov_base, datalen);
3672*0Sstevel@tonic-gate 
3673*0Sstevel@tonic-gate 	if (sign.cd_raw.iov_base != NULL)
3674*0Sstevel@tonic-gate 		kmem_free(sign.cd_raw.iov_base, signlen);
3675*0Sstevel@tonic-gate 
3676*0Sstevel@tonic-gate 	if (error != 0)
3677*0Sstevel@tonic-gate 		return (error);
3678*0Sstevel@tonic-gate 
3679*0Sstevel@tonic-gate 	STRUCT_FSET(verify, cv_return_value, rv);
3680*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(verify), arg, STRUCT_SIZE(verify)) != 0) {
3681*0Sstevel@tonic-gate 		return (EFAULT);
3682*0Sstevel@tonic-gate 	}
3683*0Sstevel@tonic-gate 	return (0);
3684*0Sstevel@tonic-gate }
3685*0Sstevel@tonic-gate 
3686*0Sstevel@tonic-gate /* ARGSUSED */
3687*0Sstevel@tonic-gate static int
3688*0Sstevel@tonic-gate verify_recover(dev_t dev, caddr_t arg, int mode, int *rval)
3689*0Sstevel@tonic-gate {
3690*0Sstevel@tonic-gate 	return (common_digest(dev, arg, mode, crypto_verify_recover_single));
3691*0Sstevel@tonic-gate }
3692*0Sstevel@tonic-gate 
3693*0Sstevel@tonic-gate /* ARGSUSED */
3694*0Sstevel@tonic-gate static int
3695*0Sstevel@tonic-gate sign_update(dev_t dev, caddr_t arg, int mode, int *rval)
3696*0Sstevel@tonic-gate {
3697*0Sstevel@tonic-gate 	return (sign_verify_update(dev, arg, mode, crypto_sign_update));
3698*0Sstevel@tonic-gate }
3699*0Sstevel@tonic-gate 
3700*0Sstevel@tonic-gate /* ARGSUSED */
3701*0Sstevel@tonic-gate static int
3702*0Sstevel@tonic-gate verify_update(dev_t dev, caddr_t arg, int mode, int *rval)
3703*0Sstevel@tonic-gate {
3704*0Sstevel@tonic-gate 	return (sign_verify_update(dev, arg, mode, crypto_verify_update));
3705*0Sstevel@tonic-gate }
3706*0Sstevel@tonic-gate 
3707*0Sstevel@tonic-gate /*
3708*0Sstevel@tonic-gate  * ASSUMPTION: crypto_sign_update and crypto_verify_update structures
3709*0Sstevel@tonic-gate  * are identical except for field names.
3710*0Sstevel@tonic-gate  */
3711*0Sstevel@tonic-gate static int
3712*0Sstevel@tonic-gate sign_verify_update(dev_t dev, caddr_t arg, int mode,
3713*0Sstevel@tonic-gate     int (*update)(crypto_context_t, crypto_data_t *, crypto_call_req_t *))
3714*0Sstevel@tonic-gate {
3715*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_sign_update, sign_update);
3716*0Sstevel@tonic-gate 	kproject_t *projp;
3717*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
3718*0Sstevel@tonic-gate 	crypto_minor_t *cm;
3719*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
3720*0Sstevel@tonic-gate 	crypto_ctx_t **ctxpp;
3721*0Sstevel@tonic-gate 	crypto_data_t data;
3722*0Sstevel@tonic-gate 	size_t datalen, need = 0;
3723*0Sstevel@tonic-gate 	int error = 0;
3724*0Sstevel@tonic-gate 	int rv;
3725*0Sstevel@tonic-gate 
3726*0Sstevel@tonic-gate 	STRUCT_INIT(sign_update, mode);
3727*0Sstevel@tonic-gate 
3728*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3729*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "sign_verify_update: failed holding minor");
3730*0Sstevel@tonic-gate 		return (ENXIO);
3731*0Sstevel@tonic-gate 	}
3732*0Sstevel@tonic-gate 
3733*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(sign_update),
3734*0Sstevel@tonic-gate 	    STRUCT_SIZE(sign_update)) != 0) {
3735*0Sstevel@tonic-gate 		crypto_release_minor(cm);
3736*0Sstevel@tonic-gate 		return (EFAULT);
3737*0Sstevel@tonic-gate 	}
3738*0Sstevel@tonic-gate 
3739*0Sstevel@tonic-gate 	data.cd_raw.iov_base = NULL;
3740*0Sstevel@tonic-gate 
3741*0Sstevel@tonic-gate 	datalen = STRUCT_FGET(sign_update, su_datalen);
3742*0Sstevel@tonic-gate 	if (datalen > crypto_max_buffer_len) {
3743*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "sign_verify_update: buffer greater than %ld "
3744*0Sstevel@tonic-gate 		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
3745*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
3746*0Sstevel@tonic-gate 		goto release_minor;
3747*0Sstevel@tonic-gate 	}
3748*0Sstevel@tonic-gate 
3749*0Sstevel@tonic-gate 	if ((rv = crypto_buffer_check(datalen, &projp)) != CRYPTO_SUCCESS) {
3750*0Sstevel@tonic-gate 		goto release_minor;
3751*0Sstevel@tonic-gate 	}
3752*0Sstevel@tonic-gate 	need = datalen;
3753*0Sstevel@tonic-gate 
3754*0Sstevel@tonic-gate 	INIT_RAW_CRYPTO_DATA(data, datalen);
3755*0Sstevel@tonic-gate 
3756*0Sstevel@tonic-gate 	if (datalen != 0 && copyin(STRUCT_FGETP(sign_update, su_databuf),
3757*0Sstevel@tonic-gate 	    data.cd_raw.iov_base, datalen) != 0) {
3758*0Sstevel@tonic-gate 		error = EFAULT;
3759*0Sstevel@tonic-gate 		goto release_minor;
3760*0Sstevel@tonic-gate 	}
3761*0Sstevel@tonic-gate 
3762*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(sign_update, su_session);
3763*0Sstevel@tonic-gate 
3764*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
3765*0Sstevel@tonic-gate 		goto release_minor;
3766*0Sstevel@tonic-gate 	}
3767*0Sstevel@tonic-gate 
3768*0Sstevel@tonic-gate 	ctxpp = (update == crypto_sign_update) ?
3769*0Sstevel@tonic-gate 	    &sp->sd_sign_ctx : &sp->sd_verify_ctx;
3770*0Sstevel@tonic-gate 
3771*0Sstevel@tonic-gate 	rv = (update)(*ctxpp, &data, NULL);
3772*0Sstevel@tonic-gate 	if (rv != CRYPTO_SUCCESS)
3773*0Sstevel@tonic-gate 		CRYPTO_CANCEL_CTX(ctxpp);
3774*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
3775*0Sstevel@tonic-gate 
3776*0Sstevel@tonic-gate release_minor:
3777*0Sstevel@tonic-gate 	if (need != 0) {
3778*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
3779*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(need, projp);
3780*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
3781*0Sstevel@tonic-gate 	}
3782*0Sstevel@tonic-gate 	crypto_release_minor(cm);
3783*0Sstevel@tonic-gate 
3784*0Sstevel@tonic-gate 	if (data.cd_raw.iov_base != NULL)
3785*0Sstevel@tonic-gate 		kmem_free(data.cd_raw.iov_base, datalen);
3786*0Sstevel@tonic-gate 
3787*0Sstevel@tonic-gate 	if (error != 0)
3788*0Sstevel@tonic-gate 		return (error);
3789*0Sstevel@tonic-gate 
3790*0Sstevel@tonic-gate 	STRUCT_FSET(sign_update, su_return_value, rv);
3791*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(sign_update), arg,
3792*0Sstevel@tonic-gate 	    STRUCT_SIZE(sign_update)) != 0) {
3793*0Sstevel@tonic-gate 		return (EFAULT);
3794*0Sstevel@tonic-gate 	}
3795*0Sstevel@tonic-gate 	return (0);
3796*0Sstevel@tonic-gate }
3797*0Sstevel@tonic-gate 
3798*0Sstevel@tonic-gate /* ARGSUSED */
3799*0Sstevel@tonic-gate static int
3800*0Sstevel@tonic-gate sign_final(dev_t dev, caddr_t arg, int mode, int *rval)
3801*0Sstevel@tonic-gate {
3802*0Sstevel@tonic-gate 	return (common_final(dev, arg, mode, crypto_sign_final));
3803*0Sstevel@tonic-gate }
3804*0Sstevel@tonic-gate 
3805*0Sstevel@tonic-gate /*
3806*0Sstevel@tonic-gate  * Can't use the common final because it does a copyout of
3807*0Sstevel@tonic-gate  * the final part.
3808*0Sstevel@tonic-gate  */
3809*0Sstevel@tonic-gate /* ARGSUSED */
3810*0Sstevel@tonic-gate static int
3811*0Sstevel@tonic-gate verify_final(dev_t dev, caddr_t arg, int mode, int *rval)
3812*0Sstevel@tonic-gate {
3813*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_verify_final, verify_final);
3814*0Sstevel@tonic-gate 	kproject_t *projp;
3815*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
3816*0Sstevel@tonic-gate 	crypto_minor_t *cm;
3817*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
3818*0Sstevel@tonic-gate 	crypto_data_t sign;
3819*0Sstevel@tonic-gate 	size_t signlen, need = 0;
3820*0Sstevel@tonic-gate 	int error = 0;
3821*0Sstevel@tonic-gate 	int rv;
3822*0Sstevel@tonic-gate 
3823*0Sstevel@tonic-gate 	STRUCT_INIT(verify_final, mode);
3824*0Sstevel@tonic-gate 
3825*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3826*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "verify_final: failed holding minor");
3827*0Sstevel@tonic-gate 		return (ENXIO);
3828*0Sstevel@tonic-gate 	}
3829*0Sstevel@tonic-gate 
3830*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(verify_final),
3831*0Sstevel@tonic-gate 	    STRUCT_SIZE(verify_final)) != 0) {
3832*0Sstevel@tonic-gate 		crypto_release_minor(cm);
3833*0Sstevel@tonic-gate 		return (EFAULT);
3834*0Sstevel@tonic-gate 	}
3835*0Sstevel@tonic-gate 
3836*0Sstevel@tonic-gate 	sign.cd_raw.iov_base = NULL;
3837*0Sstevel@tonic-gate 
3838*0Sstevel@tonic-gate 	signlen = STRUCT_FGET(verify_final, vf_signlen);
3839*0Sstevel@tonic-gate 	if (signlen > crypto_max_buffer_len) {
3840*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "verify_final: buffer greater than %ld "
3841*0Sstevel@tonic-gate 		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
3842*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
3843*0Sstevel@tonic-gate 		goto release_minor;
3844*0Sstevel@tonic-gate 	}
3845*0Sstevel@tonic-gate 
3846*0Sstevel@tonic-gate 	if ((rv = crypto_buffer_check(signlen, &projp)) != CRYPTO_SUCCESS) {
3847*0Sstevel@tonic-gate 		goto release_minor;
3848*0Sstevel@tonic-gate 	}
3849*0Sstevel@tonic-gate 	need = signlen;
3850*0Sstevel@tonic-gate 
3851*0Sstevel@tonic-gate 	INIT_RAW_CRYPTO_DATA(sign, signlen);
3852*0Sstevel@tonic-gate 
3853*0Sstevel@tonic-gate 	if (signlen != 0 && copyin(STRUCT_FGETP(verify_final, vf_signbuf),
3854*0Sstevel@tonic-gate 	    sign.cd_raw.iov_base, signlen) != 0) {
3855*0Sstevel@tonic-gate 		error = EFAULT;
3856*0Sstevel@tonic-gate 		goto release_minor;
3857*0Sstevel@tonic-gate 	}
3858*0Sstevel@tonic-gate 
3859*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(verify_final, vf_session);
3860*0Sstevel@tonic-gate 
3861*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
3862*0Sstevel@tonic-gate 		goto release_minor;
3863*0Sstevel@tonic-gate 	}
3864*0Sstevel@tonic-gate 
3865*0Sstevel@tonic-gate 	rv = crypto_verify_final(sp->sd_verify_ctx, &sign, NULL);
3866*0Sstevel@tonic-gate 	if (KCF_CONTEXT_DONE(rv))
3867*0Sstevel@tonic-gate 		sp->sd_verify_ctx = NULL;
3868*0Sstevel@tonic-gate 
3869*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
3870*0Sstevel@tonic-gate 
3871*0Sstevel@tonic-gate release_minor:
3872*0Sstevel@tonic-gate 	if (need != 0) {
3873*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
3874*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(need, projp);
3875*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
3876*0Sstevel@tonic-gate 	}
3877*0Sstevel@tonic-gate 	crypto_release_minor(cm);
3878*0Sstevel@tonic-gate 
3879*0Sstevel@tonic-gate 	if (sign.cd_raw.iov_base != NULL)
3880*0Sstevel@tonic-gate 		kmem_free(sign.cd_raw.iov_base, signlen);
3881*0Sstevel@tonic-gate 
3882*0Sstevel@tonic-gate 	if (error != 0)
3883*0Sstevel@tonic-gate 		return (error);
3884*0Sstevel@tonic-gate 
3885*0Sstevel@tonic-gate 	STRUCT_FSET(verify_final, vf_return_value, rv);
3886*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(verify_final), arg,
3887*0Sstevel@tonic-gate 	    STRUCT_SIZE(verify_final)) != 0) {
3888*0Sstevel@tonic-gate 		return (EFAULT);
3889*0Sstevel@tonic-gate 	}
3890*0Sstevel@tonic-gate 	return (0);
3891*0Sstevel@tonic-gate }
3892*0Sstevel@tonic-gate 
3893*0Sstevel@tonic-gate /* ARGSUSED */
3894*0Sstevel@tonic-gate static int
3895*0Sstevel@tonic-gate seed_random(dev_t dev, caddr_t arg, int mode, int *rval)
3896*0Sstevel@tonic-gate {
3897*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_seed_random, seed_random);
3898*0Sstevel@tonic-gate 	kproject_t *projp;
3899*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
3900*0Sstevel@tonic-gate 	kcf_req_params_t params;
3901*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
3902*0Sstevel@tonic-gate 	crypto_minor_t *cm;
3903*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
3904*0Sstevel@tonic-gate 	uchar_t *seed_buffer = NULL;
3905*0Sstevel@tonic-gate 	size_t seed_len;
3906*0Sstevel@tonic-gate 	size_t need = 0;
3907*0Sstevel@tonic-gate 	int error = 0;
3908*0Sstevel@tonic-gate 	int rv;
3909*0Sstevel@tonic-gate 
3910*0Sstevel@tonic-gate 	STRUCT_INIT(seed_random, mode);
3911*0Sstevel@tonic-gate 
3912*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3913*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "seed_random: failed holding minor");
3914*0Sstevel@tonic-gate 		return (ENXIO);
3915*0Sstevel@tonic-gate 	}
3916*0Sstevel@tonic-gate 
3917*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(seed_random),
3918*0Sstevel@tonic-gate 	    STRUCT_SIZE(seed_random)) != 0) {
3919*0Sstevel@tonic-gate 		crypto_release_minor(cm);
3920*0Sstevel@tonic-gate 		return (EFAULT);
3921*0Sstevel@tonic-gate 	}
3922*0Sstevel@tonic-gate 
3923*0Sstevel@tonic-gate 	seed_len = STRUCT_FGET(seed_random, sr_seedlen);
3924*0Sstevel@tonic-gate 	if (seed_len > crypto_max_buffer_len) {
3925*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "seed_random: buffer greater than %ld "
3926*0Sstevel@tonic-gate 		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
3927*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
3928*0Sstevel@tonic-gate 		goto release_minor;
3929*0Sstevel@tonic-gate 	}
3930*0Sstevel@tonic-gate 
3931*0Sstevel@tonic-gate 	if ((rv = crypto_buffer_check(seed_len, &projp)) != CRYPTO_SUCCESS) {
3932*0Sstevel@tonic-gate 		goto release_minor;
3933*0Sstevel@tonic-gate 	}
3934*0Sstevel@tonic-gate 	need = seed_len;
3935*0Sstevel@tonic-gate 	seed_buffer = kmem_alloc(seed_len, KM_SLEEP);
3936*0Sstevel@tonic-gate 
3937*0Sstevel@tonic-gate 	if (seed_len != 0 && copyin(STRUCT_FGETP(seed_random, sr_seedbuf),
3938*0Sstevel@tonic-gate 	    seed_buffer, seed_len) != 0) {
3939*0Sstevel@tonic-gate 		error = EFAULT;
3940*0Sstevel@tonic-gate 		goto release_minor;
3941*0Sstevel@tonic-gate 	}
3942*0Sstevel@tonic-gate 
3943*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(seed_random, sr_session);
3944*0Sstevel@tonic-gate 
3945*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
3946*0Sstevel@tonic-gate 		goto release_minor;
3947*0Sstevel@tonic-gate 	}
3948*0Sstevel@tonic-gate 
3949*0Sstevel@tonic-gate 	if (random_mech == CRYPTO_MECH_INVALID)
3950*0Sstevel@tonic-gate 		random_mech = crypto_mech2id_common(SUN_RANDOM, B_FALSE);
3951*0Sstevel@tonic-gate 
3952*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider(random_mech,
3953*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(random_ops),
3954*0Sstevel@tonic-gate 	    CRYPTO_RANDOM_OFFSET(seed_random),
3955*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
3956*0Sstevel@tonic-gate 		goto out;
3957*0Sstevel@tonic-gate 	}
3958*0Sstevel@tonic-gate 
3959*0Sstevel@tonic-gate 	KCF_WRAP_RANDOM_OPS_PARAMS(&params, KCF_OP_RANDOM_SEED,
3960*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, seed_buffer, seed_len);
3961*0Sstevel@tonic-gate 
3962*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
3963*0Sstevel@tonic-gate 
3964*0Sstevel@tonic-gate out:
3965*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
3966*0Sstevel@tonic-gate 
3967*0Sstevel@tonic-gate release_minor:
3968*0Sstevel@tonic-gate 	if (need != 0) {
3969*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
3970*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(need, projp);
3971*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
3972*0Sstevel@tonic-gate 	}
3973*0Sstevel@tonic-gate 	crypto_release_minor(cm);
3974*0Sstevel@tonic-gate 
3975*0Sstevel@tonic-gate 	if (seed_buffer != NULL)
3976*0Sstevel@tonic-gate 		kmem_free(seed_buffer, seed_len);
3977*0Sstevel@tonic-gate 
3978*0Sstevel@tonic-gate 	if (error != 0)
3979*0Sstevel@tonic-gate 		return (error);
3980*0Sstevel@tonic-gate 
3981*0Sstevel@tonic-gate 	STRUCT_FSET(seed_random, sr_return_value, rv);
3982*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(seed_random), arg,
3983*0Sstevel@tonic-gate 	    STRUCT_SIZE(seed_random)) != 0) {
3984*0Sstevel@tonic-gate 		return (EFAULT);
3985*0Sstevel@tonic-gate 	}
3986*0Sstevel@tonic-gate 	return (0);
3987*0Sstevel@tonic-gate }
3988*0Sstevel@tonic-gate 
3989*0Sstevel@tonic-gate /* ARGSUSED */
3990*0Sstevel@tonic-gate static int
3991*0Sstevel@tonic-gate generate_random(dev_t dev, caddr_t arg, int mode, int *rval)
3992*0Sstevel@tonic-gate {
3993*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_generate_random, generate_random);
3994*0Sstevel@tonic-gate 	kproject_t *projp;
3995*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
3996*0Sstevel@tonic-gate 	kcf_req_params_t params;
3997*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
3998*0Sstevel@tonic-gate 	crypto_minor_t *cm;
3999*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
4000*0Sstevel@tonic-gate 	uchar_t *buffer = NULL;
4001*0Sstevel@tonic-gate 	size_t len;
4002*0Sstevel@tonic-gate 	size_t need = 0;
4003*0Sstevel@tonic-gate 	int error = 0;
4004*0Sstevel@tonic-gate 	int rv;
4005*0Sstevel@tonic-gate 
4006*0Sstevel@tonic-gate 	STRUCT_INIT(generate_random, mode);
4007*0Sstevel@tonic-gate 
4008*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4009*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "generate_random: failed holding minor");
4010*0Sstevel@tonic-gate 		return (ENXIO);
4011*0Sstevel@tonic-gate 	}
4012*0Sstevel@tonic-gate 
4013*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(generate_random),
4014*0Sstevel@tonic-gate 	    STRUCT_SIZE(generate_random)) != 0) {
4015*0Sstevel@tonic-gate 		crypto_release_minor(cm);
4016*0Sstevel@tonic-gate 		return (EFAULT);
4017*0Sstevel@tonic-gate 	}
4018*0Sstevel@tonic-gate 
4019*0Sstevel@tonic-gate 	len = STRUCT_FGET(generate_random, gr_buflen);
4020*0Sstevel@tonic-gate 	if (len > crypto_max_buffer_len) {
4021*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "generate_random: buffer greater than %ld "
4022*0Sstevel@tonic-gate 		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
4023*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
4024*0Sstevel@tonic-gate 		goto release_minor;
4025*0Sstevel@tonic-gate 	}
4026*0Sstevel@tonic-gate 
4027*0Sstevel@tonic-gate 	if ((rv = crypto_buffer_check(len, &projp)) != CRYPTO_SUCCESS) {
4028*0Sstevel@tonic-gate 		goto release_minor;
4029*0Sstevel@tonic-gate 	}
4030*0Sstevel@tonic-gate 	need = len;
4031*0Sstevel@tonic-gate 	buffer = kmem_alloc(len, KM_SLEEP);
4032*0Sstevel@tonic-gate 
4033*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(generate_random, gr_session);
4034*0Sstevel@tonic-gate 
4035*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4036*0Sstevel@tonic-gate 		goto release_minor;
4037*0Sstevel@tonic-gate 	}
4038*0Sstevel@tonic-gate 
4039*0Sstevel@tonic-gate 	if (random_mech == CRYPTO_MECH_INVALID)
4040*0Sstevel@tonic-gate 		random_mech = crypto_mech2id_common(SUN_RANDOM, B_FALSE);
4041*0Sstevel@tonic-gate 
4042*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider(random_mech,
4043*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(random_ops),
4044*0Sstevel@tonic-gate 	    CRYPTO_RANDOM_OFFSET(generate_random),
4045*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4046*0Sstevel@tonic-gate 		goto out;
4047*0Sstevel@tonic-gate 	}
4048*0Sstevel@tonic-gate 
4049*0Sstevel@tonic-gate 	KCF_WRAP_RANDOM_OPS_PARAMS(&params, KCF_OP_RANDOM_GENERATE,
4050*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, buffer, len);
4051*0Sstevel@tonic-gate 
4052*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4053*0Sstevel@tonic-gate 
4054*0Sstevel@tonic-gate out:
4055*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
4056*0Sstevel@tonic-gate 
4057*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS) {
4058*0Sstevel@tonic-gate 		if (len != 0 && copyout(buffer,
4059*0Sstevel@tonic-gate 		    STRUCT_FGETP(generate_random, gr_buf), len) != 0) {
4060*0Sstevel@tonic-gate 			error = EFAULT;
4061*0Sstevel@tonic-gate 		}
4062*0Sstevel@tonic-gate 	}
4063*0Sstevel@tonic-gate 
4064*0Sstevel@tonic-gate release_minor:
4065*0Sstevel@tonic-gate 	if (need != 0) {
4066*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
4067*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(need, projp);
4068*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
4069*0Sstevel@tonic-gate 	}
4070*0Sstevel@tonic-gate 	crypto_release_minor(cm);
4071*0Sstevel@tonic-gate 
4072*0Sstevel@tonic-gate 	if (buffer != NULL) {
4073*0Sstevel@tonic-gate 		/* random numbers are often used to create keys */
4074*0Sstevel@tonic-gate 		bzero(buffer, len);
4075*0Sstevel@tonic-gate 		kmem_free(buffer, len);
4076*0Sstevel@tonic-gate 	}
4077*0Sstevel@tonic-gate 
4078*0Sstevel@tonic-gate 	if (error != 0)
4079*0Sstevel@tonic-gate 		return (error);
4080*0Sstevel@tonic-gate 
4081*0Sstevel@tonic-gate 	STRUCT_FSET(generate_random, gr_return_value, rv);
4082*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(generate_random), arg,
4083*0Sstevel@tonic-gate 	    STRUCT_SIZE(generate_random)) != 0) {
4084*0Sstevel@tonic-gate 		return (EFAULT);
4085*0Sstevel@tonic-gate 	}
4086*0Sstevel@tonic-gate 	return (0);
4087*0Sstevel@tonic-gate }
4088*0Sstevel@tonic-gate 
4089*0Sstevel@tonic-gate /*
4090*0Sstevel@tonic-gate  * Copyout a kernel array of attributes to user space.
4091*0Sstevel@tonic-gate  * u_attrs is the corresponding user space array containing
4092*0Sstevel@tonic-gate  * user space pointers necessary for the copyout.
4093*0Sstevel@tonic-gate  */
4094*0Sstevel@tonic-gate /* ARGSUSED */
4095*0Sstevel@tonic-gate static int
4096*0Sstevel@tonic-gate copyout_attributes(int mode, caddr_t out, uint_t count,
4097*0Sstevel@tonic-gate     crypto_object_attribute_t *k_attrs, caddr_t u_attrs)
4098*0Sstevel@tonic-gate {
4099*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_attribute, oa);
4100*0Sstevel@tonic-gate 	caddr_t p, valuep;
4101*0Sstevel@tonic-gate 	size_t value_len;
4102*0Sstevel@tonic-gate 	size_t len;
4103*0Sstevel@tonic-gate 	int i;
4104*0Sstevel@tonic-gate 	int error = 0;
4105*0Sstevel@tonic-gate 
4106*0Sstevel@tonic-gate 	if (count == 0)
4107*0Sstevel@tonic-gate 		return (0);
4108*0Sstevel@tonic-gate 
4109*0Sstevel@tonic-gate 	STRUCT_INIT(oa, mode);
4110*0Sstevel@tonic-gate 
4111*0Sstevel@tonic-gate 	len = count * STRUCT_SIZE(oa);
4112*0Sstevel@tonic-gate 
4113*0Sstevel@tonic-gate 	ASSERT(u_attrs != NULL);
4114*0Sstevel@tonic-gate 	p = u_attrs;
4115*0Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
4116*0Sstevel@tonic-gate 		/* can this bcopy be eliminated? */
4117*0Sstevel@tonic-gate 		bcopy(p, STRUCT_BUF(oa), STRUCT_SIZE(oa));
4118*0Sstevel@tonic-gate 		value_len = k_attrs[i].oa_value_len;
4119*0Sstevel@tonic-gate 		STRUCT_FSET(oa, oa_type, k_attrs[i].oa_type);
4120*0Sstevel@tonic-gate 		STRUCT_FSET(oa, oa_value_len, value_len);
4121*0Sstevel@tonic-gate 		valuep = STRUCT_FGETP(oa, oa_value);
4122*0Sstevel@tonic-gate 		if (valuep != NULL && value_len != -1) {
4123*0Sstevel@tonic-gate 			if (copyout(k_attrs[i].oa_value,
4124*0Sstevel@tonic-gate 			    valuep, value_len) != 0) {
4125*0Sstevel@tonic-gate 				error = EFAULT;
4126*0Sstevel@tonic-gate 				goto out;
4127*0Sstevel@tonic-gate 			}
4128*0Sstevel@tonic-gate 		}
4129*0Sstevel@tonic-gate 		bcopy(STRUCT_BUF(oa), p, STRUCT_SIZE(oa));
4130*0Sstevel@tonic-gate 		p += STRUCT_SIZE(oa);
4131*0Sstevel@tonic-gate 	}
4132*0Sstevel@tonic-gate 	if (copyout(u_attrs, out, len)) {
4133*0Sstevel@tonic-gate 		error = EFAULT;
4134*0Sstevel@tonic-gate 	}
4135*0Sstevel@tonic-gate out:
4136*0Sstevel@tonic-gate 	return (error);
4137*0Sstevel@tonic-gate }
4138*0Sstevel@tonic-gate 
4139*0Sstevel@tonic-gate 
4140*0Sstevel@tonic-gate /* ARGSUSED */
4141*0Sstevel@tonic-gate static int
4142*0Sstevel@tonic-gate object_create(dev_t dev, caddr_t arg, int mode, int *rval)
4143*0Sstevel@tonic-gate {
4144*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_create, object_create);
4145*0Sstevel@tonic-gate 	kproject_t *projp;
4146*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
4147*0Sstevel@tonic-gate 	kcf_req_params_t params;
4148*0Sstevel@tonic-gate 	crypto_object_attribute_t *k_attrs = NULL;
4149*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
4150*0Sstevel@tonic-gate 	crypto_minor_t *cm;
4151*0Sstevel@tonic-gate 	crypto_session_data_t *sp = NULL;
4152*0Sstevel@tonic-gate 	crypto_object_id_t object_handle;
4153*0Sstevel@tonic-gate 	caddr_t oc_attributes;
4154*0Sstevel@tonic-gate 	size_t k_attrs_size;
4155*0Sstevel@tonic-gate 	size_t rctl_bytes = 0;
4156*0Sstevel@tonic-gate 	int error = 0;
4157*0Sstevel@tonic-gate 	int rv;
4158*0Sstevel@tonic-gate 	uint_t count;
4159*0Sstevel@tonic-gate 
4160*0Sstevel@tonic-gate 	STRUCT_INIT(object_create, mode);
4161*0Sstevel@tonic-gate 
4162*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4163*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "object_create: failed holding minor");
4164*0Sstevel@tonic-gate 		return (ENXIO);
4165*0Sstevel@tonic-gate 	}
4166*0Sstevel@tonic-gate 
4167*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(object_create),
4168*0Sstevel@tonic-gate 	    STRUCT_SIZE(object_create)) != 0) {
4169*0Sstevel@tonic-gate 		crypto_release_minor(cm);
4170*0Sstevel@tonic-gate 		return (EFAULT);
4171*0Sstevel@tonic-gate 	}
4172*0Sstevel@tonic-gate 
4173*0Sstevel@tonic-gate 	count = STRUCT_FGET(object_create, oc_count);
4174*0Sstevel@tonic-gate 	oc_attributes = STRUCT_FGETP(object_create, oc_attributes);
4175*0Sstevel@tonic-gate 	if (!copyin_attributes(mode, count, oc_attributes, &k_attrs,
4176*0Sstevel@tonic-gate 	    &k_attrs_size, NULL, &rv, &error, &rctl_bytes, 0, B_TRUE, &projp)) {
4177*0Sstevel@tonic-gate 		goto release_minor;
4178*0Sstevel@tonic-gate 	}
4179*0Sstevel@tonic-gate 
4180*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(object_create, oc_session);
4181*0Sstevel@tonic-gate 
4182*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4183*0Sstevel@tonic-gate 		goto release_minor;
4184*0Sstevel@tonic-gate 	}
4185*0Sstevel@tonic-gate 
4186*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider_nomech(
4187*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(object_ops),
4188*0Sstevel@tonic-gate 	    CRYPTO_OBJECT_OFFSET(object_create),
4189*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4190*0Sstevel@tonic-gate 		goto release_minor;
4191*0Sstevel@tonic-gate 	}
4192*0Sstevel@tonic-gate 
4193*0Sstevel@tonic-gate 	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_CREATE,
4194*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, 0, k_attrs, count,
4195*0Sstevel@tonic-gate 	    &object_handle, 0, NULL, NULL, 0, NULL);
4196*0Sstevel@tonic-gate 
4197*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4198*0Sstevel@tonic-gate 
4199*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS)
4200*0Sstevel@tonic-gate 		STRUCT_FSET(object_create, oc_handle, object_handle);
4201*0Sstevel@tonic-gate 
4202*0Sstevel@tonic-gate release_minor:
4203*0Sstevel@tonic-gate 	if (rctl_bytes != 0) {
4204*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
4205*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(rctl_bytes, projp);
4206*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
4207*0Sstevel@tonic-gate 	}
4208*0Sstevel@tonic-gate 
4209*0Sstevel@tonic-gate 	if (k_attrs != NULL)
4210*0Sstevel@tonic-gate 		kmem_free(k_attrs, k_attrs_size);
4211*0Sstevel@tonic-gate 
4212*0Sstevel@tonic-gate 	if (error != 0)
4213*0Sstevel@tonic-gate 		goto out;
4214*0Sstevel@tonic-gate 
4215*0Sstevel@tonic-gate 	STRUCT_FSET(object_create, oc_return_value, rv);
4216*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(object_create), arg,
4217*0Sstevel@tonic-gate 	    STRUCT_SIZE(object_create)) != 0) {
4218*0Sstevel@tonic-gate 		if (rv == CRYPTO_SUCCESS) {
4219*0Sstevel@tonic-gate 			KCF_WRAP_OBJECT_OPS_PARAMS(&params,
4220*0Sstevel@tonic-gate 			    KCF_OP_OBJECT_DESTROY,
4221*0Sstevel@tonic-gate 			    sp->sd_provider_session->ps_session, object_handle,
4222*0Sstevel@tonic-gate 			    NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
4223*0Sstevel@tonic-gate 
4224*0Sstevel@tonic-gate 			(void) kcf_submit_request(real_provider, NULL,
4225*0Sstevel@tonic-gate 			    NULL, &params, B_FALSE);
4226*0Sstevel@tonic-gate 
4227*0Sstevel@tonic-gate 			error = EFAULT;
4228*0Sstevel@tonic-gate 		}
4229*0Sstevel@tonic-gate 	}
4230*0Sstevel@tonic-gate out:
4231*0Sstevel@tonic-gate 	if (sp != NULL)
4232*0Sstevel@tonic-gate 		CRYPTO_SESSION_RELE(sp);
4233*0Sstevel@tonic-gate 	crypto_release_minor(cm);
4234*0Sstevel@tonic-gate 	return (error);
4235*0Sstevel@tonic-gate }
4236*0Sstevel@tonic-gate 
4237*0Sstevel@tonic-gate /* ARGSUSED */
4238*0Sstevel@tonic-gate static int
4239*0Sstevel@tonic-gate object_copy(dev_t dev, caddr_t arg, int mode, int *rval)
4240*0Sstevel@tonic-gate {
4241*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_copy, object_copy);
4242*0Sstevel@tonic-gate 	kproject_t *projp;
4243*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
4244*0Sstevel@tonic-gate 	kcf_req_params_t params;
4245*0Sstevel@tonic-gate 	crypto_object_attribute_t *k_attrs = NULL;
4246*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
4247*0Sstevel@tonic-gate 	crypto_minor_t *cm;
4248*0Sstevel@tonic-gate 	crypto_session_data_t *sp = NULL;
4249*0Sstevel@tonic-gate 	crypto_object_id_t handle, new_handle;
4250*0Sstevel@tonic-gate 	caddr_t oc_new_attributes;
4251*0Sstevel@tonic-gate 	size_t k_attrs_size;
4252*0Sstevel@tonic-gate 	size_t rctl_bytes = 0;
4253*0Sstevel@tonic-gate 	int error = 0;
4254*0Sstevel@tonic-gate 	int rv;
4255*0Sstevel@tonic-gate 	uint_t count;
4256*0Sstevel@tonic-gate 
4257*0Sstevel@tonic-gate 	STRUCT_INIT(object_copy, mode);
4258*0Sstevel@tonic-gate 
4259*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4260*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "object_copy: failed holding minor");
4261*0Sstevel@tonic-gate 		return (ENXIO);
4262*0Sstevel@tonic-gate 	}
4263*0Sstevel@tonic-gate 
4264*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(object_copy),
4265*0Sstevel@tonic-gate 	    STRUCT_SIZE(object_copy)) != 0) {
4266*0Sstevel@tonic-gate 		crypto_release_minor(cm);
4267*0Sstevel@tonic-gate 		return (EFAULT);
4268*0Sstevel@tonic-gate 	}
4269*0Sstevel@tonic-gate 
4270*0Sstevel@tonic-gate 	count = STRUCT_FGET(object_copy, oc_count);
4271*0Sstevel@tonic-gate 	oc_new_attributes = STRUCT_FGETP(object_copy, oc_new_attributes);
4272*0Sstevel@tonic-gate 	if (!copyin_attributes(mode, count, oc_new_attributes, &k_attrs,
4273*0Sstevel@tonic-gate 	    &k_attrs_size, NULL, &rv, &error, &rctl_bytes, 0, B_TRUE, &projp)) {
4274*0Sstevel@tonic-gate 		goto release_minor;
4275*0Sstevel@tonic-gate 	}
4276*0Sstevel@tonic-gate 
4277*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(object_copy, oc_session);
4278*0Sstevel@tonic-gate 
4279*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4280*0Sstevel@tonic-gate 		goto release_minor;
4281*0Sstevel@tonic-gate 	}
4282*0Sstevel@tonic-gate 
4283*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider_nomech(
4284*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(object_ops),
4285*0Sstevel@tonic-gate 	    CRYPTO_OBJECT_OFFSET(object_copy),
4286*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4287*0Sstevel@tonic-gate 		goto release_minor;
4288*0Sstevel@tonic-gate 	}
4289*0Sstevel@tonic-gate 
4290*0Sstevel@tonic-gate 	handle = STRUCT_FGET(object_copy, oc_handle);
4291*0Sstevel@tonic-gate 	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_COPY,
4292*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, handle, k_attrs, count,
4293*0Sstevel@tonic-gate 	    &new_handle, 0, NULL, NULL, 0, NULL);
4294*0Sstevel@tonic-gate 
4295*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4296*0Sstevel@tonic-gate 
4297*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS)
4298*0Sstevel@tonic-gate 		STRUCT_FSET(object_copy, oc_new_handle, new_handle);
4299*0Sstevel@tonic-gate 
4300*0Sstevel@tonic-gate release_minor:
4301*0Sstevel@tonic-gate 	if (rctl_bytes != 0) {
4302*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
4303*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(rctl_bytes, projp);
4304*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
4305*0Sstevel@tonic-gate 	}
4306*0Sstevel@tonic-gate 
4307*0Sstevel@tonic-gate 	if (k_attrs != NULL)
4308*0Sstevel@tonic-gate 		kmem_free(k_attrs, k_attrs_size);
4309*0Sstevel@tonic-gate 
4310*0Sstevel@tonic-gate 	if (error != 0)
4311*0Sstevel@tonic-gate 		goto out;
4312*0Sstevel@tonic-gate 
4313*0Sstevel@tonic-gate 	STRUCT_FSET(object_copy, oc_return_value, rv);
4314*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(object_copy), arg,
4315*0Sstevel@tonic-gate 	    STRUCT_SIZE(object_copy)) != 0) {
4316*0Sstevel@tonic-gate 		if (rv == CRYPTO_SUCCESS) {
4317*0Sstevel@tonic-gate 			KCF_WRAP_OBJECT_OPS_PARAMS(&params,
4318*0Sstevel@tonic-gate 			    KCF_OP_OBJECT_DESTROY,
4319*0Sstevel@tonic-gate 			    sp->sd_provider_session->ps_session, new_handle,
4320*0Sstevel@tonic-gate 			    NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
4321*0Sstevel@tonic-gate 
4322*0Sstevel@tonic-gate 			(void) kcf_submit_request(real_provider, NULL,
4323*0Sstevel@tonic-gate 			    NULL, &params, B_FALSE);
4324*0Sstevel@tonic-gate 
4325*0Sstevel@tonic-gate 			error = EFAULT;
4326*0Sstevel@tonic-gate 		}
4327*0Sstevel@tonic-gate 	}
4328*0Sstevel@tonic-gate out:
4329*0Sstevel@tonic-gate 	if (sp != NULL)
4330*0Sstevel@tonic-gate 		CRYPTO_SESSION_RELE(sp);
4331*0Sstevel@tonic-gate 	crypto_release_minor(cm);
4332*0Sstevel@tonic-gate 	return (error);
4333*0Sstevel@tonic-gate }
4334*0Sstevel@tonic-gate 
4335*0Sstevel@tonic-gate /* ARGSUSED */
4336*0Sstevel@tonic-gate static int
4337*0Sstevel@tonic-gate object_destroy(dev_t dev, caddr_t arg, int mode, int *rval)
4338*0Sstevel@tonic-gate {
4339*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_destroy, object_destroy);
4340*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
4341*0Sstevel@tonic-gate 	kcf_req_params_t params;
4342*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
4343*0Sstevel@tonic-gate 	crypto_minor_t *cm;
4344*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
4345*0Sstevel@tonic-gate 	crypto_object_id_t handle;
4346*0Sstevel@tonic-gate 	int error = 0;
4347*0Sstevel@tonic-gate 	int rv;
4348*0Sstevel@tonic-gate 
4349*0Sstevel@tonic-gate 	STRUCT_INIT(object_destroy, mode);
4350*0Sstevel@tonic-gate 
4351*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4352*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "object_destroy: failed holding minor");
4353*0Sstevel@tonic-gate 		return (ENXIO);
4354*0Sstevel@tonic-gate 	}
4355*0Sstevel@tonic-gate 
4356*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(object_destroy),
4357*0Sstevel@tonic-gate 	    STRUCT_SIZE(object_destroy)) != 0) {
4358*0Sstevel@tonic-gate 		crypto_release_minor(cm);
4359*0Sstevel@tonic-gate 		return (EFAULT);
4360*0Sstevel@tonic-gate 	}
4361*0Sstevel@tonic-gate 
4362*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(object_destroy, od_session);
4363*0Sstevel@tonic-gate 
4364*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4365*0Sstevel@tonic-gate 		goto release_minor;
4366*0Sstevel@tonic-gate 	}
4367*0Sstevel@tonic-gate 
4368*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider_nomech(
4369*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(object_ops),
4370*0Sstevel@tonic-gate 	    CRYPTO_OBJECT_OFFSET(object_destroy),
4371*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4372*0Sstevel@tonic-gate 		goto out;
4373*0Sstevel@tonic-gate 	}
4374*0Sstevel@tonic-gate 
4375*0Sstevel@tonic-gate 	handle = STRUCT_FGET(object_destroy, od_handle);
4376*0Sstevel@tonic-gate 	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_DESTROY,
4377*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, handle, NULL, 0, NULL, 0,
4378*0Sstevel@tonic-gate 	    NULL, NULL, 0, NULL);
4379*0Sstevel@tonic-gate 
4380*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4381*0Sstevel@tonic-gate 
4382*0Sstevel@tonic-gate out:
4383*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
4384*0Sstevel@tonic-gate 
4385*0Sstevel@tonic-gate release_minor:
4386*0Sstevel@tonic-gate 	crypto_release_minor(cm);
4387*0Sstevel@tonic-gate 
4388*0Sstevel@tonic-gate 	if (error != 0)
4389*0Sstevel@tonic-gate 		return (error);
4390*0Sstevel@tonic-gate 
4391*0Sstevel@tonic-gate 	STRUCT_FSET(object_destroy, od_return_value, rv);
4392*0Sstevel@tonic-gate 
4393*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(object_destroy), arg,
4394*0Sstevel@tonic-gate 	    STRUCT_SIZE(object_destroy)) != 0) {
4395*0Sstevel@tonic-gate 		return (EFAULT);
4396*0Sstevel@tonic-gate 	}
4397*0Sstevel@tonic-gate 	return (0);
4398*0Sstevel@tonic-gate }
4399*0Sstevel@tonic-gate 
4400*0Sstevel@tonic-gate /* ARGSUSED */
4401*0Sstevel@tonic-gate static int
4402*0Sstevel@tonic-gate object_get_attribute_value(dev_t dev, caddr_t arg, int mode, int *rval)
4403*0Sstevel@tonic-gate {
4404*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_get_attribute_value, get_attribute_value);
4405*0Sstevel@tonic-gate 	/* LINTED E_FUNC_SET_NOT_USED */
4406*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_attribute, oa);
4407*0Sstevel@tonic-gate 	kproject_t *projp;
4408*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
4409*0Sstevel@tonic-gate 	kcf_req_params_t params;
4410*0Sstevel@tonic-gate 	crypto_object_attribute_t *k_attrs = NULL;
4411*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
4412*0Sstevel@tonic-gate 	crypto_minor_t *cm;
4413*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
4414*0Sstevel@tonic-gate 	crypto_object_id_t handle;
4415*0Sstevel@tonic-gate 	caddr_t og_attributes;
4416*0Sstevel@tonic-gate 	caddr_t u_attrs;
4417*0Sstevel@tonic-gate 	size_t k_attrs_size;
4418*0Sstevel@tonic-gate 	size_t rctl_bytes = 0;
4419*0Sstevel@tonic-gate 	int error = 0;
4420*0Sstevel@tonic-gate 	int rv;
4421*0Sstevel@tonic-gate 	uint_t count;
4422*0Sstevel@tonic-gate 
4423*0Sstevel@tonic-gate 	STRUCT_INIT(get_attribute_value, mode);
4424*0Sstevel@tonic-gate 	STRUCT_INIT(oa, mode);
4425*0Sstevel@tonic-gate 
4426*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4427*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
4428*0Sstevel@tonic-gate 		    "object_get_attribute_value: failed holding minor");
4429*0Sstevel@tonic-gate 		return (ENXIO);
4430*0Sstevel@tonic-gate 	}
4431*0Sstevel@tonic-gate 
4432*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(get_attribute_value),
4433*0Sstevel@tonic-gate 	    STRUCT_SIZE(get_attribute_value)) != 0) {
4434*0Sstevel@tonic-gate 		crypto_release_minor(cm);
4435*0Sstevel@tonic-gate 		return (EFAULT);
4436*0Sstevel@tonic-gate 	}
4437*0Sstevel@tonic-gate 
4438*0Sstevel@tonic-gate 	count = STRUCT_FGET(get_attribute_value, og_count);
4439*0Sstevel@tonic-gate 	og_attributes = STRUCT_FGETP(get_attribute_value, og_attributes);
4440*0Sstevel@tonic-gate 	if (!copyin_attributes(mode, count, og_attributes, &k_attrs,
4441*0Sstevel@tonic-gate 	    &k_attrs_size, &u_attrs, &rv, &error, &rctl_bytes, 0, B_FALSE,
4442*0Sstevel@tonic-gate 	    &projp)) {
4443*0Sstevel@tonic-gate 		goto release_minor;
4444*0Sstevel@tonic-gate 	}
4445*0Sstevel@tonic-gate 
4446*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(get_attribute_value, og_session);
4447*0Sstevel@tonic-gate 
4448*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4449*0Sstevel@tonic-gate 		goto release_minor;
4450*0Sstevel@tonic-gate 	}
4451*0Sstevel@tonic-gate 
4452*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider_nomech(
4453*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(object_ops),
4454*0Sstevel@tonic-gate 	    CRYPTO_OBJECT_OFFSET(object_get_attribute_value),
4455*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4456*0Sstevel@tonic-gate 		goto out;
4457*0Sstevel@tonic-gate 	}
4458*0Sstevel@tonic-gate 
4459*0Sstevel@tonic-gate 	handle = STRUCT_FGET(get_attribute_value, og_handle);
4460*0Sstevel@tonic-gate 	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_GET_ATTRIBUTE_VALUE,
4461*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, handle, k_attrs, count, NULL,
4462*0Sstevel@tonic-gate 	    0, NULL, NULL, 0, NULL);
4463*0Sstevel@tonic-gate 
4464*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4465*0Sstevel@tonic-gate 
4466*0Sstevel@tonic-gate out:
4467*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
4468*0Sstevel@tonic-gate 
4469*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS || rv == CRYPTO_ATTRIBUTE_SENSITIVE ||
4470*0Sstevel@tonic-gate 	    rv == CRYPTO_ATTRIBUTE_TYPE_INVALID ||
4471*0Sstevel@tonic-gate 	    rv == CRYPTO_BUFFER_TOO_SMALL) {
4472*0Sstevel@tonic-gate 		error = copyout_attributes(mode,
4473*0Sstevel@tonic-gate 		    STRUCT_FGETP(get_attribute_value, og_attributes),
4474*0Sstevel@tonic-gate 		    count, k_attrs, u_attrs);
4475*0Sstevel@tonic-gate 	}
4476*0Sstevel@tonic-gate 
4477*0Sstevel@tonic-gate release_minor:
4478*0Sstevel@tonic-gate 	if (rctl_bytes != 0) {
4479*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
4480*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(rctl_bytes, projp);
4481*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
4482*0Sstevel@tonic-gate 	}
4483*0Sstevel@tonic-gate 	crypto_release_minor(cm);
4484*0Sstevel@tonic-gate 
4485*0Sstevel@tonic-gate 	if (k_attrs != NULL)
4486*0Sstevel@tonic-gate 		kmem_free(k_attrs, k_attrs_size);
4487*0Sstevel@tonic-gate 
4488*0Sstevel@tonic-gate 	if (u_attrs != NULL)
4489*0Sstevel@tonic-gate 		kmem_free(u_attrs, count * STRUCT_SIZE(oa));
4490*0Sstevel@tonic-gate 
4491*0Sstevel@tonic-gate 	if (error != 0)
4492*0Sstevel@tonic-gate 		return (error);
4493*0Sstevel@tonic-gate 
4494*0Sstevel@tonic-gate 	STRUCT_FSET(get_attribute_value, og_return_value, rv);
4495*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(get_attribute_value), arg,
4496*0Sstevel@tonic-gate 	    STRUCT_SIZE(get_attribute_value)) != 0) {
4497*0Sstevel@tonic-gate 		return (EFAULT);
4498*0Sstevel@tonic-gate 	}
4499*0Sstevel@tonic-gate 	return (0);
4500*0Sstevel@tonic-gate }
4501*0Sstevel@tonic-gate 
4502*0Sstevel@tonic-gate /* ARGSUSED */
4503*0Sstevel@tonic-gate static int
4504*0Sstevel@tonic-gate object_get_size(dev_t dev, caddr_t arg, int mode, int *rval)
4505*0Sstevel@tonic-gate {
4506*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_get_size, object_get_size);
4507*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
4508*0Sstevel@tonic-gate 	kcf_req_params_t params;
4509*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
4510*0Sstevel@tonic-gate 	crypto_minor_t *cm;
4511*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
4512*0Sstevel@tonic-gate 	crypto_object_id_t handle;
4513*0Sstevel@tonic-gate 	size_t size;
4514*0Sstevel@tonic-gate 	int error = 0;
4515*0Sstevel@tonic-gate 	int rv;
4516*0Sstevel@tonic-gate 
4517*0Sstevel@tonic-gate 	STRUCT_INIT(object_get_size, mode);
4518*0Sstevel@tonic-gate 
4519*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4520*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "object_get_size: failed holding minor");
4521*0Sstevel@tonic-gate 		return (ENXIO);
4522*0Sstevel@tonic-gate 	}
4523*0Sstevel@tonic-gate 
4524*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(object_get_size),
4525*0Sstevel@tonic-gate 	    STRUCT_SIZE(object_get_size)) != 0) {
4526*0Sstevel@tonic-gate 		crypto_release_minor(cm);
4527*0Sstevel@tonic-gate 		return (EFAULT);
4528*0Sstevel@tonic-gate 	}
4529*0Sstevel@tonic-gate 
4530*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(object_get_size, gs_session);
4531*0Sstevel@tonic-gate 
4532*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4533*0Sstevel@tonic-gate 		goto release_minor;
4534*0Sstevel@tonic-gate 	}
4535*0Sstevel@tonic-gate 
4536*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider_nomech(
4537*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(object_ops),
4538*0Sstevel@tonic-gate 	    CRYPTO_OBJECT_OFFSET(object_get_size),
4539*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4540*0Sstevel@tonic-gate 		goto out;
4541*0Sstevel@tonic-gate 	}
4542*0Sstevel@tonic-gate 
4543*0Sstevel@tonic-gate 	handle = STRUCT_FGET(object_get_size, gs_handle);
4544*0Sstevel@tonic-gate 	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_GET_SIZE,
4545*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, handle, NULL, 0, NULL, &size,
4546*0Sstevel@tonic-gate 	    NULL, NULL, 0, NULL);
4547*0Sstevel@tonic-gate 
4548*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4549*0Sstevel@tonic-gate 
4550*0Sstevel@tonic-gate out:
4551*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
4552*0Sstevel@tonic-gate 
4553*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS) {
4554*0Sstevel@tonic-gate 		STRUCT_FSET(object_get_size, gs_size, size);
4555*0Sstevel@tonic-gate 	}
4556*0Sstevel@tonic-gate release_minor:
4557*0Sstevel@tonic-gate 	crypto_release_minor(cm);
4558*0Sstevel@tonic-gate 
4559*0Sstevel@tonic-gate 	if (error != 0)
4560*0Sstevel@tonic-gate 		return (error);
4561*0Sstevel@tonic-gate 
4562*0Sstevel@tonic-gate 	STRUCT_FSET(object_get_size, gs_return_value, rv);
4563*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(object_get_size), arg,
4564*0Sstevel@tonic-gate 	    STRUCT_SIZE(object_get_size)) != 0) {
4565*0Sstevel@tonic-gate 		return (EFAULT);
4566*0Sstevel@tonic-gate 	}
4567*0Sstevel@tonic-gate 	return (0);
4568*0Sstevel@tonic-gate }
4569*0Sstevel@tonic-gate 
4570*0Sstevel@tonic-gate /* ARGSUSED */
4571*0Sstevel@tonic-gate static int
4572*0Sstevel@tonic-gate object_set_attribute_value(dev_t dev, caddr_t arg, int mode, int *rval)
4573*0Sstevel@tonic-gate {
4574*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_set_attribute_value, set_attribute_value);
4575*0Sstevel@tonic-gate 	kproject_t *projp;
4576*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
4577*0Sstevel@tonic-gate 	kcf_req_params_t params;
4578*0Sstevel@tonic-gate 	crypto_object_attribute_t *k_attrs = NULL;
4579*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
4580*0Sstevel@tonic-gate 	crypto_minor_t *cm;
4581*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
4582*0Sstevel@tonic-gate 	crypto_object_id_t object_handle;
4583*0Sstevel@tonic-gate 	caddr_t sa_attributes;
4584*0Sstevel@tonic-gate 	size_t k_attrs_size;
4585*0Sstevel@tonic-gate 	size_t rctl_bytes = 0;
4586*0Sstevel@tonic-gate 	int error = 0;
4587*0Sstevel@tonic-gate 	int rv;
4588*0Sstevel@tonic-gate 	uint_t count;
4589*0Sstevel@tonic-gate 
4590*0Sstevel@tonic-gate 	STRUCT_INIT(set_attribute_value, mode);
4591*0Sstevel@tonic-gate 
4592*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4593*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
4594*0Sstevel@tonic-gate 		    "object_set_attribute_value: failed holding minor");
4595*0Sstevel@tonic-gate 		return (ENXIO);
4596*0Sstevel@tonic-gate 	}
4597*0Sstevel@tonic-gate 
4598*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(set_attribute_value),
4599*0Sstevel@tonic-gate 	    STRUCT_SIZE(set_attribute_value)) != 0) {
4600*0Sstevel@tonic-gate 		crypto_release_minor(cm);
4601*0Sstevel@tonic-gate 		return (EFAULT);
4602*0Sstevel@tonic-gate 	}
4603*0Sstevel@tonic-gate 
4604*0Sstevel@tonic-gate 	count = STRUCT_FGET(set_attribute_value, sa_count);
4605*0Sstevel@tonic-gate 	sa_attributes = STRUCT_FGETP(set_attribute_value, sa_attributes);
4606*0Sstevel@tonic-gate 	if (!copyin_attributes(mode, count, sa_attributes, &k_attrs,
4607*0Sstevel@tonic-gate 	    &k_attrs_size, NULL, &rv, &error, &rctl_bytes, 0, B_TRUE, &projp)) {
4608*0Sstevel@tonic-gate 		goto release_minor;
4609*0Sstevel@tonic-gate 	}
4610*0Sstevel@tonic-gate 
4611*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(set_attribute_value, sa_session);
4612*0Sstevel@tonic-gate 
4613*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4614*0Sstevel@tonic-gate 		goto release_minor;
4615*0Sstevel@tonic-gate 	}
4616*0Sstevel@tonic-gate 
4617*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider_nomech(
4618*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(object_ops),
4619*0Sstevel@tonic-gate 	    CRYPTO_OBJECT_OFFSET(object_set_attribute_value),
4620*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4621*0Sstevel@tonic-gate 		goto out;
4622*0Sstevel@tonic-gate 	}
4623*0Sstevel@tonic-gate 
4624*0Sstevel@tonic-gate 	object_handle = STRUCT_FGET(set_attribute_value, sa_handle);
4625*0Sstevel@tonic-gate 	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_SET_ATTRIBUTE_VALUE,
4626*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, object_handle, k_attrs, count,
4627*0Sstevel@tonic-gate 	    NULL, 0, NULL, NULL, 0, NULL);
4628*0Sstevel@tonic-gate 
4629*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4630*0Sstevel@tonic-gate 
4631*0Sstevel@tonic-gate out:
4632*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
4633*0Sstevel@tonic-gate 
4634*0Sstevel@tonic-gate release_minor:
4635*0Sstevel@tonic-gate 	if (rctl_bytes != 0) {
4636*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
4637*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(rctl_bytes, projp);
4638*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
4639*0Sstevel@tonic-gate 	}
4640*0Sstevel@tonic-gate 	crypto_release_minor(cm);
4641*0Sstevel@tonic-gate 
4642*0Sstevel@tonic-gate 	if (k_attrs != NULL)
4643*0Sstevel@tonic-gate 		kmem_free(k_attrs, k_attrs_size);
4644*0Sstevel@tonic-gate 
4645*0Sstevel@tonic-gate 	if (error != 0)
4646*0Sstevel@tonic-gate 		return (error);
4647*0Sstevel@tonic-gate 
4648*0Sstevel@tonic-gate 	STRUCT_FSET(set_attribute_value, sa_return_value, rv);
4649*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(set_attribute_value), arg,
4650*0Sstevel@tonic-gate 	    STRUCT_SIZE(set_attribute_value)) != 0) {
4651*0Sstevel@tonic-gate 		return (EFAULT);
4652*0Sstevel@tonic-gate 	}
4653*0Sstevel@tonic-gate 	return (0);
4654*0Sstevel@tonic-gate }
4655*0Sstevel@tonic-gate 
4656*0Sstevel@tonic-gate /* ARGSUSED */
4657*0Sstevel@tonic-gate static int
4658*0Sstevel@tonic-gate object_find_init(dev_t dev, caddr_t arg, int mode, int *rval)
4659*0Sstevel@tonic-gate {
4660*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_find_init, find_init);
4661*0Sstevel@tonic-gate 	kproject_t *projp;
4662*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
4663*0Sstevel@tonic-gate 	kcf_req_params_t params;
4664*0Sstevel@tonic-gate 	crypto_object_attribute_t *k_attrs = NULL;
4665*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
4666*0Sstevel@tonic-gate 	crypto_minor_t *cm;
4667*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
4668*0Sstevel@tonic-gate 	caddr_t attributes;
4669*0Sstevel@tonic-gate 	size_t k_attrs_size;
4670*0Sstevel@tonic-gate 	size_t rctl_bytes = 0;
4671*0Sstevel@tonic-gate 	int error = 0;
4672*0Sstevel@tonic-gate 	int rv;
4673*0Sstevel@tonic-gate 	uint_t count;
4674*0Sstevel@tonic-gate 	void *cookie;
4675*0Sstevel@tonic-gate 
4676*0Sstevel@tonic-gate 	STRUCT_INIT(find_init, mode);
4677*0Sstevel@tonic-gate 
4678*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4679*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "object_find_init: failed holding minor");
4680*0Sstevel@tonic-gate 		return (ENXIO);
4681*0Sstevel@tonic-gate 	}
4682*0Sstevel@tonic-gate 
4683*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(find_init), STRUCT_SIZE(find_init)) != 0) {
4684*0Sstevel@tonic-gate 		crypto_release_minor(cm);
4685*0Sstevel@tonic-gate 		return (EFAULT);
4686*0Sstevel@tonic-gate 	}
4687*0Sstevel@tonic-gate 
4688*0Sstevel@tonic-gate 	count = STRUCT_FGET(find_init, fi_count);
4689*0Sstevel@tonic-gate 	attributes = STRUCT_FGETP(find_init, fi_attributes);
4690*0Sstevel@tonic-gate 	if (!copyin_attributes(mode, count, attributes, &k_attrs,
4691*0Sstevel@tonic-gate 	    &k_attrs_size, NULL, &rv, &error, &rctl_bytes, 0, B_TRUE, &projp)) {
4692*0Sstevel@tonic-gate 		goto release_minor;
4693*0Sstevel@tonic-gate 	}
4694*0Sstevel@tonic-gate 
4695*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(find_init, fi_session);
4696*0Sstevel@tonic-gate 
4697*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4698*0Sstevel@tonic-gate 		goto release_minor;
4699*0Sstevel@tonic-gate 	}
4700*0Sstevel@tonic-gate 
4701*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider_nomech(
4702*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(object_ops),
4703*0Sstevel@tonic-gate 	    CRYPTO_OBJECT_OFFSET(object_find_init),
4704*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4705*0Sstevel@tonic-gate 		goto out;
4706*0Sstevel@tonic-gate 	}
4707*0Sstevel@tonic-gate 
4708*0Sstevel@tonic-gate 	/* check for an active find */
4709*0Sstevel@tonic-gate 	if (sp->sd_find_init_cookie != NULL) {
4710*0Sstevel@tonic-gate 		rv = CRYPTO_OPERATION_IS_ACTIVE;
4711*0Sstevel@tonic-gate 		CRYPTO_SESSION_RELE(sp);
4712*0Sstevel@tonic-gate 		goto release_minor;
4713*0Sstevel@tonic-gate 	}
4714*0Sstevel@tonic-gate 
4715*0Sstevel@tonic-gate 	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_FIND_INIT,
4716*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, 0, k_attrs, count, NULL, 0,
4717*0Sstevel@tonic-gate 	    &cookie, NULL, 0, NULL);
4718*0Sstevel@tonic-gate 
4719*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4720*0Sstevel@tonic-gate 
4721*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS) {
4722*0Sstevel@tonic-gate 		/*
4723*0Sstevel@tonic-gate 		 * The cookie is allocated by a provider at the start of an
4724*0Sstevel@tonic-gate 		 * object search.  It is freed when the search is terminated
4725*0Sstevel@tonic-gate 		 * by a final operation, or when the session is closed.
4726*0Sstevel@tonic-gate 		 * It contains state information about which object handles
4727*0Sstevel@tonic-gate 		 * have been returned to the caller.
4728*0Sstevel@tonic-gate 		 */
4729*0Sstevel@tonic-gate 		sp->sd_find_init_cookie = cookie;
4730*0Sstevel@tonic-gate 	}
4731*0Sstevel@tonic-gate 
4732*0Sstevel@tonic-gate out:
4733*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
4734*0Sstevel@tonic-gate 
4735*0Sstevel@tonic-gate release_minor:
4736*0Sstevel@tonic-gate 	if (rctl_bytes != 0) {
4737*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
4738*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(rctl_bytes, projp);
4739*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
4740*0Sstevel@tonic-gate 	}
4741*0Sstevel@tonic-gate 	crypto_release_minor(cm);
4742*0Sstevel@tonic-gate 
4743*0Sstevel@tonic-gate 	if (k_attrs != NULL)
4744*0Sstevel@tonic-gate 		kmem_free(k_attrs, k_attrs_size);
4745*0Sstevel@tonic-gate 
4746*0Sstevel@tonic-gate 	if (error != 0)
4747*0Sstevel@tonic-gate 		return (error);
4748*0Sstevel@tonic-gate 
4749*0Sstevel@tonic-gate 	STRUCT_FSET(find_init, fi_return_value, rv);
4750*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(find_init), arg, STRUCT_SIZE(find_init)) != 0) {
4751*0Sstevel@tonic-gate 		return (EFAULT);
4752*0Sstevel@tonic-gate 	}
4753*0Sstevel@tonic-gate 	return (0);
4754*0Sstevel@tonic-gate }
4755*0Sstevel@tonic-gate 
4756*0Sstevel@tonic-gate /* ARGSUSED */
4757*0Sstevel@tonic-gate static int
4758*0Sstevel@tonic-gate object_find_update(dev_t dev, caddr_t arg, int mode, int *rval)
4759*0Sstevel@tonic-gate {
4760*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_find_update, find_update);
4761*0Sstevel@tonic-gate 	kproject_t *projp;
4762*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
4763*0Sstevel@tonic-gate 	kcf_req_params_t params;
4764*0Sstevel@tonic-gate 	crypto_minor_t *cm;
4765*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
4766*0Sstevel@tonic-gate 	crypto_object_id_t *buffer = NULL;
4767*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
4768*0Sstevel@tonic-gate 	size_t len, rctl_bytes = 0;
4769*0Sstevel@tonic-gate 	uint_t count, max_count;
4770*0Sstevel@tonic-gate 	int rv, error = 0;
4771*0Sstevel@tonic-gate 
4772*0Sstevel@tonic-gate 	STRUCT_INIT(find_update, mode);
4773*0Sstevel@tonic-gate 
4774*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4775*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "object_find_update: failed holding minor");
4776*0Sstevel@tonic-gate 		return (ENXIO);
4777*0Sstevel@tonic-gate 	}
4778*0Sstevel@tonic-gate 
4779*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(find_update),
4780*0Sstevel@tonic-gate 	    STRUCT_SIZE(find_update)) != 0) {
4781*0Sstevel@tonic-gate 		crypto_release_minor(cm);
4782*0Sstevel@tonic-gate 		return (EFAULT);
4783*0Sstevel@tonic-gate 	}
4784*0Sstevel@tonic-gate 
4785*0Sstevel@tonic-gate 	max_count = STRUCT_FGET(find_update, fu_max_count);
4786*0Sstevel@tonic-gate 	if (max_count > CRYPTO_MAX_FIND_COUNT) {
4787*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "object_find_update: count greater than %d, "
4788*0Sstevel@tonic-gate 		    "pid = %d", CRYPTO_MAX_FIND_COUNT, curproc->p_pid);
4789*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
4790*0Sstevel@tonic-gate 		goto release_minor;
4791*0Sstevel@tonic-gate 	}
4792*0Sstevel@tonic-gate 	len = max_count * sizeof (crypto_object_id_t);
4793*0Sstevel@tonic-gate 	if ((rv = crypto_buffer_check(len, &projp)) != CRYPTO_SUCCESS) {
4794*0Sstevel@tonic-gate 		goto release_minor;
4795*0Sstevel@tonic-gate 	}
4796*0Sstevel@tonic-gate 	rctl_bytes = len;
4797*0Sstevel@tonic-gate 	buffer = kmem_alloc(len, KM_SLEEP);
4798*0Sstevel@tonic-gate 
4799*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(find_update, fu_session);
4800*0Sstevel@tonic-gate 
4801*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4802*0Sstevel@tonic-gate 		goto release_minor;
4803*0Sstevel@tonic-gate 	}
4804*0Sstevel@tonic-gate 
4805*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider_nomech(
4806*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(object_ops),
4807*0Sstevel@tonic-gate 	    CRYPTO_OBJECT_OFFSET(object_find),
4808*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4809*0Sstevel@tonic-gate 		goto out;
4810*0Sstevel@tonic-gate 	}
4811*0Sstevel@tonic-gate 
4812*0Sstevel@tonic-gate 	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_FIND,
4813*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, 0, NULL, 0, buffer, 0,
4814*0Sstevel@tonic-gate 	    NULL, sp->sd_find_init_cookie, max_count, &count);
4815*0Sstevel@tonic-gate 
4816*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4817*0Sstevel@tonic-gate 
4818*0Sstevel@tonic-gate out:
4819*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
4820*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS) {
4821*0Sstevel@tonic-gate 		if (count > max_count) {
4822*0Sstevel@tonic-gate 			/* bad bad provider */
4823*0Sstevel@tonic-gate 			rv = CRYPTO_FAILED;
4824*0Sstevel@tonic-gate 			goto release_minor;
4825*0Sstevel@tonic-gate 		}
4826*0Sstevel@tonic-gate 		if (count != 0) {
4827*0Sstevel@tonic-gate 			/* copyout handles */
4828*0Sstevel@tonic-gate 			if (copyout(buffer,
4829*0Sstevel@tonic-gate 			    STRUCT_FGETP(find_update, fu_handles),
4830*0Sstevel@tonic-gate 			    count * sizeof (crypto_object_id_t)) != 0) {
4831*0Sstevel@tonic-gate 				error = EFAULT;
4832*0Sstevel@tonic-gate 			}
4833*0Sstevel@tonic-gate 		}
4834*0Sstevel@tonic-gate 		STRUCT_FSET(find_update, fu_count, count);
4835*0Sstevel@tonic-gate 	}
4836*0Sstevel@tonic-gate 
4837*0Sstevel@tonic-gate release_minor:
4838*0Sstevel@tonic-gate 	if (rctl_bytes != 0) {
4839*0Sstevel@tonic-gate 		mutex_enter(&crypto_rctl_lock);
4840*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(rctl_bytes, projp);
4841*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
4842*0Sstevel@tonic-gate 	}
4843*0Sstevel@tonic-gate 	crypto_release_minor(cm);
4844*0Sstevel@tonic-gate 
4845*0Sstevel@tonic-gate 	if (buffer != NULL)
4846*0Sstevel@tonic-gate 		kmem_free(buffer, len);
4847*0Sstevel@tonic-gate 
4848*0Sstevel@tonic-gate 	if (error != 0)
4849*0Sstevel@tonic-gate 		return (error);
4850*0Sstevel@tonic-gate 
4851*0Sstevel@tonic-gate 	STRUCT_FSET(find_update, fu_return_value, rv);
4852*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(find_update), arg,
4853*0Sstevel@tonic-gate 	    STRUCT_SIZE(find_update)) != 0) {
4854*0Sstevel@tonic-gate 		return (EFAULT);
4855*0Sstevel@tonic-gate 	}
4856*0Sstevel@tonic-gate 
4857*0Sstevel@tonic-gate 	return (0);
4858*0Sstevel@tonic-gate }
4859*0Sstevel@tonic-gate 
4860*0Sstevel@tonic-gate /*
4861*0Sstevel@tonic-gate  * Free provider-allocated storage used for find object searches.
4862*0Sstevel@tonic-gate  */
4863*0Sstevel@tonic-gate static int
4864*0Sstevel@tonic-gate crypto_free_find_ctx(crypto_session_data_t *sp)
4865*0Sstevel@tonic-gate {
4866*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
4867*0Sstevel@tonic-gate 	kcf_req_params_t params;
4868*0Sstevel@tonic-gate 	int rv;
4869*0Sstevel@tonic-gate 
4870*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider_nomech(
4871*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(object_ops),
4872*0Sstevel@tonic-gate 	    CRYPTO_OBJECT_OFFSET(object_find_final),
4873*0Sstevel@tonic-gate 	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4874*0Sstevel@tonic-gate 		return (rv);
4875*0Sstevel@tonic-gate 	}
4876*0Sstevel@tonic-gate 
4877*0Sstevel@tonic-gate 	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_FIND_FINAL,
4878*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, 0, NULL, 0, NULL, 0,
4879*0Sstevel@tonic-gate 	    NULL, sp->sd_find_init_cookie, 0, NULL);
4880*0Sstevel@tonic-gate 
4881*0Sstevel@tonic-gate 	return (kcf_submit_request(real_provider,
4882*0Sstevel@tonic-gate 	    NULL, NULL, &params, B_FALSE));
4883*0Sstevel@tonic-gate }
4884*0Sstevel@tonic-gate 
4885*0Sstevel@tonic-gate /* ARGSUSED */
4886*0Sstevel@tonic-gate static int
4887*0Sstevel@tonic-gate object_find_final(dev_t dev, caddr_t arg, int mode, int *rval)
4888*0Sstevel@tonic-gate {
4889*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_find_final, object_find_final);
4890*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
4891*0Sstevel@tonic-gate 	crypto_minor_t *cm;
4892*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
4893*0Sstevel@tonic-gate 	int error = 0;
4894*0Sstevel@tonic-gate 	int rv;
4895*0Sstevel@tonic-gate 
4896*0Sstevel@tonic-gate 	STRUCT_INIT(object_find_final, mode);
4897*0Sstevel@tonic-gate 
4898*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4899*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "object_find_final: failed holding minor");
4900*0Sstevel@tonic-gate 		return (ENXIO);
4901*0Sstevel@tonic-gate 	}
4902*0Sstevel@tonic-gate 
4903*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(object_find_final),
4904*0Sstevel@tonic-gate 	    STRUCT_SIZE(object_find_final)) != 0) {
4905*0Sstevel@tonic-gate 		crypto_release_minor(cm);
4906*0Sstevel@tonic-gate 		return (EFAULT);
4907*0Sstevel@tonic-gate 	}
4908*0Sstevel@tonic-gate 
4909*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(object_find_final, ff_session);
4910*0Sstevel@tonic-gate 
4911*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4912*0Sstevel@tonic-gate 		goto release_minor;
4913*0Sstevel@tonic-gate 	}
4914*0Sstevel@tonic-gate 
4915*0Sstevel@tonic-gate 	if ((rv = crypto_free_find_ctx(sp)) == CRYPTO_SUCCESS) {
4916*0Sstevel@tonic-gate 		sp->sd_find_init_cookie = NULL;
4917*0Sstevel@tonic-gate 	}
4918*0Sstevel@tonic-gate 
4919*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
4920*0Sstevel@tonic-gate 
4921*0Sstevel@tonic-gate release_minor:
4922*0Sstevel@tonic-gate 	crypto_release_minor(cm);
4923*0Sstevel@tonic-gate 
4924*0Sstevel@tonic-gate 	if (error != 0)
4925*0Sstevel@tonic-gate 		return (error);
4926*0Sstevel@tonic-gate 
4927*0Sstevel@tonic-gate 	STRUCT_FSET(object_find_final, ff_return_value, rv);
4928*0Sstevel@tonic-gate 
4929*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(object_find_final), arg,
4930*0Sstevel@tonic-gate 	    STRUCT_SIZE(object_find_final)) != 0) {
4931*0Sstevel@tonic-gate 		return (EFAULT);
4932*0Sstevel@tonic-gate 	}
4933*0Sstevel@tonic-gate 	return (0);
4934*0Sstevel@tonic-gate }
4935*0Sstevel@tonic-gate 
4936*0Sstevel@tonic-gate /* ARGSUSED */
4937*0Sstevel@tonic-gate static int
4938*0Sstevel@tonic-gate object_generate_key(dev_t dev, caddr_t arg, int mode, int *rval)
4939*0Sstevel@tonic-gate {
4940*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_generate_key, generate_key);
4941*0Sstevel@tonic-gate 	kproject_t *mech_projp, *key_projp;
4942*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
4943*0Sstevel@tonic-gate 	kcf_req_params_t params;
4944*0Sstevel@tonic-gate 	crypto_mechanism_t mech;
4945*0Sstevel@tonic-gate 	crypto_object_attribute_t *k_attrs = NULL;
4946*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
4947*0Sstevel@tonic-gate 	crypto_minor_t *cm;
4948*0Sstevel@tonic-gate 	crypto_session_data_t *sp = NULL;
4949*0Sstevel@tonic-gate 	crypto_object_id_t key_handle;
4950*0Sstevel@tonic-gate 	caddr_t attributes;
4951*0Sstevel@tonic-gate 	size_t k_attrs_size;
4952*0Sstevel@tonic-gate 	size_t mech_rctl_bytes = 0, key_rctl_bytes = 0;
4953*0Sstevel@tonic-gate 	size_t carry;
4954*0Sstevel@tonic-gate 	uint_t count;
4955*0Sstevel@tonic-gate 	int error = 0;
4956*0Sstevel@tonic-gate 	int rv;
4957*0Sstevel@tonic-gate 
4958*0Sstevel@tonic-gate 	STRUCT_INIT(generate_key, mode);
4959*0Sstevel@tonic-gate 
4960*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4961*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "object_generate_key: failed holding minor");
4962*0Sstevel@tonic-gate 		return (ENXIO);
4963*0Sstevel@tonic-gate 	}
4964*0Sstevel@tonic-gate 
4965*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(generate_key),
4966*0Sstevel@tonic-gate 	    STRUCT_SIZE(generate_key)) != 0) {
4967*0Sstevel@tonic-gate 		crypto_release_minor(cm);
4968*0Sstevel@tonic-gate 		return (EFAULT);
4969*0Sstevel@tonic-gate 	}
4970*0Sstevel@tonic-gate 
4971*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(generate_key, gk_session);
4972*0Sstevel@tonic-gate 
4973*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4974*0Sstevel@tonic-gate 		goto release_minor;
4975*0Sstevel@tonic-gate 	}
4976*0Sstevel@tonic-gate 
4977*0Sstevel@tonic-gate 	if (!copyin_mech(mode, STRUCT_FADDR(generate_key, gk_mechanism),
4978*0Sstevel@tonic-gate 	    &mech, &mech_rctl_bytes, &carry, &rv, &error, &mech_projp)) {
4979*0Sstevel@tonic-gate 		goto release_minor;
4980*0Sstevel@tonic-gate 	}
4981*0Sstevel@tonic-gate 
4982*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider(mech.cm_type,
4983*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(key_ops),
4984*0Sstevel@tonic-gate 	    CRYPTO_KEY_OFFSET(key_generate), sp->sd_provider,
4985*0Sstevel@tonic-gate 	    &real_provider)) != CRYPTO_SUCCESS) {
4986*0Sstevel@tonic-gate 		goto release_minor;
4987*0Sstevel@tonic-gate 	}
4988*0Sstevel@tonic-gate 
4989*0Sstevel@tonic-gate 	count = STRUCT_FGET(generate_key, gk_count);
4990*0Sstevel@tonic-gate 	attributes = STRUCT_FGETP(generate_key, gk_attributes);
4991*0Sstevel@tonic-gate 	if (!copyin_attributes(mode, count, attributes, &k_attrs,
4992*0Sstevel@tonic-gate 	    &k_attrs_size, NULL, &rv, &error, &key_rctl_bytes, carry, B_TRUE,
4993*0Sstevel@tonic-gate 	    &key_projp)) {
4994*0Sstevel@tonic-gate 		goto release_minor;
4995*0Sstevel@tonic-gate 	}
4996*0Sstevel@tonic-gate 
4997*0Sstevel@tonic-gate 	KCF_WRAP_KEY_OPS_PARAMS(&params, KCF_OP_KEY_GENERATE,
4998*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, &mech, k_attrs, count,
4999*0Sstevel@tonic-gate 	    &key_handle, NULL, 0, NULL, NULL, NULL, 0);
5000*0Sstevel@tonic-gate 
5001*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5002*0Sstevel@tonic-gate 
5003*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS)
5004*0Sstevel@tonic-gate 		STRUCT_FSET(generate_key, gk_handle, key_handle);
5005*0Sstevel@tonic-gate 
5006*0Sstevel@tonic-gate release_minor:
5007*0Sstevel@tonic-gate 	mutex_enter(&crypto_rctl_lock);
5008*0Sstevel@tonic-gate 	if (mech_rctl_bytes != 0)
5009*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(mech_rctl_bytes, mech_projp);
5010*0Sstevel@tonic-gate 	if (key_rctl_bytes != 0)
5011*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(key_rctl_bytes, key_projp);
5012*0Sstevel@tonic-gate 	mutex_exit(&crypto_rctl_lock);
5013*0Sstevel@tonic-gate 
5014*0Sstevel@tonic-gate 	if (k_attrs != NULL)
5015*0Sstevel@tonic-gate 		kmem_free(k_attrs, k_attrs_size);
5016*0Sstevel@tonic-gate 
5017*0Sstevel@tonic-gate 	if (error != 0)
5018*0Sstevel@tonic-gate 		goto out;
5019*0Sstevel@tonic-gate 
5020*0Sstevel@tonic-gate 	STRUCT_FSET(generate_key, gk_return_value, rv);
5021*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(generate_key), arg,
5022*0Sstevel@tonic-gate 	    STRUCT_SIZE(generate_key)) != 0) {
5023*0Sstevel@tonic-gate 		if (rv == CRYPTO_SUCCESS) {
5024*0Sstevel@tonic-gate 			KCF_WRAP_OBJECT_OPS_PARAMS(&params,
5025*0Sstevel@tonic-gate 			    KCF_OP_OBJECT_DESTROY,
5026*0Sstevel@tonic-gate 			    sp->sd_provider_session->ps_session, key_handle,
5027*0Sstevel@tonic-gate 			    NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
5028*0Sstevel@tonic-gate 
5029*0Sstevel@tonic-gate 			(void) kcf_submit_request(real_provider, NULL,
5030*0Sstevel@tonic-gate 			    NULL, &params, B_FALSE);
5031*0Sstevel@tonic-gate 
5032*0Sstevel@tonic-gate 			error = EFAULT;
5033*0Sstevel@tonic-gate 		}
5034*0Sstevel@tonic-gate 	}
5035*0Sstevel@tonic-gate out:
5036*0Sstevel@tonic-gate 	if (sp != NULL)
5037*0Sstevel@tonic-gate 		CRYPTO_SESSION_RELE(sp);
5038*0Sstevel@tonic-gate 	crypto_release_minor(cm);
5039*0Sstevel@tonic-gate 	return (error);
5040*0Sstevel@tonic-gate }
5041*0Sstevel@tonic-gate 
5042*0Sstevel@tonic-gate /* ARGSUSED */
5043*0Sstevel@tonic-gate static int
5044*0Sstevel@tonic-gate object_generate_key_pair(dev_t dev, caddr_t arg, int mode, int *rval)
5045*0Sstevel@tonic-gate {
5046*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_generate_key_pair, generate_key_pair);
5047*0Sstevel@tonic-gate 	kproject_t *pub_projp, *pri_projp, *mech_projp;
5048*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
5049*0Sstevel@tonic-gate 	kcf_req_params_t params;
5050*0Sstevel@tonic-gate 	crypto_mechanism_t mech;
5051*0Sstevel@tonic-gate 	crypto_object_attribute_t *k_pub_attrs = NULL;
5052*0Sstevel@tonic-gate 	crypto_object_attribute_t *k_pri_attrs = NULL;
5053*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
5054*0Sstevel@tonic-gate 	crypto_minor_t *cm;
5055*0Sstevel@tonic-gate 	crypto_session_data_t *sp = NULL;
5056*0Sstevel@tonic-gate 	crypto_object_id_t pub_handle;
5057*0Sstevel@tonic-gate 	crypto_object_id_t pri_handle;
5058*0Sstevel@tonic-gate 	caddr_t pri_attributes;
5059*0Sstevel@tonic-gate 	caddr_t pub_attributes;
5060*0Sstevel@tonic-gate 	size_t k_pub_attrs_size, k_pri_attrs_size;
5061*0Sstevel@tonic-gate 	size_t mech_rctl_bytes = 0;
5062*0Sstevel@tonic-gate 	size_t pub_rctl_bytes = 0;
5063*0Sstevel@tonic-gate 	size_t pri_rctl_bytes = 0;
5064*0Sstevel@tonic-gate 	size_t carry;
5065*0Sstevel@tonic-gate 	uint_t pub_count;
5066*0Sstevel@tonic-gate 	uint_t pri_count;
5067*0Sstevel@tonic-gate 	int error = 0;
5068*0Sstevel@tonic-gate 	int rv;
5069*0Sstevel@tonic-gate 
5070*0Sstevel@tonic-gate 	STRUCT_INIT(generate_key_pair, mode);
5071*0Sstevel@tonic-gate 
5072*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5073*0Sstevel@tonic-gate 		cmn_err(CE_WARN,
5074*0Sstevel@tonic-gate 		    "object_generate_key_pair: failed holding minor");
5075*0Sstevel@tonic-gate 		return (ENXIO);
5076*0Sstevel@tonic-gate 	}
5077*0Sstevel@tonic-gate 
5078*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(generate_key_pair),
5079*0Sstevel@tonic-gate 	    STRUCT_SIZE(generate_key_pair)) != 0) {
5080*0Sstevel@tonic-gate 		crypto_release_minor(cm);
5081*0Sstevel@tonic-gate 		return (EFAULT);
5082*0Sstevel@tonic-gate 	}
5083*0Sstevel@tonic-gate 
5084*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(generate_key_pair, kp_session);
5085*0Sstevel@tonic-gate 
5086*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5087*0Sstevel@tonic-gate 		goto release_minor;
5088*0Sstevel@tonic-gate 	}
5089*0Sstevel@tonic-gate 
5090*0Sstevel@tonic-gate 	if (!copyin_mech(mode, STRUCT_FADDR(generate_key_pair, kp_mechanism),
5091*0Sstevel@tonic-gate 	    &mech, &mech_rctl_bytes, &carry, &rv, &error, &mech_projp)) {
5092*0Sstevel@tonic-gate 		goto release_minor;
5093*0Sstevel@tonic-gate 	}
5094*0Sstevel@tonic-gate 
5095*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider(mech.cm_type,
5096*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(key_ops),
5097*0Sstevel@tonic-gate 	    CRYPTO_KEY_OFFSET(key_generate_pair), sp->sd_provider,
5098*0Sstevel@tonic-gate 	    &real_provider)) != CRYPTO_SUCCESS) {
5099*0Sstevel@tonic-gate 		goto release_minor;
5100*0Sstevel@tonic-gate 	}
5101*0Sstevel@tonic-gate 
5102*0Sstevel@tonic-gate 	pub_count = STRUCT_FGET(generate_key_pair, kp_public_count);
5103*0Sstevel@tonic-gate 	pri_count = STRUCT_FGET(generate_key_pair, kp_private_count);
5104*0Sstevel@tonic-gate 
5105*0Sstevel@tonic-gate 	pub_attributes = STRUCT_FGETP(generate_key_pair, kp_public_attributes);
5106*0Sstevel@tonic-gate 	if (!copyin_attributes(mode, pub_count, pub_attributes, &k_pub_attrs,
5107*0Sstevel@tonic-gate 	    &k_pub_attrs_size, NULL, &rv, &error, &pub_rctl_bytes, carry,
5108*0Sstevel@tonic-gate 	    B_TRUE, &pub_projp)) {
5109*0Sstevel@tonic-gate 		goto release_minor;
5110*0Sstevel@tonic-gate 	}
5111*0Sstevel@tonic-gate 
5112*0Sstevel@tonic-gate 	pri_attributes = STRUCT_FGETP(generate_key_pair, kp_private_attributes);
5113*0Sstevel@tonic-gate 	if (!copyin_attributes(mode, pri_count, pri_attributes, &k_pri_attrs,
5114*0Sstevel@tonic-gate 	    &k_pri_attrs_size, NULL, &rv, &error, &pri_rctl_bytes, 0,
5115*0Sstevel@tonic-gate 	    B_TRUE, &pri_projp)) {
5116*0Sstevel@tonic-gate 		goto release_minor;
5117*0Sstevel@tonic-gate 	}
5118*0Sstevel@tonic-gate 
5119*0Sstevel@tonic-gate 	KCF_WRAP_KEY_OPS_PARAMS(&params, KCF_OP_KEY_GENERATE_PAIR,
5120*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, &mech, k_pub_attrs,
5121*0Sstevel@tonic-gate 	    pub_count, &pub_handle, k_pri_attrs, pri_count, &pri_handle,
5122*0Sstevel@tonic-gate 	    NULL, NULL, 0);
5123*0Sstevel@tonic-gate 
5124*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5125*0Sstevel@tonic-gate 
5126*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS) {
5127*0Sstevel@tonic-gate 		STRUCT_FSET(generate_key_pair, kp_public_handle, pub_handle);
5128*0Sstevel@tonic-gate 		STRUCT_FSET(generate_key_pair, kp_private_handle, pri_handle);
5129*0Sstevel@tonic-gate 	}
5130*0Sstevel@tonic-gate 
5131*0Sstevel@tonic-gate release_minor:
5132*0Sstevel@tonic-gate 	mutex_enter(&crypto_rctl_lock);
5133*0Sstevel@tonic-gate 	if (mech_rctl_bytes != 0)
5134*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(mech_rctl_bytes, mech_projp);
5135*0Sstevel@tonic-gate 	if (pub_rctl_bytes != 0)
5136*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(pub_rctl_bytes, pub_projp);
5137*0Sstevel@tonic-gate 	if (pri_rctl_bytes != 0)
5138*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(pri_rctl_bytes, pri_projp);
5139*0Sstevel@tonic-gate 	mutex_exit(&crypto_rctl_lock);
5140*0Sstevel@tonic-gate 
5141*0Sstevel@tonic-gate 	if (k_pub_attrs != NULL)
5142*0Sstevel@tonic-gate 		kmem_free(k_pub_attrs, k_pub_attrs_size);
5143*0Sstevel@tonic-gate 
5144*0Sstevel@tonic-gate 	if (k_pri_attrs != NULL)
5145*0Sstevel@tonic-gate 		kmem_free(k_pri_attrs, k_pri_attrs_size);
5146*0Sstevel@tonic-gate 
5147*0Sstevel@tonic-gate 	if (error != 0)
5148*0Sstevel@tonic-gate 		goto out;
5149*0Sstevel@tonic-gate 
5150*0Sstevel@tonic-gate 	STRUCT_FSET(generate_key_pair, kp_return_value, rv);
5151*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(generate_key_pair), arg,
5152*0Sstevel@tonic-gate 	    STRUCT_SIZE(generate_key_pair)) != 0) {
5153*0Sstevel@tonic-gate 		if (rv == CRYPTO_SUCCESS) {
5154*0Sstevel@tonic-gate 			KCF_WRAP_OBJECT_OPS_PARAMS(&params,
5155*0Sstevel@tonic-gate 			    KCF_OP_OBJECT_DESTROY,
5156*0Sstevel@tonic-gate 			    sp->sd_provider_session->ps_session, pub_handle,
5157*0Sstevel@tonic-gate 			    NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
5158*0Sstevel@tonic-gate 
5159*0Sstevel@tonic-gate 			(void) kcf_submit_request(real_provider, NULL,
5160*0Sstevel@tonic-gate 			    NULL, &params, B_FALSE);
5161*0Sstevel@tonic-gate 
5162*0Sstevel@tonic-gate 			KCF_WRAP_OBJECT_OPS_PARAMS(&params,
5163*0Sstevel@tonic-gate 			    KCF_OP_OBJECT_DESTROY,
5164*0Sstevel@tonic-gate 			    sp->sd_provider_session->ps_session, pri_handle,
5165*0Sstevel@tonic-gate 			    NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
5166*0Sstevel@tonic-gate 
5167*0Sstevel@tonic-gate 			(void) kcf_submit_request(real_provider, NULL,
5168*0Sstevel@tonic-gate 			    NULL, &params, B_FALSE);
5169*0Sstevel@tonic-gate 
5170*0Sstevel@tonic-gate 			error = EFAULT;
5171*0Sstevel@tonic-gate 		}
5172*0Sstevel@tonic-gate 	}
5173*0Sstevel@tonic-gate out:
5174*0Sstevel@tonic-gate 	if (sp != NULL)
5175*0Sstevel@tonic-gate 		CRYPTO_SESSION_RELE(sp);
5176*0Sstevel@tonic-gate 	crypto_release_minor(cm);
5177*0Sstevel@tonic-gate 	return (error);
5178*0Sstevel@tonic-gate }
5179*0Sstevel@tonic-gate 
5180*0Sstevel@tonic-gate /* ARGSUSED */
5181*0Sstevel@tonic-gate static int
5182*0Sstevel@tonic-gate object_wrap_key(dev_t dev, caddr_t arg, int mode, int *rval)
5183*0Sstevel@tonic-gate {
5184*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_wrap_key, wrap_key);
5185*0Sstevel@tonic-gate 	kproject_t *mech_projp, *key_projp, *wrapped_key_projp;
5186*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
5187*0Sstevel@tonic-gate 	kcf_req_params_t params;
5188*0Sstevel@tonic-gate 	crypto_mechanism_t mech;
5189*0Sstevel@tonic-gate 	crypto_key_t key;
5190*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
5191*0Sstevel@tonic-gate 	crypto_minor_t *cm;
5192*0Sstevel@tonic-gate 	crypto_session_data_t *sp;
5193*0Sstevel@tonic-gate 	crypto_object_id_t handle;
5194*0Sstevel@tonic-gate 	size_t mech_rctl_bytes = 0, key_rctl_bytes = 0;
5195*0Sstevel@tonic-gate 	size_t wrapped_key_rctl_bytes = 0;
5196*0Sstevel@tonic-gate 	size_t carry;
5197*0Sstevel@tonic-gate 	size_t wrapped_key_len, new_wrapped_key_len;
5198*0Sstevel@tonic-gate 	uchar_t *wrapped_key = NULL;
5199*0Sstevel@tonic-gate 	char *wrapped_key_buffer;
5200*0Sstevel@tonic-gate 	int error = 0;
5201*0Sstevel@tonic-gate 	int rv;
5202*0Sstevel@tonic-gate 
5203*0Sstevel@tonic-gate 	STRUCT_INIT(wrap_key, mode);
5204*0Sstevel@tonic-gate 
5205*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5206*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "object_wrap_key: failed holding minor");
5207*0Sstevel@tonic-gate 		return (ENXIO);
5208*0Sstevel@tonic-gate 	}
5209*0Sstevel@tonic-gate 
5210*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(wrap_key), STRUCT_SIZE(wrap_key)) != 0) {
5211*0Sstevel@tonic-gate 		crypto_release_minor(cm);
5212*0Sstevel@tonic-gate 		return (EFAULT);
5213*0Sstevel@tonic-gate 	}
5214*0Sstevel@tonic-gate 
5215*0Sstevel@tonic-gate 	bzero(&key, sizeof (crypto_key_t));
5216*0Sstevel@tonic-gate 
5217*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(wrap_key, wk_session);
5218*0Sstevel@tonic-gate 
5219*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5220*0Sstevel@tonic-gate 		goto release_minor;
5221*0Sstevel@tonic-gate 	}
5222*0Sstevel@tonic-gate 
5223*0Sstevel@tonic-gate 	if (!copyin_mech(mode, STRUCT_FADDR(wrap_key, wk_mechanism),
5224*0Sstevel@tonic-gate 	    &mech, &mech_rctl_bytes, &carry, &rv, &error, &mech_projp)) {
5225*0Sstevel@tonic-gate 		goto out;
5226*0Sstevel@tonic-gate 	}
5227*0Sstevel@tonic-gate 
5228*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider(mech.cm_type,
5229*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(key_ops),
5230*0Sstevel@tonic-gate 	    CRYPTO_KEY_OFFSET(key_wrap), sp->sd_provider,
5231*0Sstevel@tonic-gate 	    &real_provider)) != CRYPTO_SUCCESS) {
5232*0Sstevel@tonic-gate 		goto out;
5233*0Sstevel@tonic-gate 	}
5234*0Sstevel@tonic-gate 
5235*0Sstevel@tonic-gate 	if (!copyin_key(mode, STRUCT_FADDR(wrap_key, wk_wrapping_key), &key,
5236*0Sstevel@tonic-gate 	    &key_rctl_bytes, &rv, &error, carry, &key_projp)) {
5237*0Sstevel@tonic-gate 		goto out;
5238*0Sstevel@tonic-gate 	}
5239*0Sstevel@tonic-gate 
5240*0Sstevel@tonic-gate 	wrapped_key_len = STRUCT_FGET(wrap_key, wk_wrapped_key_len);
5241*0Sstevel@tonic-gate 
5242*0Sstevel@tonic-gate 	/*
5243*0Sstevel@tonic-gate 	 * Don't allocate output buffer unless both buffer pointer and
5244*0Sstevel@tonic-gate 	 * buffer length are not NULL or 0 (length).
5245*0Sstevel@tonic-gate 	 */
5246*0Sstevel@tonic-gate 	wrapped_key_buffer = STRUCT_FGETP(wrap_key, wk_wrapped_key);
5247*0Sstevel@tonic-gate 	if (wrapped_key_buffer == NULL || wrapped_key_len == 0) {
5248*0Sstevel@tonic-gate 		wrapped_key_len = 0;
5249*0Sstevel@tonic-gate 	}
5250*0Sstevel@tonic-gate 
5251*0Sstevel@tonic-gate 	if (wrapped_key_len > crypto_max_buffer_len) {
5252*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "object_wrap_key: buffer greater than %ld "
5253*0Sstevel@tonic-gate 		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
5254*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
5255*0Sstevel@tonic-gate 		goto out;
5256*0Sstevel@tonic-gate 	}
5257*0Sstevel@tonic-gate 
5258*0Sstevel@tonic-gate 	if ((rv = crypto_buffer_check(wrapped_key_len,
5259*0Sstevel@tonic-gate 	    &wrapped_key_projp)) != CRYPTO_SUCCESS) {
5260*0Sstevel@tonic-gate 		goto out;
5261*0Sstevel@tonic-gate 	}
5262*0Sstevel@tonic-gate 
5263*0Sstevel@tonic-gate 	/* new_wrapped_key_len can be modified by the provider */
5264*0Sstevel@tonic-gate 	wrapped_key_rctl_bytes = new_wrapped_key_len = wrapped_key_len;
5265*0Sstevel@tonic-gate 	wrapped_key = kmem_alloc(wrapped_key_len, KM_SLEEP);
5266*0Sstevel@tonic-gate 
5267*0Sstevel@tonic-gate 	handle = STRUCT_FGET(wrap_key, wk_object_handle);
5268*0Sstevel@tonic-gate 	KCF_WRAP_KEY_OPS_PARAMS(&params, KCF_OP_KEY_WRAP,
5269*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, &mech, NULL, 0, &handle,
5270*0Sstevel@tonic-gate 	    NULL, 0, NULL, &key, wrapped_key, &new_wrapped_key_len);
5271*0Sstevel@tonic-gate 
5272*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5273*0Sstevel@tonic-gate 
5274*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS) {
5275*0Sstevel@tonic-gate 		if (wrapped_key_len != 0 && copyout(wrapped_key,
5276*0Sstevel@tonic-gate 		    wrapped_key_buffer, new_wrapped_key_len) != 0) {
5277*0Sstevel@tonic-gate 			error = EFAULT;
5278*0Sstevel@tonic-gate 		}
5279*0Sstevel@tonic-gate 		STRUCT_FSET(wrap_key, wk_wrapped_key_len, new_wrapped_key_len);
5280*0Sstevel@tonic-gate 	}
5281*0Sstevel@tonic-gate 
5282*0Sstevel@tonic-gate 	if (rv == CRYPTO_BUFFER_TOO_SMALL) {
5283*0Sstevel@tonic-gate 		/*
5284*0Sstevel@tonic-gate 		 * The providers return CRYPTO_BUFFER_TOO_SMALL even for case 1
5285*0Sstevel@tonic-gate 		 * of section 11.2 of the pkcs11 spec. We catch it here and
5286*0Sstevel@tonic-gate 		 * provide the correct pkcs11 return value.
5287*0Sstevel@tonic-gate 		 */
5288*0Sstevel@tonic-gate 		if (STRUCT_FGETP(wrap_key, wk_wrapped_key) == NULL)
5289*0Sstevel@tonic-gate 			rv = CRYPTO_SUCCESS;
5290*0Sstevel@tonic-gate 		STRUCT_FSET(wrap_key, wk_wrapped_key_len, new_wrapped_key_len);
5291*0Sstevel@tonic-gate 	}
5292*0Sstevel@tonic-gate out:
5293*0Sstevel@tonic-gate 	CRYPTO_SESSION_RELE(sp);
5294*0Sstevel@tonic-gate 
5295*0Sstevel@tonic-gate release_minor:
5296*0Sstevel@tonic-gate 	mutex_enter(&crypto_rctl_lock);
5297*0Sstevel@tonic-gate 	if (mech_rctl_bytes != 0)
5298*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(mech_rctl_bytes, mech_projp);
5299*0Sstevel@tonic-gate 	if (key_rctl_bytes != 0)
5300*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(key_rctl_bytes, key_projp);
5301*0Sstevel@tonic-gate 	if (wrapped_key_rctl_bytes != 0)
5302*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(wrapped_key_rctl_bytes,
5303*0Sstevel@tonic-gate 		    wrapped_key_projp);
5304*0Sstevel@tonic-gate 	mutex_exit(&crypto_rctl_lock);
5305*0Sstevel@tonic-gate 	crypto_release_minor(cm);
5306*0Sstevel@tonic-gate 
5307*0Sstevel@tonic-gate 	if (wrapped_key != NULL)
5308*0Sstevel@tonic-gate 		kmem_free(wrapped_key, wrapped_key_len);
5309*0Sstevel@tonic-gate 
5310*0Sstevel@tonic-gate 	free_crypto_key(&key);
5311*0Sstevel@tonic-gate 
5312*0Sstevel@tonic-gate 	if (error != 0)
5313*0Sstevel@tonic-gate 		return (error);
5314*0Sstevel@tonic-gate 
5315*0Sstevel@tonic-gate 	STRUCT_FSET(wrap_key, wk_return_value, rv);
5316*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(wrap_key), arg, STRUCT_SIZE(wrap_key)) != 0) {
5317*0Sstevel@tonic-gate 		return (EFAULT);
5318*0Sstevel@tonic-gate 	}
5319*0Sstevel@tonic-gate 	return (0);
5320*0Sstevel@tonic-gate }
5321*0Sstevel@tonic-gate 
5322*0Sstevel@tonic-gate /* ARGSUSED */
5323*0Sstevel@tonic-gate static int
5324*0Sstevel@tonic-gate object_unwrap_key(dev_t dev, caddr_t arg, int mode, int *rval)
5325*0Sstevel@tonic-gate {
5326*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_object_unwrap_key, unwrap_key);
5327*0Sstevel@tonic-gate 	kproject_t *mech_projp, *unwrapping_key_projp, *wrapped_key_projp,
5328*0Sstevel@tonic-gate 	    *k_attrs_projp;
5329*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
5330*0Sstevel@tonic-gate 	kcf_req_params_t params;
5331*0Sstevel@tonic-gate 	crypto_mechanism_t mech;
5332*0Sstevel@tonic-gate 	crypto_key_t unwrapping_key;
5333*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
5334*0Sstevel@tonic-gate 	crypto_minor_t *cm;
5335*0Sstevel@tonic-gate 	crypto_session_data_t *sp = NULL;
5336*0Sstevel@tonic-gate 	crypto_object_id_t handle;
5337*0Sstevel@tonic-gate 	crypto_object_attribute_t *k_attrs = NULL;
5338*0Sstevel@tonic-gate 	size_t k_attrs_size;
5339*0Sstevel@tonic-gate 	size_t mech_rctl_bytes = 0, unwrapping_key_rctl_bytes = 0;
5340*0Sstevel@tonic-gate 	size_t wrapped_key_rctl_bytes = 0, k_attrs_rctl_bytes = 0;
5341*0Sstevel@tonic-gate 	size_t carry;
5342*0Sstevel@tonic-gate 	size_t wrapped_key_len;
5343*0Sstevel@tonic-gate 	uchar_t *wrapped_key = NULL;
5344*0Sstevel@tonic-gate 	int error = 0;
5345*0Sstevel@tonic-gate 	int rv;
5346*0Sstevel@tonic-gate 	uint_t count;
5347*0Sstevel@tonic-gate 	caddr_t uk_attributes;
5348*0Sstevel@tonic-gate 
5349*0Sstevel@tonic-gate 	STRUCT_INIT(unwrap_key, mode);
5350*0Sstevel@tonic-gate 
5351*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5352*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "object_unwrap_key: failed holding minor");
5353*0Sstevel@tonic-gate 		return (ENXIO);
5354*0Sstevel@tonic-gate 	}
5355*0Sstevel@tonic-gate 
5356*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(unwrap_key), STRUCT_SIZE(unwrap_key)) != 0) {
5357*0Sstevel@tonic-gate 		crypto_release_minor(cm);
5358*0Sstevel@tonic-gate 		return (EFAULT);
5359*0Sstevel@tonic-gate 	}
5360*0Sstevel@tonic-gate 
5361*0Sstevel@tonic-gate 	bzero(&unwrapping_key, sizeof (unwrapping_key));
5362*0Sstevel@tonic-gate 
5363*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(unwrap_key, uk_session);
5364*0Sstevel@tonic-gate 
5365*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5366*0Sstevel@tonic-gate 		goto release_minor;
5367*0Sstevel@tonic-gate 	}
5368*0Sstevel@tonic-gate 
5369*0Sstevel@tonic-gate 	if (!copyin_mech(mode, STRUCT_FADDR(unwrap_key, uk_mechanism),
5370*0Sstevel@tonic-gate 		&mech, &mech_rctl_bytes, &carry, &rv, &error, &mech_projp)) {
5371*0Sstevel@tonic-gate 		goto release_minor;
5372*0Sstevel@tonic-gate 	}
5373*0Sstevel@tonic-gate 
5374*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider(mech.cm_type,
5375*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(key_ops),
5376*0Sstevel@tonic-gate 	    CRYPTO_KEY_OFFSET(key_unwrap), sp->sd_provider,
5377*0Sstevel@tonic-gate 	    &real_provider)) != CRYPTO_SUCCESS) {
5378*0Sstevel@tonic-gate 		goto release_minor;
5379*0Sstevel@tonic-gate 	}
5380*0Sstevel@tonic-gate 
5381*0Sstevel@tonic-gate 	if (!copyin_key(mode, STRUCT_FADDR(unwrap_key, uk_unwrapping_key),
5382*0Sstevel@tonic-gate 	    &unwrapping_key, &unwrapping_key_rctl_bytes, &rv, &error, carry,
5383*0Sstevel@tonic-gate 	    &unwrapping_key_projp)) {
5384*0Sstevel@tonic-gate 		goto release_minor;
5385*0Sstevel@tonic-gate 	}
5386*0Sstevel@tonic-gate 
5387*0Sstevel@tonic-gate 	count = STRUCT_FGET(unwrap_key, uk_count);
5388*0Sstevel@tonic-gate 	uk_attributes = STRUCT_FGETP(unwrap_key, uk_attributes);
5389*0Sstevel@tonic-gate 	if (!copyin_attributes(mode, count, uk_attributes, &k_attrs,
5390*0Sstevel@tonic-gate 	    &k_attrs_size, NULL, &rv, &error, &k_attrs_rctl_bytes, 0, B_TRUE,
5391*0Sstevel@tonic-gate 	    &k_attrs_projp)) {
5392*0Sstevel@tonic-gate 		goto release_minor;
5393*0Sstevel@tonic-gate 	}
5394*0Sstevel@tonic-gate 
5395*0Sstevel@tonic-gate 	wrapped_key_len = STRUCT_FGET(unwrap_key, uk_wrapped_key_len);
5396*0Sstevel@tonic-gate 	if (wrapped_key_len > crypto_max_buffer_len) {
5397*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "object_unwrap_key: buffer greater than %ld "
5398*0Sstevel@tonic-gate 		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
5399*0Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
5400*0Sstevel@tonic-gate 		goto release_minor;
5401*0Sstevel@tonic-gate 	}
5402*0Sstevel@tonic-gate 
5403*0Sstevel@tonic-gate 	if ((rv = crypto_buffer_check(wrapped_key_len, &wrapped_key_projp))
5404*0Sstevel@tonic-gate 	    != CRYPTO_SUCCESS) {
5405*0Sstevel@tonic-gate 		goto release_minor;
5406*0Sstevel@tonic-gate 	}
5407*0Sstevel@tonic-gate 	wrapped_key_rctl_bytes = wrapped_key_len;
5408*0Sstevel@tonic-gate 	wrapped_key = kmem_alloc(wrapped_key_len, KM_SLEEP);
5409*0Sstevel@tonic-gate 
5410*0Sstevel@tonic-gate 	if (wrapped_key_len != 0 && copyin(STRUCT_FGETP(unwrap_key,
5411*0Sstevel@tonic-gate 	    uk_wrapped_key), wrapped_key, wrapped_key_len) != 0) {
5412*0Sstevel@tonic-gate 		error = EFAULT;
5413*0Sstevel@tonic-gate 		goto release_minor;
5414*0Sstevel@tonic-gate 	}
5415*0Sstevel@tonic-gate 
5416*0Sstevel@tonic-gate 	/* wrapped_key_len is not modified by the unwrap operation */
5417*0Sstevel@tonic-gate 	KCF_WRAP_KEY_OPS_PARAMS(&params, KCF_OP_KEY_UNWRAP,
5418*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, &mech, k_attrs, count, &handle,
5419*0Sstevel@tonic-gate 	    NULL, 0, NULL, &unwrapping_key, wrapped_key, &wrapped_key_len);
5420*0Sstevel@tonic-gate 
5421*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5422*0Sstevel@tonic-gate 
5423*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS)
5424*0Sstevel@tonic-gate 		STRUCT_FSET(unwrap_key, uk_object_handle, handle);
5425*0Sstevel@tonic-gate 
5426*0Sstevel@tonic-gate release_minor:
5427*0Sstevel@tonic-gate 	mutex_enter(&crypto_rctl_lock);
5428*0Sstevel@tonic-gate 	if (mech_rctl_bytes != 0)
5429*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(mech_rctl_bytes, mech_projp);
5430*0Sstevel@tonic-gate 	if (unwrapping_key_rctl_bytes != 0)
5431*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(unwrapping_key_rctl_bytes,
5432*0Sstevel@tonic-gate 		    unwrapping_key_projp);
5433*0Sstevel@tonic-gate 	if (wrapped_key_rctl_bytes != 0)
5434*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(wrapped_key_rctl_bytes,
5435*0Sstevel@tonic-gate 		    wrapped_key_projp);
5436*0Sstevel@tonic-gate 	if (k_attrs_rctl_bytes != 0)
5437*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(k_attrs_rctl_bytes, k_attrs_projp);
5438*0Sstevel@tonic-gate 	mutex_exit(&crypto_rctl_lock);
5439*0Sstevel@tonic-gate 
5440*0Sstevel@tonic-gate 	if (k_attrs != NULL)
5441*0Sstevel@tonic-gate 		kmem_free(k_attrs, k_attrs_size);
5442*0Sstevel@tonic-gate 
5443*0Sstevel@tonic-gate 	if (wrapped_key != NULL)
5444*0Sstevel@tonic-gate 		kmem_free(wrapped_key, wrapped_key_len);
5445*0Sstevel@tonic-gate 
5446*0Sstevel@tonic-gate 	free_crypto_key(&unwrapping_key);
5447*0Sstevel@tonic-gate 
5448*0Sstevel@tonic-gate 	if (error != 0)
5449*0Sstevel@tonic-gate 		goto out;
5450*0Sstevel@tonic-gate 
5451*0Sstevel@tonic-gate 	STRUCT_FSET(unwrap_key, uk_return_value, rv);
5452*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(unwrap_key), arg,
5453*0Sstevel@tonic-gate 	    STRUCT_SIZE(unwrap_key)) != 0) {
5454*0Sstevel@tonic-gate 		if (rv == CRYPTO_SUCCESS) {
5455*0Sstevel@tonic-gate 			KCF_WRAP_OBJECT_OPS_PARAMS(&params,
5456*0Sstevel@tonic-gate 			    KCF_OP_OBJECT_DESTROY,
5457*0Sstevel@tonic-gate 			    sp->sd_provider_session->ps_session, handle,
5458*0Sstevel@tonic-gate 			    NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
5459*0Sstevel@tonic-gate 
5460*0Sstevel@tonic-gate 			(void) kcf_submit_request(real_provider, NULL,
5461*0Sstevel@tonic-gate 			    NULL, &params, B_FALSE);
5462*0Sstevel@tonic-gate 
5463*0Sstevel@tonic-gate 			error = EFAULT;
5464*0Sstevel@tonic-gate 		}
5465*0Sstevel@tonic-gate 	}
5466*0Sstevel@tonic-gate out:
5467*0Sstevel@tonic-gate 	if (sp != NULL)
5468*0Sstevel@tonic-gate 		CRYPTO_SESSION_RELE(sp);
5469*0Sstevel@tonic-gate 	crypto_release_minor(cm);
5470*0Sstevel@tonic-gate 	return (error);
5471*0Sstevel@tonic-gate }
5472*0Sstevel@tonic-gate 
5473*0Sstevel@tonic-gate /* ARGSUSED */
5474*0Sstevel@tonic-gate static int
5475*0Sstevel@tonic-gate object_derive_key(dev_t dev, caddr_t arg, int mode, int *rval)
5476*0Sstevel@tonic-gate {
5477*0Sstevel@tonic-gate 	STRUCT_DECL(crypto_derive_key, derive_key);
5478*0Sstevel@tonic-gate 	kproject_t *key_projp, *mech_projp, *attributes_projp;
5479*0Sstevel@tonic-gate 	kcf_provider_desc_t *real_provider;
5480*0Sstevel@tonic-gate 	kcf_req_params_t params;
5481*0Sstevel@tonic-gate 	crypto_object_attribute_t *k_attrs = NULL;
5482*0Sstevel@tonic-gate 	crypto_mechanism_t mech;
5483*0Sstevel@tonic-gate 	crypto_key_t base_key;
5484*0Sstevel@tonic-gate 	crypto_session_id_t session_id;
5485*0Sstevel@tonic-gate 	crypto_minor_t *cm;
5486*0Sstevel@tonic-gate 	crypto_session_data_t *sp = NULL;
5487*0Sstevel@tonic-gate 	crypto_object_id_t handle;
5488*0Sstevel@tonic-gate 	size_t k_attrs_size;
5489*0Sstevel@tonic-gate 	size_t key_rctl_bytes = 0, mech_rctl_bytes = 0;
5490*0Sstevel@tonic-gate 	size_t attributes_rctl_bytes = 0;
5491*0Sstevel@tonic-gate 	size_t carry;
5492*0Sstevel@tonic-gate 	caddr_t attributes;
5493*0Sstevel@tonic-gate 	uint_t count;
5494*0Sstevel@tonic-gate 	int error = 0;
5495*0Sstevel@tonic-gate 	int rv;
5496*0Sstevel@tonic-gate 
5497*0Sstevel@tonic-gate 	STRUCT_INIT(derive_key, mode);
5498*0Sstevel@tonic-gate 
5499*0Sstevel@tonic-gate 	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5500*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "object_derive_key: failed holding minor");
5501*0Sstevel@tonic-gate 		return (ENXIO);
5502*0Sstevel@tonic-gate 	}
5503*0Sstevel@tonic-gate 
5504*0Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(derive_key), STRUCT_SIZE(derive_key)) != 0) {
5505*0Sstevel@tonic-gate 		crypto_release_minor(cm);
5506*0Sstevel@tonic-gate 		return (EFAULT);
5507*0Sstevel@tonic-gate 	}
5508*0Sstevel@tonic-gate 
5509*0Sstevel@tonic-gate 	bzero(&base_key, sizeof (base_key));
5510*0Sstevel@tonic-gate 
5511*0Sstevel@tonic-gate 	session_id = STRUCT_FGET(derive_key, dk_session);
5512*0Sstevel@tonic-gate 
5513*0Sstevel@tonic-gate 	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5514*0Sstevel@tonic-gate 		goto release_minor;
5515*0Sstevel@tonic-gate 	}
5516*0Sstevel@tonic-gate 
5517*0Sstevel@tonic-gate 	if (!copyin_mech(mode, STRUCT_FADDR(derive_key, dk_mechanism),
5518*0Sstevel@tonic-gate 	    &mech, &mech_rctl_bytes, &carry, &rv, &error, &mech_projp)) {
5519*0Sstevel@tonic-gate 		goto release_minor;
5520*0Sstevel@tonic-gate 	}
5521*0Sstevel@tonic-gate 
5522*0Sstevel@tonic-gate 	if ((rv = kcf_get_hardware_provider(mech.cm_type,
5523*0Sstevel@tonic-gate 	    CRYPTO_OPS_OFFSET(key_ops),
5524*0Sstevel@tonic-gate 	    CRYPTO_KEY_OFFSET(key_derive), sp->sd_provider,
5525*0Sstevel@tonic-gate 	    &real_provider)) != CRYPTO_SUCCESS) {
5526*0Sstevel@tonic-gate 		goto release_minor;
5527*0Sstevel@tonic-gate 	}
5528*0Sstevel@tonic-gate 
5529*0Sstevel@tonic-gate 	if (!copyin_key(mode, STRUCT_FADDR(derive_key, dk_base_key),
5530*0Sstevel@tonic-gate 	    &base_key, &key_rctl_bytes, &rv, &error, carry, &key_projp)) {
5531*0Sstevel@tonic-gate 		goto release_minor;
5532*0Sstevel@tonic-gate 	}
5533*0Sstevel@tonic-gate 
5534*0Sstevel@tonic-gate 	count = STRUCT_FGET(derive_key, dk_count);
5535*0Sstevel@tonic-gate 
5536*0Sstevel@tonic-gate 	attributes = STRUCT_FGETP(derive_key, dk_attributes);
5537*0Sstevel@tonic-gate 	if (!copyin_attributes(mode, count, attributes, &k_attrs,
5538*0Sstevel@tonic-gate 	    &k_attrs_size, NULL, &rv, &error, &attributes_rctl_bytes, 0, B_TRUE,
5539*0Sstevel@tonic-gate 	    &attributes_projp)) {
5540*0Sstevel@tonic-gate 		goto release_minor;
5541*0Sstevel@tonic-gate 	}
5542*0Sstevel@tonic-gate 
5543*0Sstevel@tonic-gate 	KCF_WRAP_KEY_OPS_PARAMS(&params, KCF_OP_KEY_DERIVE,
5544*0Sstevel@tonic-gate 	    sp->sd_provider_session->ps_session, &mech, k_attrs, count,
5545*0Sstevel@tonic-gate 	    &handle, NULL, 0, NULL, &base_key, NULL, NULL);
5546*0Sstevel@tonic-gate 
5547*0Sstevel@tonic-gate 	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5548*0Sstevel@tonic-gate 
5549*0Sstevel@tonic-gate 	if (rv == CRYPTO_SUCCESS)
5550*0Sstevel@tonic-gate 		STRUCT_FSET(derive_key, dk_object_handle, handle);
5551*0Sstevel@tonic-gate 
5552*0Sstevel@tonic-gate release_minor:
5553*0Sstevel@tonic-gate 	mutex_enter(&crypto_rctl_lock);
5554*0Sstevel@tonic-gate 	if (mech_rctl_bytes != 0)
5555*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(mech_rctl_bytes, mech_projp);
5556*0Sstevel@tonic-gate 	if (key_rctl_bytes != 0)
5557*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(key_rctl_bytes, key_projp);
5558*0Sstevel@tonic-gate 	if (attributes_rctl_bytes != 0)
5559*0Sstevel@tonic-gate 		CRYPTO_DECREMENT_RCTL(attributes_rctl_bytes, attributes_projp);
5560*0Sstevel@tonic-gate 	mutex_exit(&crypto_rctl_lock);
5561*0Sstevel@tonic-gate 
5562*0Sstevel@tonic-gate 	if (k_attrs != NULL)
5563*0Sstevel@tonic-gate 		kmem_free(k_attrs, k_attrs_size);
5564*0Sstevel@tonic-gate 
5565*0Sstevel@tonic-gate 	free_crypto_key(&base_key);
5566*0Sstevel@tonic-gate 
5567*0Sstevel@tonic-gate 	if (error != 0)
5568*0Sstevel@tonic-gate 		goto out;
5569*0Sstevel@tonic-gate 
5570*0Sstevel@tonic-gate 	STRUCT_FSET(derive_key, dk_return_value, rv);
5571*0Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(derive_key), arg,
5572*0Sstevel@tonic-gate 	    STRUCT_SIZE(derive_key)) != 0) {
5573*0Sstevel@tonic-gate 		if (rv == CRYPTO_SUCCESS) {
5574*0Sstevel@tonic-gate 			KCF_WRAP_OBJECT_OPS_PARAMS(&params,
5575*0Sstevel@tonic-gate 			    KCF_OP_OBJECT_DESTROY,
5576*0Sstevel@tonic-gate 			    sp->sd_provider_session->ps_session, handle,
5577*0Sstevel@tonic-gate 			    NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
5578*0Sstevel@tonic-gate 
5579*0Sstevel@tonic-gate 			(void) kcf_submit_request(real_provider, NULL,
5580*0Sstevel@tonic-gate 			    NULL, &params, B_FALSE);
5581*0Sstevel@tonic-gate 
5582*0Sstevel@tonic-gate 			error = EFAULT;
5583*0Sstevel@tonic-gate 		}
5584*0Sstevel@tonic-gate 	}
5585*0Sstevel@tonic-gate out:
5586*0Sstevel@tonic-gate 	if (sp != NULL)
5587*0Sstevel@tonic-gate 		CRYPTO_SESSION_RELE(sp);
5588*0Sstevel@tonic-gate 	crypto_release_minor(cm);
5589*0Sstevel@tonic-gate 	return (error);
5590*0Sstevel@tonic-gate }
5591*0Sstevel@tonic-gate 
5592*0Sstevel@tonic-gate /* ARGSUSED */
5593*0Sstevel@tonic-gate static int
5594*0Sstevel@tonic-gate crypto_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *c,
5595*0Sstevel@tonic-gate     int *rval)
5596*0Sstevel@tonic-gate {
5597*0Sstevel@tonic-gate #define	ARG	((caddr_t)arg)
5598*0Sstevel@tonic-gate 
5599*0Sstevel@tonic-gate 	switch (cmd) {
5600*0Sstevel@tonic-gate 	case CRYPTO_GET_FUNCTION_LIST:
5601*0Sstevel@tonic-gate 		return (get_function_list(dev, ARG, mode, rval));
5602*0Sstevel@tonic-gate 
5603*0Sstevel@tonic-gate 	case CRYPTO_GET_MECHANISM_NUMBER:
5604*0Sstevel@tonic-gate 		return (get_mechanism_number(dev, ARG, mode, rval));
5605*0Sstevel@tonic-gate 
5606*0Sstevel@tonic-gate 	case CRYPTO_GET_PROVIDER_LIST:
5607*0Sstevel@tonic-gate 		return (get_provider_list(dev, ARG, mode, rval));
5608*0Sstevel@tonic-gate 
5609*0Sstevel@tonic-gate 	case CRYPTO_GET_PROVIDER_INFO:
5610*0Sstevel@tonic-gate 		return (get_provider_info(dev, ARG, mode, rval));
5611*0Sstevel@tonic-gate 
5612*0Sstevel@tonic-gate 	case CRYPTO_GET_PROVIDER_MECHANISMS:
5613*0Sstevel@tonic-gate 		return (get_provider_mechanisms(dev, ARG, mode, rval));
5614*0Sstevel@tonic-gate 
5615*0Sstevel@tonic-gate 	case CRYPTO_GET_PROVIDER_MECHANISM_INFO:
5616*0Sstevel@tonic-gate 		return (get_provider_mechanism_info(dev, ARG, mode, rval));
5617*0Sstevel@tonic-gate 
5618*0Sstevel@tonic-gate 	case CRYPTO_OPEN_SESSION:
5619*0Sstevel@tonic-gate 		return (open_session(dev, ARG, mode, rval));
5620*0Sstevel@tonic-gate 
5621*0Sstevel@tonic-gate 	case CRYPTO_CLOSE_SESSION:
5622*0Sstevel@tonic-gate 		return (close_session(dev, ARG, mode, rval));
5623*0Sstevel@tonic-gate 
5624*0Sstevel@tonic-gate 	case CRYPTO_ENCRYPT_INIT:
5625*0Sstevel@tonic-gate 		return (encrypt_init(dev, ARG, mode, rval));
5626*0Sstevel@tonic-gate 
5627*0Sstevel@tonic-gate 	case CRYPTO_DECRYPT_INIT:
5628*0Sstevel@tonic-gate 		return (decrypt_init(dev, ARG, mode, rval));
5629*0Sstevel@tonic-gate 
5630*0Sstevel@tonic-gate 	case CRYPTO_ENCRYPT:
5631*0Sstevel@tonic-gate 		return (encrypt(dev, ARG, mode, rval));
5632*0Sstevel@tonic-gate 
5633*0Sstevel@tonic-gate 	case CRYPTO_DECRYPT:
5634*0Sstevel@tonic-gate 		return (decrypt(dev, ARG, mode, rval));
5635*0Sstevel@tonic-gate 
5636*0Sstevel@tonic-gate 	case CRYPTO_ENCRYPT_UPDATE:
5637*0Sstevel@tonic-gate 		return (encrypt_update(dev, ARG, mode, rval));
5638*0Sstevel@tonic-gate 
5639*0Sstevel@tonic-gate 	case CRYPTO_DECRYPT_UPDATE:
5640*0Sstevel@tonic-gate 		return (decrypt_update(dev, ARG, mode, rval));
5641*0Sstevel@tonic-gate 
5642*0Sstevel@tonic-gate 	case CRYPTO_ENCRYPT_FINAL:
5643*0Sstevel@tonic-gate 		return (encrypt_final(dev, ARG, mode, rval));
5644*0Sstevel@tonic-gate 
5645*0Sstevel@tonic-gate 	case CRYPTO_DECRYPT_FINAL:
5646*0Sstevel@tonic-gate 		return (decrypt_final(dev, ARG, mode, rval));
5647*0Sstevel@tonic-gate 
5648*0Sstevel@tonic-gate 	case CRYPTO_DIGEST_INIT:
5649*0Sstevel@tonic-gate 		return (digest_init(dev, ARG, mode, rval));
5650*0Sstevel@tonic-gate 
5651*0Sstevel@tonic-gate 	case CRYPTO_DIGEST:
5652*0Sstevel@tonic-gate 		return (digest(dev, ARG, mode, rval));
5653*0Sstevel@tonic-gate 
5654*0Sstevel@tonic-gate 	case CRYPTO_DIGEST_UPDATE:
5655*0Sstevel@tonic-gate 		return (digest_update(dev, ARG, mode, rval));
5656*0Sstevel@tonic-gate 
5657*0Sstevel@tonic-gate 	case CRYPTO_DIGEST_KEY:
5658*0Sstevel@tonic-gate 		return (digest_key(dev, ARG, mode, rval));
5659*0Sstevel@tonic-gate 
5660*0Sstevel@tonic-gate 	case CRYPTO_DIGEST_FINAL:
5661*0Sstevel@tonic-gate 		return (digest_final(dev, ARG, mode, rval));
5662*0Sstevel@tonic-gate 
5663*0Sstevel@tonic-gate 	case CRYPTO_SIGN_INIT:
5664*0Sstevel@tonic-gate 		return (sign_init(dev, ARG, mode, rval));
5665*0Sstevel@tonic-gate 
5666*0Sstevel@tonic-gate 	case CRYPTO_SIGN:
5667*0Sstevel@tonic-gate 		return (sign(dev, ARG, mode, rval));
5668*0Sstevel@tonic-gate 
5669*0Sstevel@tonic-gate 	case CRYPTO_SIGN_UPDATE:
5670*0Sstevel@tonic-gate 		return (sign_update(dev, ARG, mode, rval));
5671*0Sstevel@tonic-gate 
5672*0Sstevel@tonic-gate 	case CRYPTO_SIGN_FINAL:
5673*0Sstevel@tonic-gate 		return (sign_final(dev, ARG, mode, rval));
5674*0Sstevel@tonic-gate 
5675*0Sstevel@tonic-gate 	case CRYPTO_SIGN_RECOVER_INIT:
5676*0Sstevel@tonic-gate 		return (sign_recover_init(dev, ARG, mode, rval));
5677*0Sstevel@tonic-gate 
5678*0Sstevel@tonic-gate 	case CRYPTO_SIGN_RECOVER:
5679*0Sstevel@tonic-gate 		return (sign_recover(dev, ARG, mode, rval));
5680*0Sstevel@tonic-gate 
5681*0Sstevel@tonic-gate 	case CRYPTO_VERIFY_INIT:
5682*0Sstevel@tonic-gate 		return (verify_init(dev, ARG, mode, rval));
5683*0Sstevel@tonic-gate 
5684*0Sstevel@tonic-gate 	case CRYPTO_VERIFY:
5685*0Sstevel@tonic-gate 		return (verify(dev, ARG, mode, rval));
5686*0Sstevel@tonic-gate 
5687*0Sstevel@tonic-gate 	case CRYPTO_VERIFY_UPDATE:
5688*0Sstevel@tonic-gate 		return (verify_update(dev, ARG, mode, rval));
5689*0Sstevel@tonic-gate 
5690*0Sstevel@tonic-gate 	case CRYPTO_VERIFY_FINAL:
5691*0Sstevel@tonic-gate 		return (verify_final(dev, ARG, mode, rval));
5692*0Sstevel@tonic-gate 
5693*0Sstevel@tonic-gate 	case CRYPTO_VERIFY_RECOVER_INIT:
5694*0Sstevel@tonic-gate 		return (verify_recover_init(dev, ARG, mode, rval));
5695*0Sstevel@tonic-gate 
5696*0Sstevel@tonic-gate 	case CRYPTO_VERIFY_RECOVER:
5697*0Sstevel@tonic-gate 		return (verify_recover(dev, ARG, mode, rval));
5698*0Sstevel@tonic-gate 
5699*0Sstevel@tonic-gate 	case CRYPTO_SET_PIN:
5700*0Sstevel@tonic-gate 		return (set_pin(dev, ARG, mode, rval));
5701*0Sstevel@tonic-gate 
5702*0Sstevel@tonic-gate 	case CRYPTO_LOGIN:
5703*0Sstevel@tonic-gate 		return (login(dev, ARG, mode, rval));
5704*0Sstevel@tonic-gate 
5705*0Sstevel@tonic-gate 	case CRYPTO_LOGOUT:
5706*0Sstevel@tonic-gate 		return (logout(dev, ARG, mode, rval));
5707*0Sstevel@tonic-gate 
5708*0Sstevel@tonic-gate 	case CRYPTO_SEED_RANDOM:
5709*0Sstevel@tonic-gate 		return (seed_random(dev, ARG, mode, rval));
5710*0Sstevel@tonic-gate 
5711*0Sstevel@tonic-gate 	case CRYPTO_GENERATE_RANDOM:
5712*0Sstevel@tonic-gate 		return (generate_random(dev, ARG, mode, rval));
5713*0Sstevel@tonic-gate 
5714*0Sstevel@tonic-gate 	case CRYPTO_OBJECT_CREATE:
5715*0Sstevel@tonic-gate 		return (object_create(dev, ARG, mode, rval));
5716*0Sstevel@tonic-gate 
5717*0Sstevel@tonic-gate 	case CRYPTO_OBJECT_COPY:
5718*0Sstevel@tonic-gate 		return (object_copy(dev, ARG, mode, rval));
5719*0Sstevel@tonic-gate 
5720*0Sstevel@tonic-gate 	case CRYPTO_OBJECT_DESTROY:
5721*0Sstevel@tonic-gate 		return (object_destroy(dev, ARG, mode, rval));
5722*0Sstevel@tonic-gate 
5723*0Sstevel@tonic-gate 	case CRYPTO_OBJECT_GET_ATTRIBUTE_VALUE:
5724*0Sstevel@tonic-gate 		return (object_get_attribute_value(dev, ARG, mode, rval));
5725*0Sstevel@tonic-gate 
5726*0Sstevel@tonic-gate 	case CRYPTO_OBJECT_GET_SIZE:
5727*0Sstevel@tonic-gate 		return (object_get_size(dev, ARG, mode, rval));
5728*0Sstevel@tonic-gate 
5729*0Sstevel@tonic-gate 	case CRYPTO_OBJECT_SET_ATTRIBUTE_VALUE:
5730*0Sstevel@tonic-gate 		return (object_set_attribute_value(dev, ARG, mode, rval));
5731*0Sstevel@tonic-gate 
5732*0Sstevel@tonic-gate 	case CRYPTO_OBJECT_FIND_INIT:
5733*0Sstevel@tonic-gate 		return (object_find_init(dev, ARG, mode, rval));
5734*0Sstevel@tonic-gate 
5735*0Sstevel@tonic-gate 	case CRYPTO_OBJECT_FIND_UPDATE:
5736*0Sstevel@tonic-gate 		return (object_find_update(dev, ARG, mode, rval));
5737*0Sstevel@tonic-gate 
5738*0Sstevel@tonic-gate 	case CRYPTO_OBJECT_FIND_FINAL:
5739*0Sstevel@tonic-gate 		return (object_find_final(dev, ARG, mode, rval));
5740*0Sstevel@tonic-gate 
5741*0Sstevel@tonic-gate 	case CRYPTO_GENERATE_KEY:
5742*0Sstevel@tonic-gate 		return (object_generate_key(dev, ARG, mode, rval));
5743*0Sstevel@tonic-gate 
5744*0Sstevel@tonic-gate 	case CRYPTO_GENERATE_KEY_PAIR:
5745*0Sstevel@tonic-gate 		return (object_generate_key_pair(dev, ARG, mode, rval));
5746*0Sstevel@tonic-gate 
5747*0Sstevel@tonic-gate 	case CRYPTO_WRAP_KEY:
5748*0Sstevel@tonic-gate 		return (object_wrap_key(dev, ARG, mode, rval));
5749*0Sstevel@tonic-gate 
5750*0Sstevel@tonic-gate 	case CRYPTO_UNWRAP_KEY:
5751*0Sstevel@tonic-gate 		return (object_unwrap_key(dev, ARG, mode, rval));
5752*0Sstevel@tonic-gate 
5753*0Sstevel@tonic-gate 	case CRYPTO_DERIVE_KEY:
5754*0Sstevel@tonic-gate 		return (object_derive_key(dev, ARG, mode, rval));
5755*0Sstevel@tonic-gate 	}
5756*0Sstevel@tonic-gate 	return (EINVAL);
5757*0Sstevel@tonic-gate }
5758*0Sstevel@tonic-gate 
5759*0Sstevel@tonic-gate /*
5760*0Sstevel@tonic-gate  * Check for the project.max-crypto-memory resource control.
5761*0Sstevel@tonic-gate  */
5762*0Sstevel@tonic-gate static int
5763*0Sstevel@tonic-gate crypto_buffer_check(size_t need, kproject_t **projp)
5764*0Sstevel@tonic-gate {
5765*0Sstevel@tonic-gate 	ASSERT(projp != NULL);
5766*0Sstevel@tonic-gate 
5767*0Sstevel@tonic-gate 	if (need == 0)
5768*0Sstevel@tonic-gate 		return (CRYPTO_SUCCESS);
5769*0Sstevel@tonic-gate 
5770*0Sstevel@tonic-gate 	mutex_enter(&curproc->p_lock);
5771*0Sstevel@tonic-gate 	mutex_enter(&crypto_rctl_lock);
5772*0Sstevel@tonic-gate 	if (rctl_test(rc_project_crypto_mem,
5773*0Sstevel@tonic-gate 	    curproc->p_task->tk_proj->kpj_rctls, curproc, need, 0) & RCT_DENY) {
5774*0Sstevel@tonic-gate 		mutex_exit(&crypto_rctl_lock);
5775*0Sstevel@tonic-gate 		mutex_exit(&curproc->p_lock);
5776*0Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
5777*0Sstevel@tonic-gate 	}
5778*0Sstevel@tonic-gate 
5779*0Sstevel@tonic-gate 	curproc->p_task->tk_proj->kpj_data.kpd_crypto_mem += need;
5780*0Sstevel@tonic-gate 	mutex_exit(&crypto_rctl_lock);
5781*0Sstevel@tonic-gate 
5782*0Sstevel@tonic-gate 	(void) project_hold(curproc->p_task->tk_proj);
5783*0Sstevel@tonic-gate 	*projp = curproc->p_task->tk_proj;
5784*0Sstevel@tonic-gate 	mutex_exit(&curproc->p_lock);
5785*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
5786*0Sstevel@tonic-gate }
5787