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