crypto.c revision 10028:2de34ea54ad5
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
54extern int kcf_des3_threshold;
55extern int kcf_aes_threshold;
56extern int kcf_rc4_threshold;
57extern int kcf_md5_threshold;
58extern 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 */
79static int crypto_attach(dev_info_t *, ddi_attach_cmd_t);
80static int crypto_detach(dev_info_t *, ddi_detach_cmd_t);
81static int crypto_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
82static int crypto_open(dev_t *, int, int, cred_t *);
83static int crypto_close(dev_t, int, int, cred_t *);
84static int crypto_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
85
86static 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
90static int common_digest(dev_t, caddr_t, int, int (*)(crypto_context_t,
91    crypto_data_t *, crypto_data_t *, crypto_call_req_t *));
92
93static int cipher(dev_t, caddr_t, int, int (*)(crypto_context_t,
94    crypto_data_t *, crypto_data_t *, crypto_call_req_t *));
95
96static int cipher_update(dev_t, caddr_t, int, int (*)(crypto_context_t,
97    crypto_data_t *, crypto_data_t *, crypto_call_req_t *));
98
99static int common_final(dev_t, caddr_t, int, int (*)(crypto_context_t,
100    crypto_data_t *, crypto_call_req_t *));
101
102static 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
106static 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
109static void crypto_initialize_rctl(void);
110static void crypto_release_provider_session(crypto_minor_t *,
111    crypto_provider_session_t *);
112static int crypto_buffer_check(size_t);
113static int crypto_free_find_ctx(crypto_session_data_t *);
114static 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
150size_t crypto_max_buffer_len = CRYPTO_MAX_BUFFER_LEN;
151size_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
160static struct kmem_cache *crypto_session_cache;
161static crypto_minor_t **crypto_minors = NULL;
162static dev_info_t *crypto_dip = NULL;
163static minor_t crypto_minor_chunk = CRYPTO_MINOR_CHUNK;
164static 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 */
170static vmem_t *crypto_arena = NULL;	/* Arena for device minors */
171static minor_t crypto_minors_count = 0;
172static 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 */
264static 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
285static 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
300static struct modldrv modldrv = {
301	&mod_driverops,					/* drv_modops */
302	"Cryptographic Library Interface",	/* drv_linkinfo */
303	&devops,
304};
305
306static struct modlinkage modlinkage = {
307	MODREV_1,		/* ml_rev */
308	&modldrv,		/* ml_linkage */
309	NULL
310};
311
312/*
313 * DDI entry points.
314 */
315int
316_init(void)
317{
318	return (mod_install(&modlinkage));
319}
320
321int
322_fini(void)
323{
324	return (mod_remove(&modlinkage));
325}
326
327int
328_info(struct modinfo *modinfop)
329{
330	return (mod_info(&modlinkage, modinfop));
331}
332
333/* ARGSUSED */
334static int
335crypto_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
349static int
350crypto_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
394static int
395crypto_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 */
437static int
438crypto_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
455again:
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 */
531static int
532crypto_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
619static crypto_minor_t *
620crypto_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
638static void
639crypto_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 */
649static void
650crypto_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 */
835static int
836get_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
896release_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 */
913static int
914get_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;
955out:
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 */
970static int
971get_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
1022out:
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 */
1031static int
1032copyout_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 */
1068static int
1069get_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
1118out1:
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));
1145out2:
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 */
1159int
1160crypto_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 */
1214static int
1215get_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
1308static void
1309ext_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	STRUCT_FSET(version, cv_major, ei->ei_firmware_version.cv_major);
1349	STRUCT_FSET(version, cv_minor, ei->ei_firmware_version.cv_minor);
1350	bcopy(STRUCT_BUF(version), STRUCT_FADDR(pd, pd_firmware_version),
1351	    STRUCT_SIZE(version));
1352	bcopy(ei->ei_time, STRUCT_FGET(pd, pd_time), CRYPTO_EXT_SIZE_TIME);
1353	bcopy(STRUCT_BUF(pd), out, STRUCT_SIZE(pd));
1354}
1355
1356/*
1357 * Utility routine to construct a crypto_provider_ext_info structure. Some
1358 * of the fields are constructed from information in the provider structure.
1359 * The rest of the fields have default values. We need to do this for
1360 * providers which do not support crypto_provider_management_ops routines.
1361 */
1362static void
1363fabricate_ext_info(kcf_provider_desc_t *provider,
1364    crypto_provider_ext_info_t *ei)
1365{
1366	/* empty label */
1367	(void) memset(ei->ei_label, ' ', CRYPTO_EXT_SIZE_LABEL);
1368
1369	(void) memset(ei->ei_manufacturerID, ' ', CRYPTO_EXT_SIZE_MANUF);
1370	(void) strncpy((char *)ei->ei_manufacturerID, "Unknown", 7);
1371
1372	(void) memset(ei->ei_model, ' ', CRYPTO_EXT_SIZE_MODEL);
1373	(void) strncpy((char *)ei->ei_model, "Unknown", 7);
1374
1375	(void) memset(ei->ei_serial_number, ' ', CRYPTO_EXT_SIZE_SERIAL);
1376	(void) strncpy((char *)ei->ei_serial_number, "Unknown", 7);
1377
1378	if (KCF_PROV_RANDOM_OPS(provider) != NULL)
1379		ei->ei_flags |= CRYPTO_EXTF_RNG;
1380	if (KCF_PROV_DUAL_OPS(provider) != NULL)
1381		ei->ei_flags |= CRYPTO_EXTF_DUAL_CRYPTO_OPERATIONS;
1382
1383	ei->ei_max_session_count = CRYPTO_UNAVAILABLE_INFO;
1384	ei->ei_max_pin_len = 0;
1385	ei->ei_min_pin_len = 0;
1386	ei->ei_total_public_memory = CRYPTO_UNAVAILABLE_INFO;
1387	ei->ei_free_public_memory = CRYPTO_UNAVAILABLE_INFO;
1388	ei->ei_total_private_memory = CRYPTO_UNAVAILABLE_INFO;
1389	ei->ei_free_private_memory = CRYPTO_UNAVAILABLE_INFO;
1390	ei->ei_hardware_version.cv_major = 1;
1391	ei->ei_hardware_version.cv_minor = 0;
1392	ei->ei_firmware_version.cv_major = 1;
1393	ei->ei_firmware_version.cv_minor = 0;
1394}
1395
1396/* ARGSUSED */
1397static int
1398get_provider_info(dev_t dev, caddr_t arg, int mode, int *rval)
1399{
1400	STRUCT_DECL(crypto_get_provider_info, get_info);
1401	crypto_minor_t *cm;
1402	crypto_provider_id_t provider_id;
1403	kcf_provider_desc_t *provider, *real_provider;
1404	crypto_provider_ext_info_t *ext_info = NULL;
1405	size_t need;
1406	int error = 0;
1407	int rv;
1408	kcf_req_params_t params;
1409
1410	STRUCT_INIT(get_info, mode);
1411
1412	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
1413		cmn_err(CE_WARN, "get_provider_info: failed holding minor");
1414		return (ENXIO);
1415	}
1416
1417	if (copyin(arg, STRUCT_BUF(get_info), STRUCT_SIZE(get_info)) != 0) {
1418		crypto_release_minor(cm);
1419		return (EFAULT);
1420	}
1421
1422	need = sizeof (crypto_provider_ext_info_t);
1423	if ((rv = crypto_buffer_check(need)) != CRYPTO_SUCCESS) {
1424		need = 0;
1425		goto release_minor;
1426	}
1427
1428	/* initialize provider_array */
1429	if (cm->cm_provider_array == NULL) {
1430		rv = crypto_get_provider_list(cm, NULL, NULL, DONT_RETURN_LIST);
1431		if (rv != CRYPTO_SUCCESS) {
1432			goto release_minor;
1433		}
1434	}
1435
1436	ext_info = kmem_zalloc(need, KM_SLEEP);
1437
1438	provider_id = STRUCT_FGET(get_info, gi_provider_id);
1439	mutex_enter(&cm->cm_lock);
1440	/* index must be less than count of providers */
1441	if (provider_id >= cm->cm_provider_count) {
1442		mutex_exit(&cm->cm_lock);
1443		rv = CRYPTO_ARGUMENTS_BAD;
1444		goto release_minor;
1445	}
1446
1447	ASSERT(cm->cm_provider_array != NULL);
1448	provider = cm->cm_provider_array[provider_id];
1449	KCF_PROV_REFHOLD(provider);
1450	mutex_exit(&cm->cm_lock);
1451
1452	(void) kcf_get_hardware_provider_nomech(
1453	    CRYPTO_OPS_OFFSET(provider_ops), CRYPTO_PROVIDER_OFFSET(ext_info),
1454	    CHECK_RESTRICT_FALSE, provider, &real_provider);
1455
1456	if (real_provider != NULL) {
1457		ASSERT(real_provider == provider ||
1458		    provider->pd_prov_type == CRYPTO_LOGICAL_PROVIDER);
1459		KCF_WRAP_PROVMGMT_OPS_PARAMS(&params, KCF_OP_MGMT_EXTINFO,
1460		    0, NULL, 0, NULL, 0, NULL, ext_info, provider);
1461		rv = kcf_submit_request(real_provider, NULL, NULL, &params,
1462		    B_FALSE);
1463		ASSERT(rv != CRYPTO_NOT_SUPPORTED);
1464		KCF_PROV_REFRELE(real_provider);
1465	} else {
1466		/* do the best we can */
1467		fabricate_ext_info(provider, ext_info);
1468		rv = CRYPTO_SUCCESS;
1469	}
1470	KCF_PROV_REFRELE(provider);
1471
1472	if (rv == CRYPTO_SUCCESS) {
1473		ext_to_provider_data(mode, provider, ext_info,
1474		    STRUCT_FADDR(get_info, gi_provider_data));
1475	}
1476
1477release_minor:
1478	CRYPTO_DECREMENT_RCTL(need);
1479	crypto_release_minor(cm);
1480
1481	if (ext_info != NULL)
1482		kmem_free(ext_info, sizeof (crypto_provider_ext_info_t));
1483
1484	if (error != 0)
1485		return (error);
1486
1487	STRUCT_FSET(get_info, gi_return_value, rv);
1488	if (copyout(STRUCT_BUF(get_info), arg, STRUCT_SIZE(get_info)) != 0) {
1489		return (EFAULT);
1490	}
1491	return (0);
1492}
1493
1494/*
1495 * This ioctl returns an array of crypto_mech_name_t entries.
1496 * This is how consumers learn which mechanisms are permitted
1497 * by a provider.
1498 */
1499/* ARGSUSED */
1500static int
1501get_provider_mechanisms(dev_t dev, caddr_t arg, int mode, int *rval)
1502{
1503	STRUCT_DECL(crypto_get_provider_mechanisms, get_mechanisms);
1504	crypto_mech_name_t *entries;
1505	crypto_minor_t *cm;
1506	size_t copyout_size;
1507	uint_t req_count;
1508	uint_t count;
1509	ulong_t offset;
1510	int err;
1511
1512	STRUCT_INIT(get_mechanisms, mode);
1513
1514	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
1515		cmn_err(CE_WARN,
1516		    "get_provider_mechanisms: failed holding minor");
1517		return (ENXIO);
1518	}
1519
1520	if (copyin(arg, STRUCT_BUF(get_mechanisms),
1521	    STRUCT_SIZE(get_mechanisms)) != 0) {
1522		crypto_release_minor(cm);
1523		return (EFAULT);
1524	}
1525
1526	/* get array of mechanisms from the core module */
1527	if ((err = crypto_get_provider_mechanisms(cm,
1528	    STRUCT_FGET(get_mechanisms, pm_provider_id),
1529	    &count, &entries)) != 0) {
1530		crypto_release_minor(cm);
1531		STRUCT_FSET(get_mechanisms, pm_return_value, err);
1532		if (copyout(STRUCT_BUF(get_mechanisms), arg,
1533		    STRUCT_SIZE(get_mechanisms)) != 0) {
1534			return (EFAULT);
1535		}
1536		return (0);
1537	}
1538	crypto_release_minor(cm);
1539	/* Number of mechs caller thinks we have */
1540	req_count = STRUCT_FGET(get_mechanisms, pm_count);
1541
1542	/* Check if caller is just requesting a count of mechanisms */
1543	if (req_count == 0) {
1544		STRUCT_FSET(get_mechanisms, pm_count, count);
1545		STRUCT_FSET(get_mechanisms, pm_return_value, CRYPTO_SUCCESS);
1546
1547		crypto_free_mech_list(entries, count);
1548		if (copyout(STRUCT_BUF(get_mechanisms), arg,
1549		    STRUCT_SIZE(get_mechanisms)) != 0) {
1550			return (EFAULT);
1551		}
1552		return (0);
1553	}
1554
1555	/* check if buffer is too small */
1556	if (count > req_count) {
1557		STRUCT_FSET(get_mechanisms, pm_count, count);
1558		STRUCT_FSET(get_mechanisms, pm_return_value,
1559		    CRYPTO_BUFFER_TOO_SMALL);
1560		crypto_free_mech_list(entries, count);
1561		if (copyout(STRUCT_BUF(get_mechanisms), arg,
1562		    STRUCT_SIZE(get_mechanisms)) != 0) {
1563			return (EFAULT);
1564		}
1565		return (0);
1566	}
1567
1568	STRUCT_FSET(get_mechanisms, pm_count, count);
1569	STRUCT_FSET(get_mechanisms, pm_return_value, CRYPTO_SUCCESS);
1570
1571	copyout_size = count * sizeof (crypto_mech_name_t);
1572
1573	/* copyout the first stuff */
1574	if (copyout(STRUCT_BUF(get_mechanisms), arg,
1575	    STRUCT_SIZE(get_mechanisms)) != 0) {
1576		crypto_free_mech_list(entries, count);
1577		return (EFAULT);
1578	}
1579
1580	if (count == 0) {
1581		return (0);
1582	}
1583
1584	/* copyout entries */
1585	offset = (ulong_t)STRUCT_FADDR(get_mechanisms, pm_list);
1586	offset -= (ulong_t)STRUCT_BUF(get_mechanisms);
1587	if (copyout(entries, arg + offset, copyout_size) != 0) {
1588		crypto_free_mech_list(entries, count);
1589		return (EFAULT);
1590	}
1591
1592	crypto_free_mech_list(entries, count);
1593	return (0);
1594}
1595
1596/*
1597 * This ioctl returns information about a provider's mechanism.
1598 */
1599/* ARGSUSED */
1600static int
1601get_provider_mechanism_info(dev_t dev, caddr_t arg, int mode, int *rval)
1602{
1603	crypto_get_provider_mechanism_info_t mechanism_info;
1604	crypto_minor_t *cm;
1605	kcf_provider_desc_t *pd;
1606	crypto_mech_info_t *mi = NULL;
1607	int rv = CRYPTO_SUCCESS;
1608	int i;
1609
1610	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
1611		cmn_err(CE_WARN,
1612		    "get_provider_mechanism_info: failed holding minor");
1613		return (ENXIO);
1614	}
1615
1616	if (copyin(arg, &mechanism_info, sizeof (mechanism_info)) != 0) {
1617		crypto_release_minor(cm);
1618		return (EFAULT);
1619	}
1620
1621	/* initialize provider table */
1622	if (cm->cm_provider_array == NULL) {
1623		rv = crypto_get_provider_list(cm, NULL, NULL, DONT_RETURN_LIST);
1624		if (rv != CRYPTO_SUCCESS) {
1625			mutex_enter(&cm->cm_lock);
1626			goto fail;
1627		}
1628	}
1629
1630	/*
1631	 * Provider ID must be less than the count of providers
1632	 * obtained by calling get_provider_list().
1633	 */
1634	mutex_enter(&cm->cm_lock);
1635	if (mechanism_info.mi_provider_id >= cm->cm_provider_count) {
1636		rv = CRYPTO_ARGUMENTS_BAD;
1637		goto fail;
1638	}
1639
1640	pd = cm->cm_provider_array[mechanism_info.mi_provider_id];
1641
1642	for (i = 0; i < pd->pd_mech_list_count; i++) {
1643		if (strncmp(pd->pd_mechanisms[i].cm_mech_name,
1644		    mechanism_info.mi_mechanism_name,
1645		    CRYPTO_MAX_MECH_NAME) == 0) {
1646			mi = &pd->pd_mechanisms[i];
1647		}
1648	}
1649
1650	if (mi == NULL) {
1651		rv = CRYPTO_ARGUMENTS_BAD;
1652		goto fail;
1653	}
1654
1655	mechanism_info.mi_min_key_size = mi->cm_min_key_length;
1656	mechanism_info.mi_max_key_size = mi->cm_max_key_length;
1657	mechanism_info.mi_flags = mi->cm_func_group_mask;
1658
1659fail:
1660	mutex_exit(&cm->cm_lock);
1661	crypto_release_minor(cm);
1662	mechanism_info.mi_return_value = rv;
1663	if (copyout(&mechanism_info, arg, sizeof (mechanism_info)) != 0) {
1664		return (EFAULT);
1665	}
1666
1667	return (0);
1668}
1669
1670/*
1671 * Every open of /dev/crypto multiplexes all PKCS#11 sessions across
1672 * a single session to each provider. Calls to open and close session
1673 * are not made to providers that do not support sessions. For these
1674 * providers, a session number of 0 is passed during subsequent operations,
1675 * and it is ignored by the provider.
1676 */
1677static int
1678crypto_get_provider_session(crypto_minor_t *cm,
1679    crypto_provider_id_t provider_index, crypto_provider_session_t **output_ps)
1680{
1681	kcf_provider_desc_t *pd, *real_provider;
1682	kcf_req_params_t params;
1683	crypto_provider_session_t *ps, *new_ps;
1684	crypto_session_id_t provider_session_id = 0;
1685	int rv;
1686
1687	ASSERT(MUTEX_HELD(&cm->cm_lock));
1688
1689	/* pd may be a logical provider */
1690	pd = cm->cm_provider_array[provider_index];
1691
1692again:
1693	/*
1694	 * Check if there is already a session to the provider.
1695	 * Sessions may be to a logical provider or a real provider.
1696	 */
1697	for (ps = cm->cm_provider_session; ps != NULL; ps = ps->ps_next) {
1698		if (ps->ps_provider == pd)
1699			break;
1700	}
1701
1702	/* found existing session */
1703	if (ps != NULL) {
1704		ps->ps_refcnt++;
1705		*output_ps = ps;
1706		return (CRYPTO_SUCCESS);
1707	}
1708	mutex_exit(&cm->cm_lock);
1709
1710	/* find a hardware provider that supports session ops */
1711	(void) kcf_get_hardware_provider_nomech(CRYPTO_OPS_OFFSET(session_ops),
1712	    CRYPTO_SESSION_OFFSET(session_open), CHECK_RESTRICT_FALSE,
1713	    pd, &real_provider);
1714
1715	if (real_provider != NULL) {
1716		ASSERT(real_provider == pd ||
1717		    pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER);
1718		/* open session to provider */
1719		KCF_WRAP_SESSION_OPS_PARAMS(&params, KCF_OP_SESSION_OPEN,
1720		    &provider_session_id, 0, CRYPTO_USER, NULL, 0, pd);
1721		rv = kcf_submit_request(real_provider, NULL, NULL, &params,
1722		    B_FALSE);
1723		if (rv != CRYPTO_SUCCESS) {
1724			mutex_enter(&cm->cm_lock);
1725			KCF_PROV_REFRELE(real_provider);
1726			return (rv);
1727		}
1728	}
1729
1730	/* allocate crypto_provider_session structure */
1731	new_ps = kmem_zalloc(sizeof (crypto_provider_session_t), KM_SLEEP);
1732
1733	/*
1734	 * Check if someone opened a session to the provider
1735	 * while we dropped the lock.
1736	 */
1737	mutex_enter(&cm->cm_lock);
1738	for (ps = cm->cm_provider_session; ps != NULL; ps = ps->ps_next) {
1739		if (ps->ps_provider == pd) {
1740			mutex_exit(&cm->cm_lock);
1741			kmem_free(new_ps, sizeof (crypto_provider_session_t));
1742			if (real_provider != NULL) {
1743				KCF_WRAP_SESSION_OPS_PARAMS(&params,
1744				    KCF_OP_SESSION_CLOSE, NULL,
1745				    provider_session_id, CRYPTO_USER, NULL, 0,
1746				    pd);
1747				(void) kcf_submit_request(real_provider, NULL,
1748				    NULL, &params, B_FALSE);
1749				KCF_PROV_REFRELE(real_provider);
1750			}
1751			mutex_enter(&cm->cm_lock);
1752			goto again;
1753
1754		}
1755	}
1756
1757	/* increment refcnt and attach to crypto_minor structure */
1758	new_ps->ps_session = provider_session_id;
1759	new_ps->ps_refcnt = 1;
1760	KCF_PROV_REFHOLD(pd);
1761	new_ps->ps_provider = pd;
1762	if (real_provider != NULL) {
1763		new_ps->ps_real_provider = real_provider;
1764	}
1765	new_ps->ps_next = cm->cm_provider_session;
1766	cm->cm_provider_session = new_ps;
1767
1768	*output_ps = new_ps;
1769	return (CRYPTO_SUCCESS);
1770}
1771
1772/*
1773 * Release a provider session.
1774 * If the reference count goes to zero, then close the session
1775 * to the provider.
1776 */
1777static void
1778crypto_release_provider_session(crypto_minor_t *cm,
1779    crypto_provider_session_t *provider_session)
1780{
1781	kcf_req_params_t params;
1782	crypto_provider_session_t *ps = NULL, **prev;
1783
1784	ASSERT(MUTEX_HELD(&cm->cm_lock));
1785
1786	/* verify that provider_session is valid */
1787	for (ps = cm->cm_provider_session, prev = &cm->cm_provider_session;
1788	    ps != NULL; prev = &ps->ps_next, ps = ps->ps_next) {
1789		if (ps == provider_session) {
1790			break;
1791		}
1792	}
1793
1794	if (ps == NULL)
1795		return;
1796
1797	ps->ps_refcnt--;
1798
1799	if (ps->ps_refcnt > 0)
1800		return;
1801
1802	if (ps->ps_real_provider != NULL) {
1803		/* close session with provider */
1804		KCF_WRAP_SESSION_OPS_PARAMS(&params, KCF_OP_SESSION_CLOSE, NULL,
1805		    ps->ps_session, CRYPTO_USER, NULL, 0, ps->ps_provider);
1806		(void) kcf_submit_request(ps->ps_real_provider,
1807		    NULL, NULL, &params, B_FALSE);
1808		KCF_PROV_REFRELE(ps->ps_real_provider);
1809	}
1810	KCF_PROV_REFRELE(ps->ps_provider);
1811	*prev = ps->ps_next;
1812	kmem_free(ps, sizeof (*ps));
1813}
1814
1815static int
1816grow_session_table(crypto_minor_t *cm)
1817{
1818	crypto_session_data_t **session_table;
1819	crypto_session_data_t **new;
1820	uint_t session_table_count;
1821	uint_t need;
1822	size_t current_allocation;
1823	size_t new_allocation;
1824	int rv;
1825
1826	ASSERT(MUTEX_HELD(&cm->cm_lock));
1827
1828	session_table_count = cm->cm_session_table_count;
1829	session_table = cm->cm_session_table;
1830	need = session_table_count + CRYPTO_SESSION_CHUNK;
1831
1832	current_allocation = session_table_count * sizeof (void *);
1833	new_allocation = need * sizeof (void *);
1834
1835	/*
1836	 * Memory needed to grow the session table is checked
1837	 * against the project.max-crypto-memory resource control.
1838	 */
1839	if ((rv = crypto_buffer_check(new_allocation - current_allocation)) !=
1840	    CRYPTO_SUCCESS) {
1841		return (rv);
1842	}
1843
1844	/* drop lock while we allocate memory */
1845	mutex_exit(&cm->cm_lock);
1846	new = kmem_zalloc(new_allocation, KM_SLEEP);
1847	mutex_enter(&cm->cm_lock);
1848
1849	/* check if another thread increased the table size */
1850	if (session_table_count != cm->cm_session_table_count) {
1851		kmem_free(new, new_allocation);
1852		return (CRYPTO_SUCCESS);
1853	}
1854
1855	bcopy(session_table, new, current_allocation);
1856	kmem_free(session_table, current_allocation);
1857	cm->cm_session_table = new;
1858	cm->cm_session_table_count += CRYPTO_SESSION_CHUNK;
1859
1860	return (CRYPTO_SUCCESS);
1861}
1862
1863/*
1864 * Find unused entry in session table and return it's index.
1865 * Initialize session table entry.
1866 */
1867/* ARGSUSED */
1868static int
1869crypto_open_session(dev_t dev, uint_t flags, crypto_session_id_t *session_index,
1870    crypto_provider_id_t provider_id)
1871{
1872	crypto_session_data_t **session_table;
1873	crypto_session_data_t *sp;
1874	crypto_minor_t *cm;
1875	uint_t session_table_count;
1876	uint_t i;
1877	int rv;
1878	crypto_provider_session_t *ps;
1879	kcf_provider_desc_t *provider;
1880
1881	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
1882		cmn_err(CE_WARN, "crypto_open_session: failed holding minor");
1883		return (CRYPTO_FAILED);
1884	}
1885
1886	/* initialize provider_array */
1887	if (cm->cm_provider_array == NULL) {
1888		rv = crypto_get_provider_list(cm, NULL, NULL, DONT_RETURN_LIST);
1889		if (rv != 0) {
1890			crypto_release_minor(cm);
1891			return (rv);
1892		}
1893	}
1894
1895	mutex_enter(&cm->cm_lock);
1896	/* index must be less than count of providers */
1897	if (provider_id >= cm->cm_provider_count) {
1898		mutex_exit(&cm->cm_lock);
1899		crypto_release_minor(cm);
1900		return (CRYPTO_INVALID_PROVIDER_ID);
1901	}
1902	ASSERT(cm->cm_provider_array != NULL);
1903
1904	rv = crypto_get_provider_session(cm, provider_id, &ps);
1905	if (rv != CRYPTO_SUCCESS) {
1906		mutex_exit(&cm->cm_lock);
1907		crypto_release_minor(cm);
1908		return (rv);
1909	}
1910	provider = cm->cm_provider_array[provider_id];
1911
1912again:
1913	session_table_count = cm->cm_session_table_count;
1914	session_table = cm->cm_session_table;
1915
1916	/* session handles start with 1 */
1917	for (i = 1; i < session_table_count; i++) {
1918		if (session_table[i] == NULL)
1919			break;
1920	}
1921
1922	if (i == session_table_count || session_table_count == 0) {
1923		if ((rv = grow_session_table(cm)) != CRYPTO_SUCCESS) {
1924			crypto_release_provider_session(cm, ps);
1925			mutex_exit(&cm->cm_lock);
1926			crypto_release_minor(cm);
1927			return (rv);
1928		}
1929		goto again;
1930	}
1931
1932	sp = kmem_cache_alloc(crypto_session_cache, KM_SLEEP);
1933	sp->sd_flags = 0;
1934	sp->sd_find_init_cookie = NULL;
1935	sp->sd_digest_ctx = NULL;
1936	sp->sd_encr_ctx = NULL;
1937	sp->sd_decr_ctx = NULL;
1938	sp->sd_sign_ctx = NULL;
1939	sp->sd_verify_ctx = NULL;
1940	sp->sd_sign_recover_ctx = NULL;
1941	sp->sd_verify_recover_ctx = NULL;
1942	mutex_init(&sp->sd_lock, NULL, MUTEX_DRIVER, NULL);
1943	cv_init(&sp->sd_cv, NULL, CV_DRIVER, NULL);
1944	KCF_PROV_REFHOLD(provider);
1945	sp->sd_provider = provider;
1946	sp->sd_provider_session = ps;
1947
1948	/* See the comment for CRYPTO_PRE_APPROVED_LIMIT. */
1949	if ((rv = crypto_buffer_check(crypto_pre_approved_limit)) !=
1950	    CRYPTO_SUCCESS) {
1951		sp->sd_pre_approved_amount = 0;
1952	} else {
1953		sp->sd_pre_approved_amount = crypto_pre_approved_limit;
1954	}
1955
1956	cm->cm_session_table[i] = sp;
1957	mutex_exit(&cm->cm_lock);
1958	crypto_release_minor(cm);
1959	*session_index = i;
1960
1961	return (CRYPTO_SUCCESS);
1962}
1963
1964/*
1965 * Close a session.
1966 */
1967static int
1968crypto_close_session(dev_t dev, crypto_session_id_t session_index)
1969{
1970	crypto_session_data_t **session_table;
1971	crypto_session_data_t *sp;
1972	crypto_minor_t *cm;
1973
1974	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
1975		cmn_err(CE_WARN, "crypto_close_session: failed holding minor");
1976		return (CRYPTO_FAILED);
1977	}
1978
1979	mutex_enter(&cm->cm_lock);
1980	session_table = cm->cm_session_table;
1981
1982	if ((session_index) == 0 ||
1983	    (session_index >= cm->cm_session_table_count)) {
1984		mutex_exit(&cm->cm_lock);
1985		crypto_release_minor(cm);
1986		return (CRYPTO_SESSION_HANDLE_INVALID);
1987	}
1988
1989	sp = session_table[session_index];
1990	if (sp == NULL) {
1991		mutex_exit(&cm->cm_lock);
1992		crypto_release_minor(cm);
1993		return (CRYPTO_SESSION_HANDLE_INVALID);
1994	}
1995	/*
1996	 * If session is in use, free it when the thread
1997	 * finishes with the session.
1998	 */
1999	mutex_enter(&sp->sd_lock);
2000	if (sp->sd_flags & CRYPTO_SESSION_IS_BUSY) {
2001		sp->sd_flags |= CRYPTO_SESSION_IS_CLOSED;
2002		mutex_exit(&sp->sd_lock);
2003	} else {
2004		ASSERT(sp->sd_pre_approved_amount == 0 ||
2005		    sp->sd_pre_approved_amount == crypto_pre_approved_limit);
2006		CRYPTO_DECREMENT_RCTL(sp->sd_pre_approved_amount);
2007
2008		if (sp->sd_find_init_cookie != NULL) {
2009			(void) crypto_free_find_ctx(sp);
2010		}
2011
2012		crypto_release_provider_session(cm, sp->sd_provider_session);
2013		KCF_PROV_REFRELE(sp->sd_provider);
2014		CRYPTO_CANCEL_ALL_CTX(sp);
2015		mutex_destroy(&sp->sd_lock);
2016		cv_destroy(&sp->sd_cv);
2017		kmem_cache_free(crypto_session_cache, sp);
2018		session_table[session_index] = NULL;
2019	}
2020
2021	mutex_exit(&cm->cm_lock);
2022	crypto_release_minor(cm);
2023
2024	return (CRYPTO_SUCCESS);
2025}
2026
2027/*
2028 * This ioctl opens a session and returns the session ID in os_session.
2029 */
2030/* ARGSUSED */
2031static int
2032open_session(dev_t dev, caddr_t arg, int mode, int *rval)
2033{
2034	crypto_open_session_t open_session;
2035	crypto_session_id_t session;
2036	int rv;
2037
2038	if (copyin(arg, &open_session, sizeof (open_session)) != 0)
2039		return (EFAULT);
2040
2041	rv = crypto_open_session(dev, open_session.os_flags,
2042	    &session, open_session.os_provider_id);
2043	if (rv != CRYPTO_SUCCESS) {
2044		open_session.os_return_value = rv;
2045		if (copyout(&open_session, arg, sizeof (open_session)) != 0) {
2046			return (EFAULT);
2047		}
2048		return (0);
2049	}
2050
2051	open_session.os_session = session;
2052	open_session.os_return_value = CRYPTO_SUCCESS;
2053
2054	if (copyout(&open_session, arg, sizeof (open_session)) != 0) {
2055		return (EFAULT);
2056	}
2057	return (0);
2058}
2059
2060/*
2061 * This ioctl closes a session.
2062 */
2063/* ARGSUSED */
2064static int
2065close_session(dev_t dev, caddr_t arg, int mode, int *rval)
2066{
2067	crypto_close_session_t close_session;
2068	int rv;
2069
2070	if (copyin(arg, &close_session, sizeof (close_session)) != 0)
2071		return (EFAULT);
2072
2073	rv = crypto_close_session(dev, close_session.cs_session);
2074	close_session.cs_return_value = rv;
2075	if (copyout(&close_session, arg, sizeof (close_session)) != 0) {
2076		return (EFAULT);
2077	}
2078	return (0);
2079}
2080
2081/*
2082 * Copy data model dependent mechanism structure into a kernel mechanism
2083 * structure.  Allocate param storage if necessary.
2084 */
2085static boolean_t
2086copyin_mech(int mode, crypto_session_data_t *sp, crypto_mechanism_t *in_mech,
2087    crypto_mechanism_t *out_mech, size_t *out_rctl_bytes,
2088    boolean_t *out_rctl_chk, int *out_rv, int *out_error)
2089{
2090	STRUCT_DECL(crypto_mechanism, mech);
2091	caddr_t param;
2092	size_t param_len;
2093	size_t rctl_bytes = 0;
2094	int error = 0;
2095	int rv = 0;
2096
2097	STRUCT_INIT(mech, mode);
2098	bcopy(in_mech, STRUCT_BUF(mech), STRUCT_SIZE(mech));
2099	param = STRUCT_FGETP(mech, cm_param);
2100	param_len = STRUCT_FGET(mech, cm_param_len);
2101	out_mech->cm_type = STRUCT_FGET(mech, cm_type);
2102	out_mech->cm_param = NULL;
2103	out_mech->cm_param_len = 0;
2104	if (param != NULL && param_len != 0) {
2105		if (param_len > crypto_max_buffer_len) {
2106			cmn_err(CE_NOTE, "copyin_mech: buffer greater than "
2107			    "%ld bytes, pid = %d", crypto_max_buffer_len,
2108			    curproc->p_pid);
2109			rv = CRYPTO_ARGUMENTS_BAD;
2110			goto out;
2111		}
2112
2113		rv = CRYPTO_BUFFER_CHECK(sp, param_len, *out_rctl_chk);
2114		if (rv != CRYPTO_SUCCESS) {
2115			goto out;
2116		}
2117		rctl_bytes = param_len;
2118
2119		out_mech->cm_param = kmem_alloc(param_len, KM_SLEEP);
2120		if (copyin((char *)param, out_mech->cm_param, param_len) != 0) {
2121			kmem_free(out_mech->cm_param, param_len);
2122			out_mech->cm_param = NULL;
2123			error = EFAULT;
2124			goto out;
2125		}
2126		out_mech->cm_param_len = param_len;
2127	}
2128out:
2129	*out_rctl_bytes = rctl_bytes;
2130	*out_rv = rv;
2131	*out_error = error;
2132	return ((rv | error) ? B_FALSE : B_TRUE);
2133}
2134
2135/*
2136 * Free key attributes when key type is CRYPTO_KEY_ATTR_LIST.
2137 * The crypto_key structure is not freed.
2138 */
2139static void
2140crypto_free_key_attributes(crypto_key_t *key)
2141{
2142	crypto_object_attribute_t *attrs;
2143	size_t len = 0;
2144	int i;
2145
2146	ASSERT(key->ck_format == CRYPTO_KEY_ATTR_LIST);
2147	if (key->ck_count == 0 || key->ck_attrs == NULL)
2148		return;
2149
2150	/* compute the size of the container */
2151	len = key->ck_count * sizeof (crypto_object_attribute_t);
2152
2153	/* total up the size of all attributes in the container */
2154	for (i = 0; i < key->ck_count; i++) {
2155		attrs = &key->ck_attrs[i];
2156		if (attrs->oa_value_len != 0 &&
2157		    attrs->oa_value != NULL) {
2158			len += roundup(attrs->oa_value_len, sizeof (caddr_t));
2159		}
2160	}
2161
2162	bzero(key->ck_attrs, len);
2163	kmem_free(key->ck_attrs, len);
2164}
2165
2166/*
2167 * Frees allocated storage in the key structure, but doesn't free
2168 * the key structure.
2169 */
2170static void
2171free_crypto_key(crypto_key_t *key)
2172{
2173	switch (key->ck_format) {
2174	case CRYPTO_KEY_RAW: {
2175		size_t len;
2176
2177		if (key->ck_length == 0 || key->ck_data == NULL)
2178			break;
2179
2180		len = CRYPTO_BITS2BYTES(key->ck_length);
2181		bzero(key->ck_data, len);
2182		kmem_free(key->ck_data, len);
2183		break;
2184	}
2185
2186	case CRYPTO_KEY_ATTR_LIST:
2187		crypto_free_key_attributes(key);
2188		break;
2189
2190	default:
2191		break;
2192	}
2193}
2194
2195/*
2196 * Copy in an array of crypto_object_attribute structures from user-space.
2197 * Kernel memory is allocated for the array and the value of each attribute
2198 * in the array.  Since unprivileged users can specify the size of attributes,
2199 * the amount of memory needed is charged against the
2200 * project.max-crypto-memory resource control.
2201 *
2202 * Attribute values are copied in from user-space if copyin_value is set to
2203 * B_TRUE.  This routine returns B_TRUE if the copyin was successful.
2204 */
2205static boolean_t
2206copyin_attributes(int mode, crypto_session_data_t *sp,
2207    uint_t count, caddr_t oc_attributes,
2208    crypto_object_attribute_t **k_attrs_out, size_t *k_attrs_size_out,
2209    caddr_t *u_attrs_out, int *out_rv, int *out_error, size_t *out_rctl_bytes,
2210    boolean_t *out_rctl_chk, boolean_t copyin_value)
2211{
2212	STRUCT_DECL(crypto_object_attribute, oa);
2213	crypto_object_attribute_t *k_attrs = NULL;
2214	caddr_t attrs = NULL, ap, p, value;
2215	caddr_t k_attrs_buf;
2216	size_t k_attrs_len;
2217	size_t k_attrs_buf_len = 0;
2218	size_t k_attrs_total_len = 0;
2219	size_t tmp_len;
2220	size_t rctl_bytes = 0;
2221	size_t len = 0;
2222	size_t value_len;
2223	int error = 0;
2224	int rv = 0;
2225	int i;
2226
2227	STRUCT_INIT(oa, mode);
2228
2229	if (count == 0) {
2230		rv = CRYPTO_SUCCESS;
2231		goto out;
2232	}
2233
2234	if (count > CRYPTO_MAX_ATTRIBUTE_COUNT) {
2235		rv = CRYPTO_ARGUMENTS_BAD;
2236		goto out;
2237	}
2238
2239	/* compute size of crypto_object_attribute array */
2240	len = count * STRUCT_SIZE(oa);
2241
2242	/* this allocation is not charged against the user's resource limit */
2243	attrs = kmem_alloc(len, KM_SLEEP);
2244	if (copyin(oc_attributes, attrs, len) != 0) {
2245		error = EFAULT;
2246		goto out;
2247	}
2248
2249	/* figure out how much memory to allocate for all of the attributes */
2250	ap = attrs;
2251	for (i = 0; i < count; i++) {
2252		bcopy(ap, STRUCT_BUF(oa), STRUCT_SIZE(oa));
2253		tmp_len = roundup(STRUCT_FGET(oa, oa_value_len),
2254		    sizeof (caddr_t));
2255		if (tmp_len > crypto_max_buffer_len) {
2256			cmn_err(CE_NOTE, "copyin_attributes: buffer greater "
2257			    "than %ld bytes, pid = %d", crypto_max_buffer_len,
2258			    curproc->p_pid);
2259			rv = CRYPTO_ARGUMENTS_BAD;
2260			goto out;
2261		}
2262		if (STRUCT_FGETP(oa, oa_value) != NULL)
2263			k_attrs_buf_len += tmp_len;
2264		ap += STRUCT_SIZE(oa);
2265	}
2266
2267	k_attrs_len = count * sizeof (crypto_object_attribute_t);
2268	k_attrs_total_len = k_attrs_buf_len + k_attrs_len;
2269
2270	rv = CRYPTO_BUFFER_CHECK(sp, k_attrs_total_len, *out_rctl_chk);
2271	if (rv != CRYPTO_SUCCESS) {
2272		goto out;
2273	}
2274	rctl_bytes = k_attrs_total_len;
2275
2276	/* one big allocation for everything */
2277	k_attrs = kmem_alloc(k_attrs_total_len, KM_SLEEP);
2278	k_attrs_buf = (char *)k_attrs + k_attrs_len;
2279
2280	ap = attrs;
2281	p = k_attrs_buf;
2282	for (i = 0; i < count; i++) {
2283		bcopy(ap, STRUCT_BUF(oa), STRUCT_SIZE(oa));
2284		k_attrs[i].oa_type = STRUCT_FGET(oa, oa_type);
2285		value = STRUCT_FGETP(oa, oa_value);
2286		value_len = STRUCT_FGET(oa, oa_value_len);
2287		if (value != NULL && value_len != 0 && copyin_value) {
2288			if (copyin(value, p, value_len) != 0) {
2289				kmem_free(k_attrs, k_attrs_total_len);
2290				k_attrs = NULL;
2291				error = EFAULT;
2292				goto out;
2293			}
2294		}
2295
2296		if (value != NULL) {
2297			k_attrs[i].oa_value = p;
2298			p += roundup(value_len, sizeof (caddr_t));
2299		} else {
2300			k_attrs[i].oa_value = NULL;
2301		}
2302		k_attrs[i].oa_value_len = value_len;
2303		ap += STRUCT_SIZE(oa);
2304	}
2305out:
2306	if (attrs != NULL) {
2307		/*
2308		 * Free the array if there is a failure or the caller
2309		 * doesn't want the array to be returned.
2310		 */
2311		if (error != 0 || rv != CRYPTO_SUCCESS || u_attrs_out == NULL) {
2312			kmem_free(attrs, len);
2313			attrs = NULL;
2314		}
2315	}
2316
2317	if (u_attrs_out != NULL)
2318		*u_attrs_out = attrs;
2319	if (k_attrs_size_out != NULL)
2320		*k_attrs_size_out = k_attrs_total_len;
2321	*k_attrs_out = k_attrs;
2322	*out_rctl_bytes = rctl_bytes;
2323	*out_rv = rv;
2324	*out_error = error;
2325	return ((rv | error) ? B_FALSE : B_TRUE);
2326}
2327
2328/*
2329 * Copy data model dependent raw key into a kernel key
2330 * structure.  Checks key length or attribute lengths against
2331 * resource controls before allocating memory.  Returns B_TRUE
2332 * if both error and rv are set to 0.
2333 */
2334static boolean_t
2335copyin_key(int mode, crypto_session_data_t *sp, crypto_key_t *in_key,
2336    crypto_key_t *out_key, size_t *out_rctl_bytes,
2337    boolean_t *out_rctl_chk, int *out_rv, int *out_error)
2338{
2339	STRUCT_DECL(crypto_key, key);
2340	crypto_object_attribute_t *k_attrs = NULL;
2341	size_t key_bits;
2342	size_t key_bytes = 0;
2343	size_t rctl_bytes = 0;
2344	int count;
2345	int error = 0;
2346	int rv = CRYPTO_SUCCESS;
2347
2348	STRUCT_INIT(key, mode);
2349	bcopy(in_key, STRUCT_BUF(key), STRUCT_SIZE(key));
2350	out_key->ck_format = STRUCT_FGET(key, ck_format);
2351	switch (out_key->ck_format) {
2352	case CRYPTO_KEY_RAW:
2353		key_bits = STRUCT_FGET(key, ck_length);
2354		if (key_bits != 0) {
2355			key_bytes = CRYPTO_BITS2BYTES(key_bits);
2356			if (key_bytes > crypto_max_buffer_len) {
2357				cmn_err(CE_NOTE, "copyin_key: buffer greater "
2358				    "than %ld bytes, pid = %d",
2359				    crypto_max_buffer_len, curproc->p_pid);
2360				rv = CRYPTO_ARGUMENTS_BAD;
2361				goto out;
2362			}
2363
2364			rv = CRYPTO_BUFFER_CHECK(sp, key_bytes,
2365			    *out_rctl_chk);
2366			if (rv != CRYPTO_SUCCESS) {
2367				goto out;
2368			}
2369			rctl_bytes = key_bytes;
2370
2371			out_key->ck_data = kmem_alloc(key_bytes, KM_SLEEP);
2372
2373			if (copyin((char *)STRUCT_FGETP(key, ck_data),
2374			    out_key->ck_data, key_bytes) != 0) {
2375				kmem_free(out_key->ck_data, key_bytes);
2376				out_key->ck_data = NULL;
2377				out_key->ck_length = 0;
2378				error = EFAULT;
2379				goto out;
2380			}
2381		}
2382		out_key->ck_length = key_bits;
2383		break;
2384
2385	case CRYPTO_KEY_ATTR_LIST:
2386		count = STRUCT_FGET(key, ck_count);
2387
2388		if (copyin_attributes(mode, sp, count,
2389		    (caddr_t)STRUCT_FGETP(key, ck_attrs), &k_attrs, NULL, NULL,
2390		    &rv, &error, &rctl_bytes, out_rctl_chk, B_TRUE)) {
2391			out_key->ck_count = count;
2392			out_key->ck_attrs = k_attrs;
2393			k_attrs = NULL;
2394		} else {
2395			out_key->ck_count = 0;
2396			out_key->ck_attrs = NULL;
2397		}
2398		break;
2399
2400	case CRYPTO_KEY_REFERENCE:
2401		out_key->ck_obj_id = STRUCT_FGET(key, ck_obj_id);
2402		break;
2403
2404	default:
2405		rv = CRYPTO_ARGUMENTS_BAD;
2406	}
2407
2408out:
2409	*out_rctl_bytes = rctl_bytes;
2410	*out_rv = rv;
2411	*out_error = error;
2412	return ((rv | error) ? B_FALSE : B_TRUE);
2413}
2414
2415/*
2416 * This routine does two things:
2417 * 1. Given a crypto_minor structure and a session ID, it returns
2418 *    a valid session pointer.
2419 * 2. It checks that the provider, to which the session has been opened,
2420 *    has not been removed.
2421 */
2422static boolean_t
2423get_session_ptr(crypto_session_id_t i, crypto_minor_t *cm,
2424    crypto_session_data_t **session_ptr, int *out_error, int *out_rv)
2425{
2426	crypto_session_data_t *sp = NULL;
2427	int rv = CRYPTO_SESSION_HANDLE_INVALID;
2428	int error = 0;
2429
2430	mutex_enter(&cm->cm_lock);
2431	if ((i < cm->cm_session_table_count) &&
2432	    (cm->cm_session_table[i] != NULL)) {
2433		sp = cm->cm_session_table[i];
2434		mutex_enter(&sp->sd_lock);
2435		mutex_exit(&cm->cm_lock);
2436		while (sp->sd_flags & CRYPTO_SESSION_IS_BUSY) {
2437			if (cv_wait_sig(&sp->sd_cv, &sp->sd_lock) == 0) {
2438				mutex_exit(&sp->sd_lock);
2439				sp = NULL;
2440				error = EINTR;
2441				goto out;
2442			}
2443		}
2444
2445		if (sp->sd_flags & CRYPTO_SESSION_IS_CLOSED) {
2446			mutex_exit(&sp->sd_lock);
2447			sp = NULL;
2448			goto out;
2449		}
2450
2451		if (KCF_IS_PROV_REMOVED(sp->sd_provider)) {
2452			mutex_exit(&sp->sd_lock);
2453			sp = NULL;
2454			rv = CRYPTO_DEVICE_ERROR;
2455			goto out;
2456		}
2457
2458		rv = CRYPTO_SUCCESS;
2459		sp->sd_flags |= CRYPTO_SESSION_IS_BUSY;
2460		mutex_exit(&sp->sd_lock);
2461	} else {
2462		mutex_exit(&cm->cm_lock);
2463	}
2464out:
2465	*session_ptr = sp;
2466	*out_error = error;
2467	*out_rv = rv;
2468	return ((rv == CRYPTO_SUCCESS && error == 0) ? B_TRUE : B_FALSE);
2469}
2470
2471#define	CRYPTO_SESSION_RELE(s)	if ((s) != NULL) {	\
2472	mutex_enter(&((s)->sd_lock));			\
2473	(s)->sd_flags &= ~CRYPTO_SESSION_IS_BUSY;	\
2474	cv_broadcast(&(s)->sd_cv);			\
2475	mutex_exit(&((s)->sd_lock));			\
2476}
2477
2478/* ARGSUSED */
2479static int
2480encrypt_init(dev_t dev, caddr_t arg, int mode, int *rval)
2481{
2482	return (cipher_init(dev, arg, mode, crypto_encrypt_init_prov));
2483}
2484
2485/* ARGSUSED */
2486static int
2487decrypt_init(dev_t dev, caddr_t arg, int mode, int *rval)
2488{
2489	return (cipher_init(dev, arg, mode, crypto_decrypt_init_prov));
2490}
2491
2492/*
2493 * umech is a mechanism structure that has been copied from user address
2494 * space into kernel address space. Only one copyin has been done.
2495 * The mechanism parameter, if non-null, still points to user address space.
2496 * If the mechanism parameter contains pointers, they are pointers into
2497 * user address space.
2498 *
2499 * kmech is a umech with all pointers and structures in kernel address space.
2500 *
2501 * This routine calls the provider's entry point to copy a umech parameter
2502 * into kernel address space. Kernel memory is allocated by the provider.
2503 */
2504static int
2505crypto_provider_copyin_mech_param(kcf_provider_desc_t *pd,
2506    crypto_mechanism_t *umech, crypto_mechanism_t *kmech, int mode, int *error)
2507{
2508	crypto_mech_type_t provider_mech_type;
2509	int rv;
2510
2511	/* get the provider's mech number */
2512	provider_mech_type = KCF_TO_PROV_MECHNUM(pd, umech->cm_type);
2513
2514	kmech->cm_param = NULL;
2515	kmech->cm_param_len = 0;
2516	kmech->cm_type = provider_mech_type;
2517	rv = KCF_PROV_COPYIN_MECH(pd, umech, kmech, error, mode);
2518	kmech->cm_type = umech->cm_type;
2519
2520	return (rv);
2521}
2522
2523/*
2524 * umech is a mechanism structure that has been copied from user address
2525 * space into kernel address space. Only one copyin has been done.
2526 * The mechanism parameter, if non-null, still points to user address space.
2527 * If the mechanism parameter contains pointers, they are pointers into
2528 * user address space.
2529 *
2530 * kmech is a umech with all pointers and structures in kernel address space.
2531 *
2532 * This routine calls the provider's entry point to copy a kmech parameter
2533 * into user address space using umech as a template containing
2534 * user address pointers.
2535 */
2536static int
2537crypto_provider_copyout_mech_param(kcf_provider_desc_t *pd,
2538    crypto_mechanism_t *kmech, crypto_mechanism_t *umech, int mode, int *error)
2539{
2540	crypto_mech_type_t provider_mech_type;
2541	int rv;
2542
2543	/* get the provider's mech number */
2544	provider_mech_type = KCF_TO_PROV_MECHNUM(pd, umech->cm_type);
2545
2546	kmech->cm_type = provider_mech_type;
2547	rv = KCF_PROV_COPYOUT_MECH(pd, kmech, umech, error, mode);
2548	kmech->cm_type = umech->cm_type;
2549
2550	return (rv);
2551}
2552
2553/*
2554 * Call the provider's entry point to free kernel memory that has been
2555 * allocated for the mechanism's parameter.
2556 */
2557static void
2558crypto_free_mech(kcf_provider_desc_t *pd, boolean_t allocated_by_crypto_module,
2559    crypto_mechanism_t *mech)
2560{
2561	crypto_mech_type_t provider_mech_type;
2562
2563	if (allocated_by_crypto_module) {
2564		if (mech->cm_param != NULL)
2565			kmem_free(mech->cm_param, mech->cm_param_len);
2566	} else {
2567		/* get the provider's mech number */
2568		provider_mech_type = KCF_TO_PROV_MECHNUM(pd, mech->cm_type);
2569
2570		if (mech->cm_param != NULL && mech->cm_param_len != 0) {
2571			mech->cm_type = provider_mech_type;
2572			(void) KCF_PROV_FREE_MECH(pd, mech);
2573		}
2574	}
2575}
2576
2577/*
2578 * ASSUMPTION: crypto_encrypt_init and crypto_decrypt_init
2579 * structures are identical except for field names.
2580 */
2581static int
2582cipher_init(dev_t dev, caddr_t arg, int mode, int (*init)(crypto_provider_t,
2583    crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
2584    crypto_ctx_template_t, crypto_context_t *, crypto_call_req_t *))
2585{
2586	STRUCT_DECL(crypto_encrypt_init, encrypt_init);
2587	kcf_provider_desc_t *real_provider = NULL;
2588	crypto_session_id_t session_id;
2589	crypto_mechanism_t mech;
2590	crypto_key_t key;
2591	crypto_minor_t *cm;
2592	crypto_session_data_t *sp = NULL;
2593	crypto_context_t cc;
2594	crypto_ctx_t **ctxpp;
2595	size_t mech_rctl_bytes = 0;
2596	boolean_t mech_rctl_chk = B_FALSE;
2597	size_t key_rctl_bytes = 0;
2598	boolean_t key_rctl_chk = B_FALSE;
2599	int error = 0;
2600	int rv;
2601	boolean_t allocated_by_crypto_module = B_FALSE;
2602	crypto_func_group_t fg;
2603
2604	STRUCT_INIT(encrypt_init, mode);
2605
2606	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
2607		cmn_err(CE_WARN, "cipher_init: failed holding minor");
2608		return (ENXIO);
2609	}
2610
2611	if (copyin(arg, STRUCT_BUF(encrypt_init),
2612	    STRUCT_SIZE(encrypt_init)) != 0) {
2613		crypto_release_minor(cm);
2614		return (EFAULT);
2615	}
2616
2617	mech.cm_param = NULL;
2618	bzero(&key, sizeof (crypto_key_t));
2619
2620	session_id = STRUCT_FGET(encrypt_init, ei_session);
2621
2622	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
2623		goto out;
2624	}
2625
2626	bcopy(STRUCT_FADDR(encrypt_init, ei_mech), &mech.cm_type,
2627	    sizeof (crypto_mech_type_t));
2628
2629	if (init == crypto_encrypt_init_prov) {
2630		fg = CRYPTO_FG_ENCRYPT;
2631	} else {
2632		fg = CRYPTO_FG_DECRYPT;
2633	}
2634
2635	if ((rv = kcf_get_hardware_provider(mech.cm_type, CRYPTO_MECH_INVALID,
2636	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider, fg))
2637	    != CRYPTO_SUCCESS) {
2638		goto out;
2639	}
2640
2641	rv = crypto_provider_copyin_mech_param(real_provider,
2642	    STRUCT_FADDR(encrypt_init, ei_mech), &mech, mode, &error);
2643
2644	if (rv == CRYPTO_NOT_SUPPORTED) {
2645		allocated_by_crypto_module = B_TRUE;
2646		if (!copyin_mech(mode, sp, STRUCT_FADDR(encrypt_init, ei_mech),
2647		    &mech, &mech_rctl_bytes, &mech_rctl_chk, &rv, &error)) {
2648			goto out;
2649		}
2650	} else {
2651		if (rv != CRYPTO_SUCCESS)
2652			goto out;
2653	}
2654
2655	if (!copyin_key(mode, sp, STRUCT_FADDR(encrypt_init, ei_key), &key,
2656	    &key_rctl_bytes, &key_rctl_chk, &rv, &error)) {
2657		goto out;
2658	}
2659
2660	rv = (init)(real_provider, sp->sd_provider_session->ps_session,
2661	    &mech, &key, NULL, &cc, NULL);
2662
2663	/*
2664	 * Check if a context already exists. If so, it means it is being
2665	 * abandoned. So, cancel it to avoid leaking it.
2666	 */
2667	ctxpp = (init == crypto_encrypt_init_prov) ?
2668	    &sp->sd_encr_ctx : &sp->sd_decr_ctx;
2669
2670	if (*ctxpp != NULL)
2671		CRYPTO_CANCEL_CTX(ctxpp);
2672	*ctxpp = (rv == CRYPTO_SUCCESS) ? cc : NULL;
2673
2674out:
2675	CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
2676	CRYPTO_DECREMENT_RCTL_SESSION(sp, key_rctl_bytes, key_rctl_chk);
2677	CRYPTO_SESSION_RELE(sp);
2678	crypto_release_minor(cm);
2679
2680	if (real_provider != NULL) {
2681		crypto_free_mech(real_provider,
2682		    allocated_by_crypto_module, &mech);
2683		KCF_PROV_REFRELE(real_provider);
2684	}
2685
2686	free_crypto_key(&key);
2687
2688	if (error != 0)
2689		/* XXX free context */
2690		return (error);
2691
2692	STRUCT_FSET(encrypt_init, ei_return_value, rv);
2693	if (copyout(STRUCT_BUF(encrypt_init), arg,
2694	    STRUCT_SIZE(encrypt_init)) != 0) {
2695		/* XXX free context */
2696		return (EFAULT);
2697	}
2698	return (0);
2699}
2700
2701/* ARGSUSED */
2702static int
2703encrypt(dev_t dev, caddr_t arg, int mode, int *rval)
2704{
2705	return (cipher(dev, arg, mode, crypto_encrypt_single));
2706}
2707
2708/* ARGSUSED */
2709static int
2710decrypt(dev_t dev, caddr_t arg, int mode, int *rval)
2711{
2712	return (cipher(dev, arg, mode, crypto_decrypt_single));
2713}
2714
2715/*
2716 * ASSUMPTION: crypto_encrypt and crypto_decrypt structures
2717 * are identical except for field names.
2718 */
2719static int
2720cipher(dev_t dev, caddr_t arg, int mode,
2721    int (*single)(crypto_context_t, crypto_data_t *, crypto_data_t *,
2722    crypto_call_req_t *))
2723{
2724	STRUCT_DECL(crypto_encrypt, encrypt);
2725	crypto_session_id_t session_id;
2726	crypto_minor_t *cm;
2727	crypto_session_data_t *sp = NULL;
2728	crypto_ctx_t **ctxpp;
2729	crypto_data_t data, encr;
2730	size_t datalen, encrlen, need = 0;
2731	boolean_t do_inplace;
2732	char *encrbuf;
2733	int error = 0;
2734	int rv;
2735	boolean_t rctl_chk = B_FALSE;
2736
2737	STRUCT_INIT(encrypt, mode);
2738
2739	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
2740		cmn_err(CE_WARN, "cipher: failed holding minor");
2741		return (ENXIO);
2742	}
2743
2744	if (copyin(arg, STRUCT_BUF(encrypt), STRUCT_SIZE(encrypt)) != 0) {
2745		crypto_release_minor(cm);
2746		return (EFAULT);
2747	}
2748
2749	data.cd_raw.iov_base = NULL;
2750	encr.cd_raw.iov_base = NULL;
2751
2752	datalen = STRUCT_FGET(encrypt, ce_datalen);
2753	encrlen = STRUCT_FGET(encrypt, ce_encrlen);
2754
2755	/*
2756	 * Don't allocate output buffer unless both buffer pointer and
2757	 * buffer length are not NULL or 0 (length).
2758	 */
2759	encrbuf = STRUCT_FGETP(encrypt, ce_encrbuf);
2760	if (encrbuf == NULL || encrlen == 0) {
2761		encrlen = 0;
2762	}
2763
2764	if (datalen > crypto_max_buffer_len ||
2765	    encrlen > crypto_max_buffer_len) {
2766		cmn_err(CE_NOTE, "cipher: buffer greater than %ld bytes, "
2767		    "pid = %d", crypto_max_buffer_len, curproc->p_pid);
2768		rv = CRYPTO_ARGUMENTS_BAD;
2769		goto release_minor;
2770	}
2771
2772	session_id = STRUCT_FGET(encrypt, ce_session);
2773
2774	if (!get_session_ptr(session_id, cm, &sp, &error, &rv))  {
2775		goto release_minor;
2776	}
2777
2778	do_inplace = (STRUCT_FGET(encrypt, ce_flags) &
2779	    CRYPTO_INPLACE_OPERATION) != 0;
2780	need = do_inplace ? datalen : datalen + encrlen;
2781
2782	if ((rv = CRYPTO_BUFFER_CHECK(sp, need, rctl_chk)) !=
2783	    CRYPTO_SUCCESS) {
2784		need = 0;
2785		goto release_minor;
2786	}
2787
2788	INIT_RAW_CRYPTO_DATA(data, datalen);
2789	data.cd_miscdata = NULL;
2790
2791	if (datalen != 0 && copyin(STRUCT_FGETP(encrypt, ce_databuf),
2792	    data.cd_raw.iov_base, datalen) != 0) {
2793		error = EFAULT;
2794		goto release_minor;
2795	}
2796
2797	if (do_inplace) {
2798		/* set out = in for in-place */
2799		encr = data;
2800	} else {
2801		INIT_RAW_CRYPTO_DATA(encr, encrlen);
2802	}
2803
2804	ctxpp = (single == crypto_encrypt_single) ?
2805	    &sp->sd_encr_ctx : &sp->sd_decr_ctx;
2806
2807	/* in-place is specified by setting output NULL */
2808	if (do_inplace)
2809		rv = (single)(*ctxpp, &encr, NULL, NULL);
2810	else
2811		rv = (single)(*ctxpp, &data, &encr, NULL);
2812	if (KCF_CONTEXT_DONE(rv))
2813		*ctxpp = NULL;
2814
2815	if (rv == CRYPTO_SUCCESS) {
2816		ASSERT(encr.cd_length <= encrlen);
2817		if (encr.cd_length != 0 && copyout(encr.cd_raw.iov_base,
2818		    encrbuf, encr.cd_length) != 0) {
2819			error = EFAULT;
2820			goto release_minor;
2821		}
2822		STRUCT_FSET(encrypt, ce_encrlen, encr.cd_length);
2823	}
2824
2825	if (rv == CRYPTO_BUFFER_TOO_SMALL) {
2826		/*
2827		 * The providers return CRYPTO_BUFFER_TOO_SMALL even for case 1
2828		 * of section 11.2 of the pkcs11 spec. We catch it here and
2829		 * provide the correct pkcs11 return value.
2830		 */
2831		if (STRUCT_FGETP(encrypt, ce_encrbuf) == NULL)
2832			rv = CRYPTO_SUCCESS;
2833		STRUCT_FSET(encrypt, ce_encrlen, encr.cd_length);
2834	}
2835
2836release_minor:
2837	CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
2838	CRYPTO_SESSION_RELE(sp);
2839	crypto_release_minor(cm);
2840
2841	if (data.cd_raw.iov_base != NULL)
2842		kmem_free(data.cd_raw.iov_base, datalen);
2843
2844	if (!do_inplace && encr.cd_raw.iov_base != NULL)
2845		kmem_free(encr.cd_raw.iov_base, encrlen);
2846
2847	if (error != 0)
2848		return (error);
2849
2850	STRUCT_FSET(encrypt, ce_return_value, rv);
2851	if (copyout(STRUCT_BUF(encrypt), arg, STRUCT_SIZE(encrypt)) != 0) {
2852		return (EFAULT);
2853	}
2854	return (0);
2855}
2856
2857/* ARGSUSED */
2858static int
2859encrypt_update(dev_t dev, caddr_t arg, int mode, int *rval)
2860{
2861	return (cipher_update(dev, arg, mode, crypto_encrypt_update));
2862}
2863
2864/* ARGSUSED */
2865static int
2866decrypt_update(dev_t dev, caddr_t arg, int mode, int *rval)
2867{
2868	return (cipher_update(dev, arg, mode, crypto_decrypt_update));
2869}
2870
2871/*
2872 * ASSUMPTION: crypto_encrypt_update and crypto_decrypt_update
2873 * structures are identical except for field names.
2874 */
2875static int
2876cipher_update(dev_t dev, caddr_t arg, int mode,
2877    int (*update)(crypto_context_t, crypto_data_t *, crypto_data_t *,
2878    crypto_call_req_t *))
2879{
2880	STRUCT_DECL(crypto_encrypt_update, encrypt_update);
2881	crypto_session_id_t session_id;
2882	crypto_minor_t *cm;
2883	crypto_session_data_t *sp = NULL;
2884	crypto_ctx_t **ctxpp;
2885	crypto_data_t data, encr;
2886	size_t datalen, encrlen, need = 0;
2887	char *encrbuf;
2888	int error = 0;
2889	int rv;
2890	boolean_t rctl_chk = B_FALSE;
2891
2892	STRUCT_INIT(encrypt_update, mode);
2893
2894	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
2895		cmn_err(CE_WARN, "cipher_update: failed holding minor");
2896		return (ENXIO);
2897	}
2898
2899	if (copyin(arg, STRUCT_BUF(encrypt_update),
2900	    STRUCT_SIZE(encrypt_update)) != 0) {
2901		crypto_release_minor(cm);
2902		return (EFAULT);
2903	}
2904
2905	data.cd_raw.iov_base = NULL;
2906	encr.cd_raw.iov_base = NULL;
2907
2908	datalen = STRUCT_FGET(encrypt_update, eu_datalen);
2909	encrlen = STRUCT_FGET(encrypt_update, eu_encrlen);
2910
2911	/*
2912	 * Don't allocate output buffer unless both buffer pointer and
2913	 * buffer length are not NULL or 0 (length).
2914	 */
2915	encrbuf = STRUCT_FGETP(encrypt_update, eu_encrbuf);
2916	if (encrbuf == NULL || encrlen == 0) {
2917		encrlen = 0;
2918	}
2919
2920	if (datalen > crypto_max_buffer_len ||
2921	    encrlen > crypto_max_buffer_len) {
2922		cmn_err(CE_NOTE, "cipher_update: buffer greater than %ld "
2923		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
2924		rv = CRYPTO_ARGUMENTS_BAD;
2925		goto out;
2926	}
2927
2928	session_id = STRUCT_FGET(encrypt_update, eu_session);
2929
2930	if (!get_session_ptr(session_id, cm, &sp, &error, &rv))  {
2931		goto out;
2932	}
2933
2934	need = datalen + encrlen;
2935
2936	if ((rv = CRYPTO_BUFFER_CHECK(sp, need, rctl_chk)) !=
2937	    CRYPTO_SUCCESS) {
2938		need = 0;
2939		goto out;
2940	}
2941
2942	INIT_RAW_CRYPTO_DATA(data, datalen);
2943	data.cd_miscdata = NULL;
2944
2945	if (datalen != 0 && copyin(STRUCT_FGETP(encrypt_update, eu_databuf),
2946	    data.cd_raw.iov_base, datalen) != 0) {
2947		error = EFAULT;
2948		goto out;
2949	}
2950
2951	INIT_RAW_CRYPTO_DATA(encr, encrlen);
2952
2953	ctxpp = (update == crypto_encrypt_update) ?
2954	    &sp->sd_encr_ctx : &sp->sd_decr_ctx;
2955
2956	rv = (update)(*ctxpp, &data, &encr, NULL);
2957
2958	if (rv == CRYPTO_SUCCESS || rv == CRYPTO_BUFFER_TOO_SMALL) {
2959		if (rv == CRYPTO_SUCCESS) {
2960			ASSERT(encr.cd_length <= encrlen);
2961			if (encr.cd_length != 0 && copyout(encr.cd_raw.iov_base,
2962			    encrbuf, encr.cd_length) != 0) {
2963				error = EFAULT;
2964				goto out;
2965			}
2966		} else {
2967			/*
2968			 * The providers return CRYPTO_BUFFER_TOO_SMALL even
2969			 * for case 1 of section 11.2 of the pkcs11 spec.
2970			 * We catch it here and provide the correct pkcs11
2971			 * return value.
2972			 */
2973			if (STRUCT_FGETP(encrypt_update, eu_encrbuf) == NULL)
2974				rv = CRYPTO_SUCCESS;
2975		}
2976		STRUCT_FSET(encrypt_update, eu_encrlen, encr.cd_length);
2977	} else {
2978		CRYPTO_CANCEL_CTX(ctxpp);
2979	}
2980out:
2981	CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
2982	CRYPTO_SESSION_RELE(sp);
2983	crypto_release_minor(cm);
2984
2985	if (data.cd_raw.iov_base != NULL)
2986		kmem_free(data.cd_raw.iov_base, datalen);
2987
2988	if (encr.cd_raw.iov_base != NULL)
2989		kmem_free(encr.cd_raw.iov_base, encrlen);
2990
2991	if (error != 0)
2992		return (error);
2993
2994	STRUCT_FSET(encrypt_update, eu_return_value, rv);
2995	if (copyout(STRUCT_BUF(encrypt_update), arg,
2996	    STRUCT_SIZE(encrypt_update)) != 0) {
2997		return (EFAULT);
2998	}
2999	return (0);
3000}
3001
3002/* ARGSUSED */
3003static int
3004encrypt_final(dev_t dev, caddr_t arg, int mode, int *rval)
3005{
3006	return (common_final(dev, arg, mode, crypto_encrypt_final));
3007}
3008
3009/* ARGSUSED */
3010static int
3011decrypt_final(dev_t dev, caddr_t arg, int mode, int *rval)
3012{
3013	return (common_final(dev, arg, mode, crypto_decrypt_final));
3014}
3015
3016/*
3017 * ASSUMPTION: crypto_encrypt_final, crypto_decrypt_final, crypto_sign_final,
3018 * and crypto_digest_final structures are identical except for field names.
3019 */
3020static int
3021common_final(dev_t dev, caddr_t arg, int mode,
3022    int (*final)(crypto_context_t, crypto_data_t *, crypto_call_req_t *))
3023{
3024	STRUCT_DECL(crypto_encrypt_final, encrypt_final);
3025	crypto_session_id_t session_id;
3026	crypto_minor_t *cm;
3027	crypto_session_data_t *sp = NULL;
3028	crypto_ctx_t **ctxpp;
3029	crypto_data_t encr;
3030	size_t encrlen, need = 0;
3031	char *encrbuf;
3032	int error = 0;
3033	int rv;
3034	boolean_t rctl_chk = B_FALSE;
3035
3036	STRUCT_INIT(encrypt_final, mode);
3037
3038	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3039		cmn_err(CE_WARN, "common_final: failed holding minor");
3040		return (ENXIO);
3041	}
3042
3043	if (copyin(arg, STRUCT_BUF(encrypt_final),
3044	    STRUCT_SIZE(encrypt_final)) != 0) {
3045		crypto_release_minor(cm);
3046		return (EFAULT);
3047	}
3048
3049	encr.cd_format = CRYPTO_DATA_RAW;
3050	encr.cd_raw.iov_base = NULL;
3051
3052	encrlen = STRUCT_FGET(encrypt_final, ef_encrlen);
3053
3054	/*
3055	 * Don't allocate output buffer unless both buffer pointer and
3056	 * buffer length are not NULL or 0 (length).
3057	 */
3058	encrbuf = STRUCT_FGETP(encrypt_final, ef_encrbuf);
3059	if (encrbuf == NULL || encrlen == 0) {
3060		encrlen = 0;
3061	}
3062
3063	if (encrlen > crypto_max_buffer_len) {
3064		cmn_err(CE_NOTE, "common_final: buffer greater than %ld "
3065		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
3066		rv = CRYPTO_ARGUMENTS_BAD;
3067		goto release_minor;
3068	}
3069
3070	session_id = STRUCT_FGET(encrypt_final, ef_session);
3071
3072	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
3073		goto release_minor;
3074	}
3075
3076	if ((rv = CRYPTO_BUFFER_CHECK(sp, encrlen, rctl_chk)) !=
3077	    CRYPTO_SUCCESS) {
3078		goto release_minor;
3079	}
3080	need = encrlen;
3081	encr.cd_raw.iov_base = kmem_alloc(encrlen, KM_SLEEP);
3082	encr.cd_raw.iov_len = encrlen;
3083
3084	encr.cd_offset = 0;
3085	encr.cd_length = encrlen;
3086
3087	ASSERT(final == crypto_encrypt_final ||
3088	    final == crypto_decrypt_final || final == crypto_sign_final ||
3089	    final == crypto_digest_final);
3090
3091	if (final == crypto_encrypt_final) {
3092		ctxpp = &sp->sd_encr_ctx;
3093	} else if (final == crypto_decrypt_final) {
3094		ctxpp = &sp->sd_decr_ctx;
3095	} else if (final == crypto_sign_final) {
3096		ctxpp = &sp->sd_sign_ctx;
3097	} else {
3098		ctxpp = &sp->sd_digest_ctx;
3099	}
3100
3101	rv = (final)(*ctxpp, &encr, NULL);
3102	if (KCF_CONTEXT_DONE(rv))
3103		*ctxpp = NULL;
3104
3105	if (rv == CRYPTO_SUCCESS) {
3106		ASSERT(encr.cd_length <= encrlen);
3107		if (encr.cd_length != 0 && copyout(encr.cd_raw.iov_base,
3108		    encrbuf, encr.cd_length) != 0) {
3109			error = EFAULT;
3110			goto release_minor;
3111		}
3112		STRUCT_FSET(encrypt_final, ef_encrlen, encr.cd_length);
3113	}
3114
3115	if (rv == CRYPTO_BUFFER_TOO_SMALL) {
3116		/*
3117		 * The providers return CRYPTO_BUFFER_TOO_SMALL even for case 1
3118		 * of section 11.2 of the pkcs11 spec. We catch it here and
3119		 * provide the correct pkcs11 return value.
3120		 */
3121		if (STRUCT_FGETP(encrypt_final, ef_encrbuf) == NULL)
3122			rv = CRYPTO_SUCCESS;
3123		STRUCT_FSET(encrypt_final, ef_encrlen, encr.cd_length);
3124	}
3125
3126release_minor:
3127	CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
3128	CRYPTO_SESSION_RELE(sp);
3129	crypto_release_minor(cm);
3130
3131	if (encr.cd_raw.iov_base != NULL)
3132		kmem_free(encr.cd_raw.iov_base, encrlen);
3133
3134	if (error != 0)
3135		return (error);
3136
3137	STRUCT_FSET(encrypt_final, ef_return_value, rv);
3138	if (copyout(STRUCT_BUF(encrypt_final), arg,
3139	    STRUCT_SIZE(encrypt_final)) != 0) {
3140		return (EFAULT);
3141	}
3142	return (0);
3143}
3144
3145/* ARGSUSED */
3146static int
3147digest_init(dev_t dev, caddr_t arg, int mode, int *rval)
3148{
3149	STRUCT_DECL(crypto_digest_init, digest_init);
3150	kcf_provider_desc_t *real_provider = NULL;
3151	crypto_session_id_t session_id;
3152	crypto_mechanism_t mech;
3153	crypto_minor_t *cm;
3154	crypto_session_data_t *sp = NULL;
3155	crypto_context_t cc;
3156	size_t rctl_bytes = 0;
3157	boolean_t rctl_chk = B_FALSE;
3158	int error = 0;
3159	int rv;
3160
3161	STRUCT_INIT(digest_init, mode);
3162
3163	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3164		cmn_err(CE_WARN, "digest_init: failed holding minor");
3165		return (ENXIO);
3166	}
3167
3168	if (copyin(arg, STRUCT_BUF(digest_init),
3169	    STRUCT_SIZE(digest_init)) != 0) {
3170		crypto_release_minor(cm);
3171		return (EFAULT);
3172	}
3173
3174	mech.cm_param = NULL;
3175
3176	session_id = STRUCT_FGET(digest_init, di_session);
3177
3178	if (!get_session_ptr(session_id, cm, &sp, &error, &rv))  {
3179		goto out;
3180	}
3181
3182	if (!copyin_mech(mode, sp, STRUCT_FADDR(digest_init, di_mech), &mech,
3183	    &rctl_bytes, &rctl_chk, &rv, &error)) {
3184		goto out;
3185	}
3186
3187	if ((rv = kcf_get_hardware_provider(mech.cm_type, CRYPTO_MECH_INVALID,
3188	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider,
3189	    CRYPTO_FG_DIGEST)) != CRYPTO_SUCCESS) {
3190		goto out;
3191	}
3192
3193	rv = crypto_digest_init_prov(real_provider,
3194	    sp->sd_provider_session->ps_session, &mech, &cc, NULL);
3195
3196	/*
3197	 * Check if a context already exists. If so, it means it is being
3198	 * abandoned. So, cancel it to avoid leaking it.
3199	 */
3200	if (sp->sd_digest_ctx != NULL)
3201		CRYPTO_CANCEL_CTX(&sp->sd_digest_ctx);
3202	sp->sd_digest_ctx = (rv == CRYPTO_SUCCESS) ? cc : NULL;
3203out:
3204	CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, rctl_chk);
3205	CRYPTO_SESSION_RELE(sp);
3206	crypto_release_minor(cm);
3207
3208	if (real_provider != NULL)
3209		KCF_PROV_REFRELE(real_provider);
3210
3211	if (mech.cm_param != NULL)
3212		kmem_free(mech.cm_param, mech.cm_param_len);
3213
3214	if (error != 0)
3215		return (error);
3216
3217	STRUCT_FSET(digest_init, di_return_value, rv);
3218	if (copyout(STRUCT_BUF(digest_init), arg,
3219	    STRUCT_SIZE(digest_init)) != 0) {
3220		return (EFAULT);
3221	}
3222	return (0);
3223}
3224
3225/* ARGSUSED */
3226static int
3227digest_update(dev_t dev, caddr_t arg, int mode, int *rval)
3228{
3229	STRUCT_DECL(crypto_digest_update, digest_update);
3230	crypto_session_id_t session_id;
3231	crypto_minor_t *cm;
3232	crypto_session_data_t *sp = NULL;
3233	crypto_data_t data;
3234	size_t datalen, need = 0;
3235	int error = 0;
3236	int rv;
3237	boolean_t rctl_chk = B_FALSE;
3238
3239	STRUCT_INIT(digest_update, mode);
3240
3241	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3242		cmn_err(CE_WARN, "digest_update: failed holding minor");
3243		return (ENXIO);
3244	}
3245
3246	if (copyin(arg, STRUCT_BUF(digest_update),
3247	    STRUCT_SIZE(digest_update)) != 0) {
3248		crypto_release_minor(cm);
3249		return (EFAULT);
3250	}
3251
3252	data.cd_format = CRYPTO_DATA_RAW;
3253	data.cd_raw.iov_base = NULL;
3254
3255	datalen = STRUCT_FGET(digest_update, du_datalen);
3256	if (datalen > crypto_max_buffer_len) {
3257		cmn_err(CE_NOTE, "digest_update: buffer greater than %ld "
3258		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
3259		rv = CRYPTO_ARGUMENTS_BAD;
3260		goto release_minor;
3261	}
3262
3263	session_id = STRUCT_FGET(digest_update, du_session);
3264
3265	if (!get_session_ptr(session_id, cm, &sp, &error, &rv))  {
3266		goto release_minor;
3267	}
3268
3269	if ((rv = CRYPTO_BUFFER_CHECK(sp, datalen, rctl_chk)) !=
3270	    CRYPTO_SUCCESS) {
3271		goto release_minor;
3272	}
3273
3274	need = datalen;
3275	data.cd_raw.iov_base = kmem_alloc(datalen, KM_SLEEP);
3276	data.cd_raw.iov_len = datalen;
3277
3278	if (datalen != 0 && copyin(STRUCT_FGETP(digest_update, du_databuf),
3279	    data.cd_raw.iov_base, datalen) != 0) {
3280		error = EFAULT;
3281		goto release_minor;
3282	}
3283
3284	data.cd_offset = 0;
3285	data.cd_length = datalen;
3286
3287	rv = crypto_digest_update(sp->sd_digest_ctx, &data, NULL);
3288	if (rv != CRYPTO_SUCCESS)
3289		CRYPTO_CANCEL_CTX(&sp->sd_digest_ctx);
3290
3291release_minor:
3292	CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
3293	CRYPTO_SESSION_RELE(sp);
3294	crypto_release_minor(cm);
3295
3296	if (data.cd_raw.iov_base != NULL)
3297		kmem_free(data.cd_raw.iov_base, datalen);
3298
3299	if (error != 0)
3300		return (error);
3301
3302	STRUCT_FSET(digest_update, du_return_value, rv);
3303	if (copyout(STRUCT_BUF(digest_update), arg,
3304	    STRUCT_SIZE(digest_update)) != 0) {
3305		return (EFAULT);
3306	}
3307	return (0);
3308}
3309
3310/* ARGSUSED */
3311static int
3312digest_key(dev_t dev, caddr_t arg, int mode, int *rval)
3313{
3314	STRUCT_DECL(crypto_digest_key, digest_key);
3315	crypto_session_id_t session_id;
3316	crypto_key_t key;
3317	crypto_minor_t *cm;
3318	crypto_session_data_t *sp = NULL;
3319	size_t rctl_bytes = 0;
3320	boolean_t key_rctl_chk = B_FALSE;
3321	int error = 0;
3322	int rv;
3323
3324	STRUCT_INIT(digest_key, mode);
3325
3326	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3327		cmn_err(CE_WARN, "digest_key: failed holding minor");
3328		return (ENXIO);
3329	}
3330
3331	if (copyin(arg, STRUCT_BUF(digest_key), STRUCT_SIZE(digest_key)) != 0) {
3332		crypto_release_minor(cm);
3333		return (EFAULT);
3334	}
3335
3336	bzero(&key, sizeof (crypto_key_t));
3337
3338	session_id = STRUCT_FGET(digest_key, dk_session);
3339
3340	if (!get_session_ptr(session_id, cm, &sp, &error, &rv))  {
3341		goto out;
3342	}
3343
3344	if (!copyin_key(mode, sp, STRUCT_FADDR(digest_key, dk_key), &key,
3345	    &rctl_bytes, &key_rctl_chk, &rv, &error)) {
3346		goto out;
3347	}
3348
3349	rv = crypto_digest_key_prov(sp->sd_digest_ctx, &key, NULL);
3350	if (rv != CRYPTO_SUCCESS)
3351		CRYPTO_CANCEL_CTX(&sp->sd_digest_ctx);
3352out:
3353	CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, key_rctl_chk);
3354	CRYPTO_SESSION_RELE(sp);
3355	crypto_release_minor(cm);
3356
3357	free_crypto_key(&key);
3358
3359	if (error != 0)
3360		return (error);
3361
3362	STRUCT_FSET(digest_key, dk_return_value, rv);
3363	if (copyout(STRUCT_BUF(digest_key), arg,
3364	    STRUCT_SIZE(digest_key)) != 0) {
3365		return (EFAULT);
3366	}
3367	return (0);
3368}
3369
3370/* ARGSUSED */
3371static int
3372digest_final(dev_t dev, caddr_t arg, int mode, int *rval)
3373{
3374	return (common_final(dev, arg, mode, crypto_digest_final));
3375}
3376
3377/* ARGSUSED */
3378static int
3379digest(dev_t dev, caddr_t arg, int mode, int *rval)
3380{
3381	return (common_digest(dev, arg, mode, crypto_digest_single));
3382}
3383
3384/*
3385 * ASSUMPTION: crypto_digest, crypto_sign, crypto_sign_recover,
3386 * and crypto_verify_recover are identical except for field names.
3387 */
3388static int
3389common_digest(dev_t dev, caddr_t arg, int mode,
3390    int (*single)(crypto_context_t, crypto_data_t *, crypto_data_t *,
3391    crypto_call_req_t *))
3392{
3393	STRUCT_DECL(crypto_digest, crypto_digest);
3394	crypto_session_id_t session_id;
3395	crypto_minor_t *cm;
3396	crypto_session_data_t *sp = NULL;
3397	crypto_data_t data, digest;
3398	crypto_ctx_t **ctxpp;
3399	size_t datalen, digestlen, need = 0;
3400	char *digestbuf;
3401	int error = 0;
3402	int rv;
3403	boolean_t rctl_chk = B_FALSE;
3404
3405	STRUCT_INIT(crypto_digest, mode);
3406
3407	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3408		cmn_err(CE_WARN, "common_digest: failed holding minor");
3409		return (ENXIO);
3410	}
3411
3412	if (copyin(arg, STRUCT_BUF(crypto_digest),
3413	    STRUCT_SIZE(crypto_digest)) != 0) {
3414		crypto_release_minor(cm);
3415		return (EFAULT);
3416	}
3417
3418	data.cd_raw.iov_base = NULL;
3419	digest.cd_raw.iov_base = NULL;
3420
3421	datalen = STRUCT_FGET(crypto_digest, cd_datalen);
3422	digestlen = STRUCT_FGET(crypto_digest, cd_digestlen);
3423
3424	/*
3425	 * Don't allocate output buffer unless both buffer pointer and
3426	 * buffer length are not NULL or 0 (length).
3427	 */
3428	digestbuf = STRUCT_FGETP(crypto_digest, cd_digestbuf);
3429	if (digestbuf == NULL || digestlen == 0) {
3430		digestlen = 0;
3431	}
3432
3433	if (datalen > crypto_max_buffer_len ||
3434	    digestlen > crypto_max_buffer_len) {
3435		cmn_err(CE_NOTE, "common_digest: buffer greater than %ld "
3436		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
3437		rv = CRYPTO_ARGUMENTS_BAD;
3438		goto release_minor;
3439	}
3440
3441	session_id = STRUCT_FGET(crypto_digest, cd_session);
3442
3443	if (!get_session_ptr(session_id, cm, &sp, &error, &rv))  {
3444		goto release_minor;
3445	}
3446
3447	need = datalen + digestlen;
3448	if ((rv = CRYPTO_BUFFER_CHECK(sp, need, rctl_chk)) !=
3449	    CRYPTO_SUCCESS) {
3450		need = 0;
3451		goto release_minor;
3452	}
3453
3454	INIT_RAW_CRYPTO_DATA(data, datalen);
3455
3456	if (datalen != 0 && copyin(STRUCT_FGETP(crypto_digest, cd_databuf),
3457	    data.cd_raw.iov_base, datalen) != 0) {
3458		error = EFAULT;
3459		goto release_minor;
3460	}
3461
3462	INIT_RAW_CRYPTO_DATA(digest, digestlen);
3463
3464	ASSERT(single == crypto_digest_single ||
3465	    single == crypto_sign_single ||
3466	    single == crypto_verify_recover_single ||
3467	    single == crypto_sign_recover_single);
3468
3469	if (single == crypto_digest_single) {
3470		ctxpp = &sp->sd_digest_ctx;
3471	} else if (single == crypto_sign_single) {
3472		ctxpp = &sp->sd_sign_ctx;
3473	} else if (single == crypto_verify_recover_single) {
3474		ctxpp = &sp->sd_verify_recover_ctx;
3475	} else {
3476		ctxpp = &sp->sd_sign_recover_ctx;
3477	}
3478	rv = (single)(*ctxpp, &data, &digest, NULL);
3479	if (KCF_CONTEXT_DONE(rv))
3480		*ctxpp = NULL;
3481
3482	if (rv == CRYPTO_SUCCESS) {
3483		ASSERT(digest.cd_length <= digestlen);
3484		if (digest.cd_length != 0 && copyout(digest.cd_raw.iov_base,
3485		    digestbuf, digest.cd_length) != 0) {
3486			error = EFAULT;
3487			goto release_minor;
3488		}
3489		STRUCT_FSET(crypto_digest, cd_digestlen, digest.cd_length);
3490	}
3491
3492	if (rv == CRYPTO_BUFFER_TOO_SMALL) {
3493		/*
3494		 * The providers return CRYPTO_BUFFER_TOO_SMALL even for case 1
3495		 * of section 11.2 of the pkcs11 spec. We catch it here and
3496		 * provide the correct pkcs11 return value.
3497		 */
3498		if (STRUCT_FGETP(crypto_digest, cd_digestbuf) == NULL)
3499			rv = CRYPTO_SUCCESS;
3500		STRUCT_FSET(crypto_digest, cd_digestlen, digest.cd_length);
3501	}
3502
3503release_minor:
3504	CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
3505	CRYPTO_SESSION_RELE(sp);
3506	crypto_release_minor(cm);
3507
3508	if (data.cd_raw.iov_base != NULL)
3509		kmem_free(data.cd_raw.iov_base, datalen);
3510
3511	if (digest.cd_raw.iov_base != NULL)
3512		kmem_free(digest.cd_raw.iov_base, digestlen);
3513
3514	if (error != 0)
3515		return (error);
3516
3517	STRUCT_FSET(crypto_digest, cd_return_value, rv);
3518	if (copyout(STRUCT_BUF(crypto_digest), arg,
3519	    STRUCT_SIZE(crypto_digest)) != 0) {
3520		return (EFAULT);
3521	}
3522	return (0);
3523}
3524
3525/*
3526 * A helper function that does what the name suggests.
3527 * Returns 0 on success and non-zero otherwise.
3528 * On failure, out_pin is set to 0.
3529 */
3530int
3531get_pin_and_session_ptr(char *in_pin, char **out_pin, size_t pin_len,
3532    crypto_minor_t *cm, crypto_session_id_t sid, crypto_session_data_t **sp,
3533    int *rv, int *error)
3534{
3535	char *tmp_pin = NULL;
3536	int tmp_error = 0, tmp_rv = 0;
3537
3538	if (pin_len > KCF_MAX_PIN_LEN) {
3539		tmp_rv = CRYPTO_PIN_LEN_RANGE;
3540		goto out;
3541	}
3542	tmp_pin = kmem_alloc(pin_len, KM_SLEEP);
3543
3544	if (pin_len != 0 && copyin(in_pin, tmp_pin, pin_len) != 0) {
3545		tmp_error = EFAULT;
3546		goto out;
3547	}
3548
3549	(void) get_session_ptr(sid, cm, sp, &tmp_error, &tmp_rv);
3550out:
3551	*out_pin = tmp_pin;
3552	*rv = tmp_rv;
3553	*error = tmp_error;
3554	return (tmp_rv | tmp_error);
3555}
3556
3557/* ARGSUSED */
3558static int
3559set_pin(dev_t dev, caddr_t arg, int mode, int *rval)
3560{
3561	STRUCT_DECL(crypto_set_pin, set_pin);
3562	kcf_provider_desc_t *real_provider;
3563	kcf_req_params_t params;
3564	crypto_minor_t *cm;
3565	crypto_session_data_t *sp;
3566	char *old_pin = NULL;
3567	char *new_pin = NULL;
3568	size_t old_pin_len;
3569	size_t new_pin_len;
3570	int error = 0;
3571	int rv;
3572
3573	STRUCT_INIT(set_pin, mode);
3574
3575	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3576		cmn_err(CE_WARN, "set_pin: failed holding minor");
3577		return (ENXIO);
3578	}
3579
3580	if (copyin(arg, STRUCT_BUF(set_pin),
3581	    STRUCT_SIZE(set_pin)) != 0) {
3582		crypto_release_minor(cm);
3583		return (EFAULT);
3584	}
3585
3586	old_pin_len = STRUCT_FGET(set_pin, sp_old_len);
3587
3588	if (get_pin_and_session_ptr(STRUCT_FGETP(set_pin, sp_old_pin),
3589	    &old_pin, old_pin_len, cm, STRUCT_FGET(set_pin, sp_session),
3590	    &sp, &rv, &error) != 0)
3591		goto release_minor;
3592
3593	new_pin_len = STRUCT_FGET(set_pin, sp_new_len);
3594	if (new_pin_len > KCF_MAX_PIN_LEN) {
3595		rv = CRYPTO_PIN_LEN_RANGE;
3596		goto out;
3597	}
3598	new_pin = kmem_alloc(new_pin_len, KM_SLEEP);
3599
3600	if (new_pin_len != 0 && copyin(STRUCT_FGETP(set_pin, sp_new_pin),
3601	    new_pin, new_pin_len) != 0) {
3602		error = EFAULT;
3603		goto out;
3604	}
3605
3606	if ((rv = kcf_get_hardware_provider_nomech(
3607	    CRYPTO_OPS_OFFSET(provider_ops), CRYPTO_PROVIDER_OFFSET(set_pin),
3608	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider))
3609	    != CRYPTO_SUCCESS) {
3610		goto out;
3611	}
3612
3613	KCF_WRAP_PROVMGMT_OPS_PARAMS(&params, KCF_OP_MGMT_SETPIN,
3614	    sp->sd_provider_session->ps_session, old_pin, old_pin_len,
3615	    new_pin, new_pin_len, NULL, NULL, real_provider);
3616
3617	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
3618	KCF_PROV_REFRELE(real_provider);
3619
3620out:
3621	CRYPTO_SESSION_RELE(sp);
3622
3623release_minor:
3624	crypto_release_minor(cm);
3625
3626	if (old_pin != NULL) {
3627		bzero(old_pin, old_pin_len);
3628		kmem_free(old_pin, old_pin_len);
3629	}
3630
3631	if (new_pin != NULL) {
3632		bzero(new_pin, new_pin_len);
3633		kmem_free(new_pin, new_pin_len);
3634	}
3635
3636	if (error != 0)
3637		return (error);
3638
3639	STRUCT_FSET(set_pin, sp_return_value, rv);
3640	if (copyout(STRUCT_BUF(set_pin), arg, STRUCT_SIZE(set_pin)) != 0) {
3641		return (EFAULT);
3642	}
3643	return (0);
3644}
3645
3646/* ARGSUSED */
3647static int
3648login(dev_t dev, caddr_t arg, int mode, int *rval)
3649{
3650	STRUCT_DECL(crypto_login, login);
3651	kcf_provider_desc_t *real_provider;
3652	kcf_req_params_t params;
3653	crypto_minor_t *cm;
3654	crypto_session_data_t *sp;
3655	size_t pin_len;
3656	char *pin;
3657	uint_t user_type;
3658	int error = 0;
3659	int rv;
3660
3661	STRUCT_INIT(login, mode);
3662
3663	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3664		cmn_err(CE_WARN, "login: failed holding minor");
3665		return (ENXIO);
3666	}
3667
3668	if (copyin(arg, STRUCT_BUF(login), STRUCT_SIZE(login)) != 0) {
3669		crypto_release_minor(cm);
3670		return (EFAULT);
3671	}
3672
3673	user_type = STRUCT_FGET(login, co_user_type);
3674
3675	pin_len = STRUCT_FGET(login, co_pin_len);
3676
3677	if (get_pin_and_session_ptr(STRUCT_FGETP(login, co_pin),
3678	    &pin, pin_len, cm, STRUCT_FGET(login, co_session),
3679	    &sp, &rv, &error) != 0) {
3680		if (rv == CRYPTO_PIN_LEN_RANGE)
3681			rv = CRYPTO_PIN_INCORRECT;
3682		goto release_minor;
3683	}
3684
3685	if ((rv = kcf_get_hardware_provider_nomech(
3686	    CRYPTO_OPS_OFFSET(session_ops),
3687	    CRYPTO_SESSION_OFFSET(session_login),
3688	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider))
3689	    != CRYPTO_SUCCESS) {
3690		goto out;
3691	}
3692
3693	KCF_WRAP_SESSION_OPS_PARAMS(&params, KCF_OP_SESSION_LOGIN, NULL,
3694	    sp->sd_provider_session->ps_session, user_type, pin, pin_len,
3695	    real_provider);
3696
3697	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
3698	KCF_PROV_REFRELE(real_provider);
3699
3700out:
3701	CRYPTO_SESSION_RELE(sp);
3702
3703release_minor:
3704	crypto_release_minor(cm);
3705
3706	if (pin != NULL) {
3707		bzero(pin, pin_len);
3708		kmem_free(pin, pin_len);
3709	}
3710
3711	if (error != 0)
3712		return (error);
3713
3714	STRUCT_FSET(login, co_return_value, rv);
3715	if (copyout(STRUCT_BUF(login), arg, STRUCT_SIZE(login)) != 0) {
3716		return (EFAULT);
3717	}
3718	return (0);
3719}
3720
3721/* ARGSUSED */
3722static int
3723logout(dev_t dev, caddr_t arg, int mode, int *rval)
3724{
3725	crypto_logout_t logout;
3726	kcf_provider_desc_t *real_provider;
3727	kcf_req_params_t params;
3728	crypto_minor_t *cm;
3729	crypto_session_data_t *sp;
3730	int error = 0;
3731	int rv;
3732
3733	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3734		cmn_err(CE_WARN, "logout: failed holding minor");
3735		return (ENXIO);
3736	}
3737
3738	if (copyin(arg, &logout, sizeof (logout)) != 0) {
3739		crypto_release_minor(cm);
3740		return (EFAULT);
3741	}
3742
3743	if (!get_session_ptr(logout.cl_session, cm, &sp, &error, &rv))  {
3744		goto release_minor;
3745	}
3746
3747	if ((rv = kcf_get_hardware_provider_nomech(
3748	    CRYPTO_OPS_OFFSET(session_ops),
3749	    CRYPTO_SESSION_OFFSET(session_logout), CHECK_RESTRICT_FALSE,
3750	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
3751		goto out;
3752	}
3753
3754	KCF_WRAP_SESSION_OPS_PARAMS(&params, KCF_OP_SESSION_LOGOUT, NULL,
3755	    sp->sd_provider_session->ps_session, 0, NULL, 0, real_provider);
3756	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
3757	KCF_PROV_REFRELE(real_provider);
3758
3759out:
3760	CRYPTO_SESSION_RELE(sp);
3761
3762release_minor:
3763	crypto_release_minor(cm);
3764
3765	if (error != 0)
3766		return (error);
3767
3768	logout.cl_return_value = rv;
3769	if (copyout(&logout, arg, sizeof (logout)) != 0) {
3770		return (EFAULT);
3771	}
3772	return (0);
3773}
3774
3775/* ARGSUSED */
3776static int
3777sign_init(dev_t dev, caddr_t arg, int mode, int *rval)
3778{
3779	return (sign_verify_init(dev, arg, mode, crypto_sign_init_prov));
3780}
3781
3782/* ARGSUSED */
3783static int
3784sign_recover_init(dev_t dev, caddr_t arg, int mode, int *rval)
3785{
3786	return (sign_verify_init(dev, arg, mode,
3787	    crypto_sign_recover_init_prov));
3788}
3789
3790/* ARGSUSED */
3791static int
3792verify_init(dev_t dev, caddr_t arg, int mode, int *rval)
3793{
3794	return (sign_verify_init(dev, arg, mode, crypto_verify_init_prov));
3795}
3796
3797/* ARGSUSED */
3798static int
3799verify_recover_init(dev_t dev, caddr_t arg, int mode, int *rval)
3800{
3801	return (sign_verify_init(dev, arg, mode,
3802	    crypto_verify_recover_init_prov));
3803}
3804
3805/*
3806 * ASSUMPTION: crypto_sign_init, crypto_verify_init, crypto_sign_recover_init,
3807 * and crypto_verify_recover_init structures are identical
3808 * except for field names.
3809 */
3810static int
3811sign_verify_init(dev_t dev, caddr_t arg, int mode,
3812    int (*init)(crypto_provider_t, crypto_session_id_t,
3813    crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
3814    crypto_context_t *, crypto_call_req_t *))
3815{
3816	STRUCT_DECL(crypto_sign_init, sign_init);
3817	kcf_provider_desc_t *real_provider = NULL;
3818	crypto_session_id_t session_id;
3819	crypto_mechanism_t mech;
3820	crypto_key_t key;
3821	crypto_minor_t *cm;
3822	crypto_session_data_t *sp = NULL;
3823	crypto_context_t cc;
3824	crypto_ctx_t **ctxpp;
3825	size_t mech_rctl_bytes = 0;
3826	boolean_t mech_rctl_chk = B_FALSE;
3827	size_t key_rctl_bytes = 0;
3828	boolean_t key_rctl_chk = B_FALSE;
3829	int error = 0;
3830	int rv;
3831	boolean_t allocated_by_crypto_module = B_FALSE;
3832	crypto_func_group_t fg;
3833
3834	STRUCT_INIT(sign_init, mode);
3835
3836	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3837		cmn_err(CE_WARN, "sign_verify_init: failed holding minor");
3838		return (ENXIO);
3839	}
3840
3841	if (copyin(arg, STRUCT_BUF(sign_init), STRUCT_SIZE(sign_init)) != 0) {
3842		crypto_release_minor(cm);
3843		return (EFAULT);
3844	}
3845
3846	mech.cm_param = NULL;
3847	bzero(&key, sizeof (key));
3848
3849	session_id = STRUCT_FGET(sign_init, si_session);
3850
3851	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
3852		goto out;
3853	}
3854
3855	bcopy(STRUCT_FADDR(sign_init, si_mech), &mech.cm_type,
3856	    sizeof (crypto_mech_type_t));
3857
3858	ASSERT(init == crypto_sign_init_prov ||
3859	    init == crypto_verify_init_prov ||
3860	    init == crypto_sign_recover_init_prov ||
3861	    init == crypto_verify_recover_init_prov);
3862
3863	if (init == crypto_sign_init_prov) {
3864		fg =  CRYPTO_FG_SIGN;
3865		ctxpp = &sp->sd_sign_ctx;
3866	} else if (init == crypto_verify_init_prov) {
3867		fg =  CRYPTO_FG_VERIFY;
3868		ctxpp = &sp->sd_verify_ctx;
3869	} else if (init == crypto_sign_recover_init_prov) {
3870		fg =  CRYPTO_FG_SIGN_RECOVER;
3871		ctxpp = &sp->sd_sign_recover_ctx;
3872	} else {
3873		fg =  CRYPTO_FG_VERIFY_RECOVER;
3874		ctxpp = &sp->sd_verify_recover_ctx;
3875	}
3876
3877	if ((rv = kcf_get_hardware_provider(mech.cm_type, CRYPTO_MECH_INVALID,
3878	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider, fg))
3879	    != CRYPTO_SUCCESS) {
3880		goto out;
3881	}
3882
3883	rv = crypto_provider_copyin_mech_param(real_provider,
3884	    STRUCT_FADDR(sign_init, si_mech), &mech, mode, &error);
3885
3886	if (rv == CRYPTO_NOT_SUPPORTED) {
3887		allocated_by_crypto_module = B_TRUE;
3888		if (!copyin_mech(mode, sp, STRUCT_FADDR(sign_init, si_mech),
3889		    &mech, &mech_rctl_bytes, &mech_rctl_chk, &rv, &error)) {
3890			goto out;
3891		}
3892	} else {
3893		if (rv != CRYPTO_SUCCESS)
3894			goto out;
3895	}
3896
3897	if (!copyin_key(mode, sp, STRUCT_FADDR(sign_init, si_key), &key,
3898	    &key_rctl_bytes, &key_rctl_chk, &rv, &error)) {
3899		goto out;
3900	}
3901
3902	rv = (init)(real_provider, sp->sd_provider_session->ps_session,
3903	    &mech, &key, NULL, &cc, NULL);
3904
3905	/*
3906	 * Check if a context already exists. If so, it means it is being
3907	 * abandoned. So, cancel it to avoid leaking it.
3908	 */
3909	if (*ctxpp != NULL)
3910		CRYPTO_CANCEL_CTX(ctxpp);
3911	*ctxpp = (rv == CRYPTO_SUCCESS) ? cc : NULL;
3912
3913out:
3914	CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
3915	CRYPTO_DECREMENT_RCTL_SESSION(sp, key_rctl_bytes, key_rctl_chk);
3916	CRYPTO_SESSION_RELE(sp);
3917	crypto_release_minor(cm);
3918
3919	if (real_provider != NULL) {
3920		crypto_free_mech(real_provider,
3921		    allocated_by_crypto_module, &mech);
3922		KCF_PROV_REFRELE(real_provider);
3923	}
3924
3925	free_crypto_key(&key);
3926
3927	if (error != 0)
3928		return (error);
3929
3930	STRUCT_FSET(sign_init, si_return_value, rv);
3931	if (copyout(STRUCT_BUF(sign_init), arg, STRUCT_SIZE(sign_init)) != 0) {
3932		return (EFAULT);
3933	}
3934	return (0);
3935}
3936
3937/* ARGSUSED */
3938static int
3939sign(dev_t dev, caddr_t arg, int mode, int *rval)
3940{
3941	return (common_digest(dev, arg, mode, crypto_sign_single));
3942}
3943
3944/* ARGSUSED */
3945static int
3946sign_recover(dev_t dev, caddr_t arg, int mode, int *rval)
3947{
3948	return (common_digest(dev, arg, mode, crypto_sign_recover_single));
3949}
3950
3951/* ARGSUSED */
3952static int
3953verify(dev_t dev, caddr_t arg, int mode, int *rval)
3954{
3955	STRUCT_DECL(crypto_verify, verify);
3956	crypto_session_id_t session_id;
3957	crypto_minor_t *cm;
3958	crypto_session_data_t *sp = NULL;
3959	crypto_data_t data, sign;
3960	size_t datalen, signlen, need = 0;
3961	int error = 0;
3962	int rv;
3963	boolean_t rctl_chk = B_FALSE;
3964
3965	STRUCT_INIT(verify, mode);
3966
3967	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3968		cmn_err(CE_WARN, "verify: failed holding minor");
3969		return (ENXIO);
3970	}
3971
3972	if (copyin(arg, STRUCT_BUF(verify), STRUCT_SIZE(verify)) != 0) {
3973		crypto_release_minor(cm);
3974		return (EFAULT);
3975	}
3976
3977	data.cd_raw.iov_base = NULL;
3978	sign.cd_raw.iov_base = NULL;
3979
3980	datalen = STRUCT_FGET(verify, cv_datalen);
3981	signlen = STRUCT_FGET(verify, cv_signlen);
3982	if (datalen > crypto_max_buffer_len ||
3983	    signlen > crypto_max_buffer_len) {
3984		cmn_err(CE_NOTE, "verify: buffer greater than %ld bytes, "
3985		"pid = %d", crypto_max_buffer_len, curproc->p_pid);
3986		rv = CRYPTO_ARGUMENTS_BAD;
3987		goto release_minor;
3988	}
3989
3990	session_id = STRUCT_FGET(verify, cv_session);
3991
3992	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
3993		goto release_minor;
3994	}
3995
3996	need = datalen + signlen;
3997	if ((rv = CRYPTO_BUFFER_CHECK(sp, need, rctl_chk)) !=
3998	    CRYPTO_SUCCESS) {
3999		need = 0;
4000		goto release_minor;
4001	}
4002
4003	INIT_RAW_CRYPTO_DATA(data, datalen);
4004	INIT_RAW_CRYPTO_DATA(sign, signlen);
4005
4006	if (datalen != 0 && copyin(STRUCT_FGETP(verify, cv_databuf),
4007	    data.cd_raw.iov_base, datalen) != 0) {
4008		error = EFAULT;
4009		goto release_minor;
4010	}
4011
4012	if (signlen != 0 && copyin(STRUCT_FGETP(verify, cv_signbuf),
4013	    sign.cd_raw.iov_base, signlen) != 0) {
4014		error = EFAULT;
4015		goto release_minor;
4016	}
4017
4018	rv = crypto_verify_single(sp->sd_verify_ctx, &data, &sign, NULL);
4019	if (KCF_CONTEXT_DONE(rv))
4020		sp->sd_verify_ctx = NULL;
4021
4022release_minor:
4023	CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
4024	CRYPTO_SESSION_RELE(sp);
4025	crypto_release_minor(cm);
4026
4027	if (data.cd_raw.iov_base != NULL)
4028		kmem_free(data.cd_raw.iov_base, datalen);
4029
4030	if (sign.cd_raw.iov_base != NULL)
4031		kmem_free(sign.cd_raw.iov_base, signlen);
4032
4033	if (error != 0)
4034		return (error);
4035
4036	STRUCT_FSET(verify, cv_return_value, rv);
4037	if (copyout(STRUCT_BUF(verify), arg, STRUCT_SIZE(verify)) != 0) {
4038		return (EFAULT);
4039	}
4040	return (0);
4041}
4042
4043/* ARGSUSED */
4044static int
4045verify_recover(dev_t dev, caddr_t arg, int mode, int *rval)
4046{
4047	return (common_digest(dev, arg, mode, crypto_verify_recover_single));
4048}
4049
4050/* ARGSUSED */
4051static int
4052sign_update(dev_t dev, caddr_t arg, int mode, int *rval)
4053{
4054	return (sign_verify_update(dev, arg, mode, crypto_sign_update));
4055}
4056
4057/* ARGSUSED */
4058static int
4059verify_update(dev_t dev, caddr_t arg, int mode, int *rval)
4060{
4061	return (sign_verify_update(dev, arg, mode, crypto_verify_update));
4062}
4063
4064/*
4065 * ASSUMPTION: crypto_sign_update and crypto_verify_update structures
4066 * are identical except for field names.
4067 */
4068static int
4069sign_verify_update(dev_t dev, caddr_t arg, int mode,
4070    int (*update)(crypto_context_t, crypto_data_t *, crypto_call_req_t *))
4071{
4072	STRUCT_DECL(crypto_sign_update, sign_update);
4073	crypto_session_id_t session_id;
4074	crypto_minor_t *cm;
4075	crypto_session_data_t *sp = NULL;
4076	crypto_ctx_t **ctxpp;
4077	crypto_data_t data;
4078	size_t datalen, need = 0;
4079	int error = 0;
4080	int rv;
4081	boolean_t rctl_chk = B_FALSE;
4082
4083	STRUCT_INIT(sign_update, mode);
4084
4085	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4086		cmn_err(CE_WARN, "sign_verify_update: failed holding minor");
4087		return (ENXIO);
4088	}
4089
4090	if (copyin(arg, STRUCT_BUF(sign_update),
4091	    STRUCT_SIZE(sign_update)) != 0) {
4092		crypto_release_minor(cm);
4093		return (EFAULT);
4094	}
4095
4096	data.cd_raw.iov_base = NULL;
4097
4098	datalen = STRUCT_FGET(sign_update, su_datalen);
4099	if (datalen > crypto_max_buffer_len) {
4100		cmn_err(CE_NOTE, "sign_verify_update: buffer greater than %ld "
4101		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
4102		rv = CRYPTO_ARGUMENTS_BAD;
4103		goto release_minor;
4104	}
4105
4106	session_id = STRUCT_FGET(sign_update, su_session);
4107
4108	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4109		goto release_minor;
4110	}
4111
4112	if ((rv = CRYPTO_BUFFER_CHECK(sp, datalen, rctl_chk)) !=
4113	    CRYPTO_SUCCESS) {
4114		goto release_minor;
4115	}
4116	need = datalen;
4117
4118	INIT_RAW_CRYPTO_DATA(data, datalen);
4119
4120	if (datalen != 0 && copyin(STRUCT_FGETP(sign_update, su_databuf),
4121	    data.cd_raw.iov_base, datalen) != 0) {
4122		error = EFAULT;
4123		goto release_minor;
4124	}
4125
4126	ctxpp = (update == crypto_sign_update) ?
4127	    &sp->sd_sign_ctx : &sp->sd_verify_ctx;
4128
4129	rv = (update)(*ctxpp, &data, NULL);
4130	if (rv != CRYPTO_SUCCESS)
4131		CRYPTO_CANCEL_CTX(ctxpp);
4132
4133release_minor:
4134	CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
4135	CRYPTO_SESSION_RELE(sp);
4136	crypto_release_minor(cm);
4137
4138	if (data.cd_raw.iov_base != NULL)
4139		kmem_free(data.cd_raw.iov_base, datalen);
4140
4141	if (error != 0)
4142		return (error);
4143
4144	STRUCT_FSET(sign_update, su_return_value, rv);
4145	if (copyout(STRUCT_BUF(sign_update), arg,
4146	    STRUCT_SIZE(sign_update)) != 0) {
4147		return (EFAULT);
4148	}
4149	return (0);
4150}
4151
4152/* ARGSUSED */
4153static int
4154sign_final(dev_t dev, caddr_t arg, int mode, int *rval)
4155{
4156	return (common_final(dev, arg, mode, crypto_sign_final));
4157}
4158
4159/*
4160 * Can't use the common final because it does a copyout of
4161 * the final part.
4162 */
4163/* ARGSUSED */
4164static int
4165verify_final(dev_t dev, caddr_t arg, int mode, int *rval)
4166{
4167	STRUCT_DECL(crypto_verify_final, verify_final);
4168	crypto_session_id_t session_id;
4169	crypto_minor_t *cm;
4170	crypto_session_data_t *sp = NULL;
4171	crypto_data_t sign;
4172	size_t signlen, need = 0;
4173	int error = 0;
4174	int rv;
4175	boolean_t rctl_chk = B_FALSE;
4176
4177	STRUCT_INIT(verify_final, mode);
4178
4179	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4180		cmn_err(CE_WARN, "verify_final: failed holding minor");
4181		return (ENXIO);
4182	}
4183
4184	if (copyin(arg, STRUCT_BUF(verify_final),
4185	    STRUCT_SIZE(verify_final)) != 0) {
4186		crypto_release_minor(cm);
4187		return (EFAULT);
4188	}
4189
4190	sign.cd_raw.iov_base = NULL;
4191
4192	signlen = STRUCT_FGET(verify_final, vf_signlen);
4193	if (signlen > crypto_max_buffer_len) {
4194		cmn_err(CE_NOTE, "verify_final: buffer greater than %ld "
4195		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
4196		rv = CRYPTO_ARGUMENTS_BAD;
4197		goto release_minor;
4198	}
4199
4200	session_id = STRUCT_FGET(verify_final, vf_session);
4201
4202	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4203		goto release_minor;
4204	}
4205
4206	if ((rv = CRYPTO_BUFFER_CHECK(sp, signlen, rctl_chk)) !=
4207	    CRYPTO_SUCCESS) {
4208		goto release_minor;
4209	}
4210	need = signlen;
4211
4212	INIT_RAW_CRYPTO_DATA(sign, signlen);
4213
4214	if (signlen != 0 && copyin(STRUCT_FGETP(verify_final, vf_signbuf),
4215	    sign.cd_raw.iov_base, signlen) != 0) {
4216		error = EFAULT;
4217		goto release_minor;
4218	}
4219
4220	rv = crypto_verify_final(sp->sd_verify_ctx, &sign, NULL);
4221	if (KCF_CONTEXT_DONE(rv))
4222		sp->sd_verify_ctx = NULL;
4223
4224release_minor:
4225	CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
4226	CRYPTO_SESSION_RELE(sp);
4227	crypto_release_minor(cm);
4228
4229	if (sign.cd_raw.iov_base != NULL)
4230		kmem_free(sign.cd_raw.iov_base, signlen);
4231
4232	if (error != 0)
4233		return (error);
4234
4235	STRUCT_FSET(verify_final, vf_return_value, rv);
4236	if (copyout(STRUCT_BUF(verify_final), arg,
4237	    STRUCT_SIZE(verify_final)) != 0) {
4238		return (EFAULT);
4239	}
4240	return (0);
4241}
4242
4243/* ARGSUSED */
4244static int
4245seed_random(dev_t dev, caddr_t arg, int mode, int *rval)
4246{
4247	STRUCT_DECL(crypto_seed_random, seed_random);
4248	kcf_provider_desc_t *real_provider = NULL;
4249	kcf_req_params_t params;
4250	crypto_session_id_t session_id;
4251	crypto_minor_t *cm;
4252	crypto_session_data_t *sp = NULL;
4253	uchar_t *seed_buffer = NULL;
4254	size_t seed_len;
4255	size_t need = 0;
4256	int error = 0;
4257	int rv;
4258	boolean_t rctl_chk = B_FALSE;
4259
4260	STRUCT_INIT(seed_random, mode);
4261
4262	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4263		cmn_err(CE_WARN, "seed_random: failed holding minor");
4264		return (ENXIO);
4265	}
4266
4267	if (copyin(arg, STRUCT_BUF(seed_random),
4268	    STRUCT_SIZE(seed_random)) != 0) {
4269		crypto_release_minor(cm);
4270		return (EFAULT);
4271	}
4272
4273	seed_len = STRUCT_FGET(seed_random, sr_seedlen);
4274	if (seed_len > crypto_max_buffer_len) {
4275		cmn_err(CE_NOTE, "seed_random: buffer greater than %ld "
4276		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
4277		rv = CRYPTO_ARGUMENTS_BAD;
4278		goto release_minor;
4279	}
4280
4281	session_id = STRUCT_FGET(seed_random, sr_session);
4282
4283	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4284		goto release_minor;
4285	}
4286
4287	if ((rv = CRYPTO_BUFFER_CHECK(sp, seed_len, rctl_chk)) !=
4288	    CRYPTO_SUCCESS) {
4289		goto release_minor;
4290	}
4291	need = seed_len;
4292	seed_buffer = kmem_alloc(seed_len, KM_SLEEP);
4293
4294	if (seed_len != 0 && copyin(STRUCT_FGETP(seed_random, sr_seedbuf),
4295	    seed_buffer, seed_len) != 0) {
4296		error = EFAULT;
4297		goto release_minor;
4298	}
4299
4300	if ((rv = kcf_get_hardware_provider_nomech(
4301	    CRYPTO_OPS_OFFSET(random_ops), CRYPTO_RANDOM_OFFSET(seed_random),
4302	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider))
4303	    != CRYPTO_SUCCESS) {
4304		goto release_minor;
4305	}
4306
4307	KCF_WRAP_RANDOM_OPS_PARAMS(&params, KCF_OP_RANDOM_SEED,
4308	    sp->sd_provider_session->ps_session, seed_buffer, seed_len, 0,
4309	    CRYPTO_SEED_NOW);
4310
4311	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4312
4313release_minor:
4314	CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
4315	CRYPTO_SESSION_RELE(sp);
4316	crypto_release_minor(cm);
4317
4318	if (real_provider != NULL)
4319		KCF_PROV_REFRELE(real_provider);
4320
4321	if (seed_buffer != NULL)
4322		kmem_free(seed_buffer, seed_len);
4323
4324	if (error != 0)
4325		return (error);
4326
4327	STRUCT_FSET(seed_random, sr_return_value, rv);
4328	if (copyout(STRUCT_BUF(seed_random), arg,
4329	    STRUCT_SIZE(seed_random)) != 0) {
4330		return (EFAULT);
4331	}
4332	return (0);
4333}
4334
4335/* ARGSUSED */
4336static int
4337generate_random(dev_t dev, caddr_t arg, int mode, int *rval)
4338{
4339	STRUCT_DECL(crypto_generate_random, generate_random);
4340	kcf_provider_desc_t *real_provider = NULL;
4341	kcf_req_params_t params;
4342	crypto_session_id_t session_id;
4343	crypto_minor_t *cm;
4344	crypto_session_data_t *sp = NULL;
4345	uchar_t *buffer = NULL;
4346	size_t len;
4347	size_t need = 0;
4348	int error = 0;
4349	int rv;
4350	boolean_t rctl_chk = B_FALSE;
4351
4352	STRUCT_INIT(generate_random, mode);
4353
4354	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4355		cmn_err(CE_WARN, "generate_random: failed holding minor");
4356		return (ENXIO);
4357	}
4358
4359	if (copyin(arg, STRUCT_BUF(generate_random),
4360	    STRUCT_SIZE(generate_random)) != 0) {
4361		crypto_release_minor(cm);
4362		return (EFAULT);
4363	}
4364
4365	len = STRUCT_FGET(generate_random, gr_buflen);
4366	if (len > crypto_max_buffer_len) {
4367		cmn_err(CE_NOTE, "generate_random: buffer greater than %ld "
4368		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
4369		rv = CRYPTO_ARGUMENTS_BAD;
4370		goto release_minor;
4371	}
4372
4373	session_id = STRUCT_FGET(generate_random, gr_session);
4374
4375	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4376		goto release_minor;
4377	}
4378
4379	if ((rv = CRYPTO_BUFFER_CHECK(sp, len, rctl_chk)) !=
4380	    CRYPTO_SUCCESS) {
4381		goto release_minor;
4382	}
4383	need = len;
4384	buffer = kmem_alloc(len, KM_SLEEP);
4385
4386	if ((rv = kcf_get_hardware_provider_nomech(
4387	    CRYPTO_OPS_OFFSET(random_ops),
4388	    CRYPTO_RANDOM_OFFSET(generate_random), CHECK_RESTRICT_FALSE,
4389	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4390		goto release_minor;
4391	}
4392
4393	KCF_WRAP_RANDOM_OPS_PARAMS(&params, KCF_OP_RANDOM_GENERATE,
4394	    sp->sd_provider_session->ps_session, buffer, len, 0, 0);
4395
4396	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4397
4398	if (rv == CRYPTO_SUCCESS) {
4399		if (len != 0 && copyout(buffer,
4400		    STRUCT_FGETP(generate_random, gr_buf), len) != 0) {
4401			error = EFAULT;
4402		}
4403	}
4404
4405release_minor:
4406	CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
4407	CRYPTO_SESSION_RELE(sp);
4408	crypto_release_minor(cm);
4409
4410	if (real_provider != NULL)
4411		KCF_PROV_REFRELE(real_provider);
4412
4413	if (buffer != NULL) {
4414		/* random numbers are often used to create keys */
4415		bzero(buffer, len);
4416		kmem_free(buffer, len);
4417	}
4418
4419	if (error != 0)
4420		return (error);
4421
4422	STRUCT_FSET(generate_random, gr_return_value, rv);
4423	if (copyout(STRUCT_BUF(generate_random), arg,
4424	    STRUCT_SIZE(generate_random)) != 0) {
4425		return (EFAULT);
4426	}
4427	return (0);
4428}
4429
4430/*
4431 * Copyout a kernel array of attributes to user space.
4432 * u_attrs is the corresponding user space array containing
4433 * user space pointers necessary for the copyout.
4434 */
4435/* ARGSUSED */
4436static int
4437copyout_attributes(int mode, caddr_t out, uint_t count,
4438    crypto_object_attribute_t *k_attrs, caddr_t u_attrs)
4439{
4440	STRUCT_DECL(crypto_object_attribute, oa);
4441	caddr_t p, valuep;
4442	size_t value_len;
4443	size_t len;
4444	int i;
4445	int error = 0;
4446
4447	if (count == 0)
4448		return (0);
4449
4450	STRUCT_INIT(oa, mode);
4451
4452	len = count * STRUCT_SIZE(oa);
4453
4454	ASSERT(u_attrs != NULL);
4455	p = u_attrs;
4456	for (i = 0; i < count; i++) {
4457		/* can this bcopy be eliminated? */
4458		bcopy(p, STRUCT_BUF(oa), STRUCT_SIZE(oa));
4459		value_len = k_attrs[i].oa_value_len;
4460		STRUCT_FSET(oa, oa_type, k_attrs[i].oa_type);
4461		STRUCT_FSET(oa, oa_value_len, value_len);
4462		valuep = STRUCT_FGETP(oa, oa_value);
4463		if (valuep != NULL && value_len != -1) {
4464			if (copyout(k_attrs[i].oa_value,
4465			    valuep, value_len) != 0) {
4466				error = EFAULT;
4467				goto out;
4468			}
4469		}
4470		bcopy(STRUCT_BUF(oa), p, STRUCT_SIZE(oa));
4471		p += STRUCT_SIZE(oa);
4472	}
4473	if (copyout(u_attrs, out, len)) {
4474		error = EFAULT;
4475	}
4476out:
4477	return (error);
4478}
4479
4480
4481/* ARGSUSED */
4482static int
4483object_create(dev_t dev, caddr_t arg, int mode, int *rval)
4484{
4485	STRUCT_DECL(crypto_object_create, object_create);
4486	kcf_provider_desc_t *real_provider = NULL;
4487	kcf_req_params_t params;
4488	crypto_object_attribute_t *k_attrs = NULL;
4489	crypto_session_id_t session_id;
4490	crypto_minor_t *cm;
4491	crypto_session_data_t *sp = NULL;
4492	crypto_object_id_t object_handle;
4493	caddr_t oc_attributes;
4494	size_t k_attrs_size;
4495	size_t rctl_bytes = 0;
4496	boolean_t rctl_chk = B_FALSE;
4497	int error = 0;
4498	int rv;
4499	uint_t count;
4500
4501	STRUCT_INIT(object_create, mode);
4502
4503	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4504		cmn_err(CE_WARN, "object_create: failed holding minor");
4505		return (ENXIO);
4506	}
4507
4508	if (copyin(arg, STRUCT_BUF(object_create),
4509	    STRUCT_SIZE(object_create)) != 0) {
4510		crypto_release_minor(cm);
4511		return (EFAULT);
4512	}
4513
4514	count = STRUCT_FGET(object_create, oc_count);
4515	oc_attributes = STRUCT_FGETP(object_create, oc_attributes);
4516
4517	session_id = STRUCT_FGET(object_create, oc_session);
4518	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4519		goto release_minor;
4520	}
4521	if (!copyin_attributes(mode, sp, count, oc_attributes, &k_attrs,
4522	    &k_attrs_size, NULL, &rv, &error, &rctl_bytes,
4523	    &rctl_chk, B_TRUE)) {
4524		goto release_minor;
4525	}
4526
4527	if ((rv = kcf_get_hardware_provider_nomech(
4528	    CRYPTO_OPS_OFFSET(object_ops),
4529	    CRYPTO_OBJECT_OFFSET(object_create),
4530	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider))
4531	    != CRYPTO_SUCCESS) {
4532		goto release_minor;
4533	}
4534
4535	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_CREATE,
4536	    sp->sd_provider_session->ps_session, 0, k_attrs, count,
4537	    &object_handle, 0, NULL, NULL, 0, NULL);
4538
4539	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4540
4541	if (rv == CRYPTO_SUCCESS)
4542		STRUCT_FSET(object_create, oc_handle, object_handle);
4543
4544release_minor:
4545	CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, rctl_chk);
4546
4547	if (k_attrs != NULL)
4548		kmem_free(k_attrs, k_attrs_size);
4549
4550	if (error != 0)
4551		goto out;
4552
4553	STRUCT_FSET(object_create, oc_return_value, rv);
4554	if (copyout(STRUCT_BUF(object_create), arg,
4555	    STRUCT_SIZE(object_create)) != 0) {
4556		if (rv == CRYPTO_SUCCESS) {
4557			KCF_WRAP_OBJECT_OPS_PARAMS(&params,
4558			    KCF_OP_OBJECT_DESTROY,
4559			    sp->sd_provider_session->ps_session, object_handle,
4560			    NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
4561
4562			(void) kcf_submit_request(real_provider, NULL,
4563			    NULL, &params, B_FALSE);
4564
4565			error = EFAULT;
4566		}
4567	}
4568out:
4569	CRYPTO_SESSION_RELE(sp);
4570	crypto_release_minor(cm);
4571	if (real_provider != NULL)
4572		KCF_PROV_REFRELE(real_provider);
4573	return (error);
4574}
4575
4576/* ARGSUSED */
4577static int
4578object_copy(dev_t dev, caddr_t arg, int mode, int *rval)
4579{
4580	STRUCT_DECL(crypto_object_copy, object_copy);
4581	kcf_provider_desc_t *real_provider = NULL;
4582	kcf_req_params_t params;
4583	crypto_object_attribute_t *k_attrs = NULL;
4584	crypto_session_id_t session_id;
4585	crypto_minor_t *cm;
4586	crypto_session_data_t *sp = NULL;
4587	crypto_object_id_t handle, new_handle;
4588	caddr_t oc_new_attributes;
4589	size_t k_attrs_size;
4590	size_t rctl_bytes = 0;
4591	boolean_t rctl_chk = B_FALSE;
4592	int error = 0;
4593	int rv;
4594	uint_t count;
4595
4596	STRUCT_INIT(object_copy, mode);
4597
4598	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4599		cmn_err(CE_WARN, "object_copy: failed holding minor");
4600		return (ENXIO);
4601	}
4602
4603	if (copyin(arg, STRUCT_BUF(object_copy),
4604	    STRUCT_SIZE(object_copy)) != 0) {
4605		crypto_release_minor(cm);
4606		return (EFAULT);
4607	}
4608
4609	count = STRUCT_FGET(object_copy, oc_count);
4610	oc_new_attributes = STRUCT_FGETP(object_copy, oc_new_attributes);
4611
4612	session_id = STRUCT_FGET(object_copy, oc_session);
4613
4614	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4615		goto release_minor;
4616	}
4617	if (!copyin_attributes(mode, sp, count, oc_new_attributes, &k_attrs,
4618	    &k_attrs_size, NULL, &rv, &error, &rctl_bytes,
4619	    &rctl_chk, B_TRUE)) {
4620		goto release_minor;
4621	}
4622
4623	if ((rv = kcf_get_hardware_provider_nomech(
4624	    CRYPTO_OPS_OFFSET(object_ops),
4625	    CRYPTO_OBJECT_OFFSET(object_copy), CHECK_RESTRICT_FALSE,
4626	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4627		goto release_minor;
4628	}
4629
4630	handle = STRUCT_FGET(object_copy, oc_handle);
4631	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_COPY,
4632	    sp->sd_provider_session->ps_session, handle, k_attrs, count,
4633	    &new_handle, 0, NULL, NULL, 0, NULL);
4634
4635	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4636
4637	if (rv == CRYPTO_SUCCESS)
4638		STRUCT_FSET(object_copy, oc_new_handle, new_handle);
4639
4640release_minor:
4641	CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, rctl_chk);
4642
4643	if (k_attrs != NULL)
4644		kmem_free(k_attrs, k_attrs_size);
4645
4646	if (error != 0)
4647		goto out;
4648
4649	STRUCT_FSET(object_copy, oc_return_value, rv);
4650	if (copyout(STRUCT_BUF(object_copy), arg,
4651	    STRUCT_SIZE(object_copy)) != 0) {
4652		if (rv == CRYPTO_SUCCESS) {
4653			KCF_WRAP_OBJECT_OPS_PARAMS(&params,
4654			    KCF_OP_OBJECT_DESTROY,
4655			    sp->sd_provider_session->ps_session, new_handle,
4656			    NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
4657
4658			(void) kcf_submit_request(real_provider, NULL,
4659			    NULL, &params, B_FALSE);
4660
4661			error = EFAULT;
4662		}
4663	}
4664out:
4665	CRYPTO_SESSION_RELE(sp);
4666	crypto_release_minor(cm);
4667	if (real_provider != NULL)
4668		KCF_PROV_REFRELE(real_provider);
4669	return (error);
4670}
4671
4672/* ARGSUSED */
4673static int
4674object_destroy(dev_t dev, caddr_t arg, int mode, int *rval)
4675{
4676	STRUCT_DECL(crypto_object_destroy, object_destroy);
4677	kcf_provider_desc_t *real_provider;
4678	kcf_req_params_t params;
4679	crypto_session_id_t session_id;
4680	crypto_minor_t *cm;
4681	crypto_session_data_t *sp;
4682	crypto_object_id_t handle;
4683	int error = 0;
4684	int rv;
4685
4686	STRUCT_INIT(object_destroy, mode);
4687
4688	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4689		cmn_err(CE_WARN, "object_destroy: failed holding minor");
4690		return (ENXIO);
4691	}
4692
4693	if (copyin(arg, STRUCT_BUF(object_destroy),
4694	    STRUCT_SIZE(object_destroy)) != 0) {
4695		crypto_release_minor(cm);
4696		return (EFAULT);
4697	}
4698
4699	session_id = STRUCT_FGET(object_destroy, od_session);
4700
4701	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4702		goto release_minor;
4703	}
4704
4705	if ((rv = kcf_get_hardware_provider_nomech(
4706	    CRYPTO_OPS_OFFSET(object_ops),
4707	    CRYPTO_OBJECT_OFFSET(object_destroy), CHECK_RESTRICT_FALSE,
4708	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4709		goto out;
4710	}
4711
4712	handle = STRUCT_FGET(object_destroy, od_handle);
4713	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_DESTROY,
4714	    sp->sd_provider_session->ps_session, handle, NULL, 0, NULL, 0,
4715	    NULL, NULL, 0, NULL);
4716
4717	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4718	KCF_PROV_REFRELE(real_provider);
4719
4720out:
4721	CRYPTO_SESSION_RELE(sp);
4722
4723release_minor:
4724	crypto_release_minor(cm);
4725
4726	if (error != 0)
4727		return (error);
4728
4729	STRUCT_FSET(object_destroy, od_return_value, rv);
4730
4731	if (copyout(STRUCT_BUF(object_destroy), arg,
4732	    STRUCT_SIZE(object_destroy)) != 0) {
4733		return (EFAULT);
4734	}
4735	return (0);
4736}
4737
4738/* ARGSUSED */
4739static int
4740object_get_attribute_value(dev_t dev, caddr_t arg, int mode, int *rval)
4741{
4742	STRUCT_DECL(crypto_object_get_attribute_value, get_attribute_value);
4743	/* LINTED E_FUNC_SET_NOT_USED */
4744	STRUCT_DECL(crypto_object_attribute, oa);
4745	kcf_provider_desc_t *real_provider;
4746	kcf_req_params_t params;
4747	crypto_object_attribute_t *k_attrs = NULL;
4748	crypto_session_id_t session_id;
4749	crypto_minor_t *cm;
4750	crypto_session_data_t *sp = NULL;
4751	crypto_object_id_t handle;
4752	caddr_t og_attributes;
4753	caddr_t u_attrs = NULL;
4754	size_t k_attrs_size;
4755	size_t rctl_bytes = 0;
4756	boolean_t rctl_chk = B_FALSE;
4757	int error = 0;
4758	int rv;
4759	uint_t count;
4760
4761	STRUCT_INIT(get_attribute_value, mode);
4762	STRUCT_INIT(oa, mode);
4763
4764	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4765		cmn_err(CE_WARN,
4766		    "object_get_attribute_value: failed holding minor");
4767		return (ENXIO);
4768	}
4769
4770	if (copyin(arg, STRUCT_BUF(get_attribute_value),
4771	    STRUCT_SIZE(get_attribute_value)) != 0) {
4772		crypto_release_minor(cm);
4773		return (EFAULT);
4774	}
4775
4776	count = STRUCT_FGET(get_attribute_value, og_count);
4777	og_attributes = STRUCT_FGETP(get_attribute_value, og_attributes);
4778
4779	session_id = STRUCT_FGET(get_attribute_value, og_session);
4780
4781	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4782		goto release_minor;
4783	}
4784	if (!copyin_attributes(mode, sp, count, og_attributes, &k_attrs,
4785	    &k_attrs_size, &u_attrs, &rv, &error, &rctl_bytes,
4786	    &rctl_chk, B_FALSE)) {
4787		goto release_minor;
4788	}
4789
4790	if ((rv = kcf_get_hardware_provider_nomech(
4791	    CRYPTO_OPS_OFFSET(object_ops),
4792	    CRYPTO_OBJECT_OFFSET(object_get_attribute_value),
4793	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider))
4794	    != CRYPTO_SUCCESS) {
4795		goto out;
4796	}
4797
4798	handle = STRUCT_FGET(get_attribute_value, og_handle);
4799	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_GET_ATTRIBUTE_VALUE,
4800	    sp->sd_provider_session->ps_session, handle, k_attrs, count, NULL,
4801	    0, NULL, NULL, 0, NULL);
4802
4803	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4804	KCF_PROV_REFRELE(real_provider);
4805
4806out:
4807	if (rv == CRYPTO_SUCCESS || rv == CRYPTO_ATTRIBUTE_SENSITIVE ||
4808	    rv == CRYPTO_ATTRIBUTE_TYPE_INVALID ||
4809	    rv == CRYPTO_BUFFER_TOO_SMALL) {
4810		error = copyout_attributes(mode,
4811		    STRUCT_FGETP(get_attribute_value, og_attributes),
4812		    count, k_attrs, u_attrs);
4813	}
4814
4815release_minor:
4816	CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, rctl_chk);
4817	CRYPTO_SESSION_RELE(sp);
4818	crypto_release_minor(cm);
4819
4820	if (k_attrs != NULL)
4821		kmem_free(k_attrs, k_attrs_size);
4822
4823	if (u_attrs != NULL)
4824		kmem_free(u_attrs, count * STRUCT_SIZE(oa));
4825
4826	if (error != 0)
4827		return (error);
4828
4829	STRUCT_FSET(get_attribute_value, og_return_value, rv);
4830	if (copyout(STRUCT_BUF(get_attribute_value), arg,
4831	    STRUCT_SIZE(get_attribute_value)) != 0) {
4832		return (EFAULT);
4833	}
4834	return (0);
4835}
4836
4837/* ARGSUSED */
4838static int
4839object_get_size(dev_t dev, caddr_t arg, int mode, int *rval)
4840{
4841	STRUCT_DECL(crypto_object_get_size, object_get_size);
4842	kcf_provider_desc_t *real_provider;
4843	kcf_req_params_t params;
4844	crypto_session_id_t session_id;
4845	crypto_minor_t *cm;
4846	crypto_session_data_t *sp = NULL;
4847	crypto_object_id_t handle;
4848	size_t size;
4849	int error = 0;
4850	int rv;
4851
4852	STRUCT_INIT(object_get_size, mode);
4853
4854	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4855		cmn_err(CE_WARN, "object_get_size: failed holding minor");
4856		return (ENXIO);
4857	}
4858
4859	if (copyin(arg, STRUCT_BUF(object_get_size),
4860	    STRUCT_SIZE(object_get_size)) != 0) {
4861		crypto_release_minor(cm);
4862		return (EFAULT);
4863	}
4864
4865	session_id = STRUCT_FGET(object_get_size, gs_session);
4866
4867	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4868		goto release_minor;
4869	}
4870
4871	if ((rv = kcf_get_hardware_provider_nomech(
4872	    CRYPTO_OPS_OFFSET(object_ops),
4873	    CRYPTO_OBJECT_OFFSET(object_get_size), CHECK_RESTRICT_FALSE,
4874	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4875		goto release_minor;
4876	}
4877
4878	handle = STRUCT_FGET(object_get_size, gs_handle);
4879	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_GET_SIZE,
4880	    sp->sd_provider_session->ps_session, handle, NULL, 0, NULL, &size,
4881	    NULL, NULL, 0, NULL);
4882
4883	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4884	KCF_PROV_REFRELE(real_provider);
4885
4886	if (rv == CRYPTO_SUCCESS) {
4887		STRUCT_FSET(object_get_size, gs_size, size);
4888	}
4889
4890release_minor:
4891	crypto_release_minor(cm);
4892	CRYPTO_SESSION_RELE(sp);
4893
4894	if (error != 0)
4895		return (error);
4896
4897	STRUCT_FSET(object_get_size, gs_return_value, rv);
4898	if (copyout(STRUCT_BUF(object_get_size), arg,
4899	    STRUCT_SIZE(object_get_size)) != 0) {
4900		return (EFAULT);
4901	}
4902	return (0);
4903}
4904
4905/* ARGSUSED */
4906static int
4907object_set_attribute_value(dev_t dev, caddr_t arg, int mode, int *rval)
4908{
4909	STRUCT_DECL(crypto_object_set_attribute_value, set_attribute_value);
4910	kcf_provider_desc_t *real_provider;
4911	kcf_req_params_t params;
4912	crypto_object_attribute_t *k_attrs = NULL;
4913	crypto_session_id_t session_id;
4914	crypto_minor_t *cm;
4915	crypto_session_data_t *sp = NULL;
4916	crypto_object_id_t object_handle;
4917	caddr_t sa_attributes;
4918	size_t k_attrs_size;
4919	size_t rctl_bytes = 0;
4920	boolean_t rctl_chk = B_FALSE;
4921	int error = 0;
4922	int rv;
4923	uint_t count;
4924
4925	STRUCT_INIT(set_attribute_value, mode);
4926
4927	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4928		cmn_err(CE_WARN,
4929		    "object_set_attribute_value: failed holding minor");
4930		return (ENXIO);
4931	}
4932
4933	if (copyin(arg, STRUCT_BUF(set_attribute_value),
4934	    STRUCT_SIZE(set_attribute_value)) != 0) {
4935		crypto_release_minor(cm);
4936		return (EFAULT);
4937	}
4938
4939	count = STRUCT_FGET(set_attribute_value, sa_count);
4940	sa_attributes = STRUCT_FGETP(set_attribute_value, sa_attributes);
4941
4942	session_id = STRUCT_FGET(set_attribute_value, sa_session);
4943
4944	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4945		goto release_minor;
4946	}
4947	if (!copyin_attributes(mode, sp, count, sa_attributes, &k_attrs,
4948	    &k_attrs_size, NULL, &rv, &error, &rctl_bytes,
4949	    &rctl_chk, B_TRUE)) {
4950		goto release_minor;
4951	}
4952
4953	if ((rv = kcf_get_hardware_provider_nomech(
4954	    CRYPTO_OPS_OFFSET(object_ops),
4955	    CRYPTO_OBJECT_OFFSET(object_set_attribute_value),
4956	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider))
4957	    != CRYPTO_SUCCESS) {
4958		goto release_minor;
4959	}
4960
4961	object_handle = STRUCT_FGET(set_attribute_value, sa_handle);
4962	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_SET_ATTRIBUTE_VALUE,
4963	    sp->sd_provider_session->ps_session, object_handle, k_attrs, count,
4964	    NULL, 0, NULL, NULL, 0, NULL);
4965
4966	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4967	KCF_PROV_REFRELE(real_provider);
4968
4969release_minor:
4970	CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, rctl_chk);
4971	CRYPTO_SESSION_RELE(sp);
4972	crypto_release_minor(cm);
4973
4974	if (k_attrs != NULL)
4975		kmem_free(k_attrs, k_attrs_size);
4976
4977	if (error != 0)
4978		return (error);
4979
4980	STRUCT_FSET(set_attribute_value, sa_return_value, rv);
4981	if (copyout(STRUCT_BUF(set_attribute_value), arg,
4982	    STRUCT_SIZE(set_attribute_value)) != 0) {
4983		return (EFAULT);
4984	}
4985	return (0);
4986}
4987
4988/* ARGSUSED */
4989static int
4990object_find_init(dev_t dev, caddr_t arg, int mode, int *rval)
4991{
4992	STRUCT_DECL(crypto_object_find_init, find_init);
4993	kcf_provider_desc_t *real_provider = NULL;
4994	kcf_req_params_t params;
4995	crypto_object_attribute_t *k_attrs = NULL;
4996	crypto_session_id_t session_id;
4997	crypto_minor_t *cm;
4998	crypto_session_data_t *sp = NULL;
4999	caddr_t attributes;
5000	size_t k_attrs_size;
5001	size_t rctl_bytes = 0;
5002	boolean_t rctl_chk = B_FALSE;
5003	int error = 0;
5004	int rv;
5005	uint_t count;
5006	void *cookie;
5007
5008	STRUCT_INIT(find_init, mode);
5009
5010	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5011		cmn_err(CE_WARN, "object_find_init: failed holding minor");
5012		return (ENXIO);
5013	}
5014
5015	if (copyin(arg, STRUCT_BUF(find_init), STRUCT_SIZE(find_init)) != 0) {
5016		crypto_release_minor(cm);
5017		return (EFAULT);
5018	}
5019
5020	count = STRUCT_FGET(find_init, fi_count);
5021	attributes = STRUCT_FGETP(find_init, fi_attributes);
5022
5023	session_id = STRUCT_FGET(find_init, fi_session);
5024
5025	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5026		goto release_minor;
5027	}
5028	if (!copyin_attributes(mode, sp, count, attributes, &k_attrs,
5029	    &k_attrs_size, NULL, &rv, &error, &rctl_bytes,
5030	    &rctl_chk, B_TRUE)) {
5031		goto release_minor;
5032	}
5033
5034	if ((rv = kcf_get_hardware_provider_nomech(
5035	    CRYPTO_OPS_OFFSET(object_ops),
5036	    CRYPTO_OBJECT_OFFSET(object_find_init), CHECK_RESTRICT_FALSE,
5037	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
5038		goto release_minor;
5039	}
5040
5041	/* check for an active find */
5042	if (sp->sd_find_init_cookie != NULL) {
5043		rv = CRYPTO_OPERATION_IS_ACTIVE;
5044		goto release_minor;
5045	}
5046
5047	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_FIND_INIT,
5048	    sp->sd_provider_session->ps_session, 0, k_attrs, count, NULL, 0,
5049	    &cookie, NULL, 0, NULL);
5050
5051	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5052
5053	if (rv == CRYPTO_SUCCESS) {
5054		/*
5055		 * The cookie is allocated by a provider at the start of an
5056		 * object search.  It is freed when the search is terminated
5057		 * by a final operation, or when the session is closed.
5058		 * It contains state information about which object handles
5059		 * have been returned to the caller.
5060		 */
5061		sp->sd_find_init_cookie = cookie;
5062	}
5063
5064release_minor:
5065	CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, rctl_chk);
5066	CRYPTO_SESSION_RELE(sp);
5067	crypto_release_minor(cm);
5068
5069	if (real_provider != NULL)
5070		KCF_PROV_REFRELE(real_provider);
5071
5072	if (k_attrs != NULL)
5073		kmem_free(k_attrs, k_attrs_size);
5074
5075	if (error != 0)
5076		return (error);
5077
5078	STRUCT_FSET(find_init, fi_return_value, rv);
5079	if (copyout(STRUCT_BUF(find_init), arg, STRUCT_SIZE(find_init)) != 0) {
5080		return (EFAULT);
5081	}
5082	return (0);
5083}
5084
5085/* ARGSUSED */
5086static int
5087object_find_update(dev_t dev, caddr_t arg, int mode, int *rval)
5088{
5089	STRUCT_DECL(crypto_object_find_update, find_update);
5090	kcf_provider_desc_t *real_provider;
5091	kcf_req_params_t params;
5092	crypto_minor_t *cm;
5093	crypto_session_data_t *sp = NULL;
5094	crypto_object_id_t *buffer = NULL;
5095	crypto_session_id_t session_id;
5096	size_t len, rctl_bytes = 0;
5097	uint_t count, max_count;
5098	int rv, error = 0;
5099	boolean_t rctl_chk = B_FALSE;
5100
5101	STRUCT_INIT(find_update, mode);
5102
5103	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5104		cmn_err(CE_WARN, "object_find_update: failed holding minor");
5105		return (ENXIO);
5106	}
5107
5108	if (copyin(arg, STRUCT_BUF(find_update),
5109	    STRUCT_SIZE(find_update)) != 0) {
5110		crypto_release_minor(cm);
5111		return (EFAULT);
5112	}
5113
5114	max_count = STRUCT_FGET(find_update, fu_max_count);
5115	if (max_count > CRYPTO_MAX_FIND_COUNT) {
5116		cmn_err(CE_NOTE, "object_find_update: count greater than %d, "
5117		    "pid = %d", CRYPTO_MAX_FIND_COUNT, curproc->p_pid);
5118		rv = CRYPTO_ARGUMENTS_BAD;
5119		goto release_minor;
5120	}
5121	len = max_count * sizeof (crypto_object_id_t);
5122	session_id = STRUCT_FGET(find_update, fu_session);
5123
5124	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5125		goto release_minor;
5126	}
5127	if ((rv = CRYPTO_BUFFER_CHECK(sp, len, rctl_chk)) !=
5128	    CRYPTO_SUCCESS) {
5129		goto release_minor;
5130	}
5131	rctl_bytes = len;
5132	buffer = kmem_alloc(len, KM_SLEEP);
5133
5134	if ((rv = kcf_get_hardware_provider_nomech(
5135	    CRYPTO_OPS_OFFSET(object_ops),
5136	    CRYPTO_OBJECT_OFFSET(object_find), CHECK_RESTRICT_FALSE,
5137	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
5138		goto release_minor;
5139	}
5140
5141	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_FIND,
5142	    sp->sd_provider_session->ps_session, 0, NULL, 0, buffer, 0,
5143	    NULL, sp->sd_find_init_cookie, max_count, &count);
5144
5145	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5146	KCF_PROV_REFRELE(real_provider);
5147
5148	if (rv == CRYPTO_SUCCESS) {
5149		if (count > max_count) {
5150			/* bad bad provider */
5151			rv = CRYPTO_FAILED;
5152			goto release_minor;
5153		}
5154		if (count != 0) {
5155			/* copyout handles */
5156			if (copyout(buffer,
5157			    STRUCT_FGETP(find_update, fu_handles),
5158			    count * sizeof (crypto_object_id_t)) != 0) {
5159				error = EFAULT;
5160			}
5161		}
5162		STRUCT_FSET(find_update, fu_count, count);
5163	}
5164
5165release_minor:
5166	CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, rctl_chk);
5167	CRYPTO_SESSION_RELE(sp);
5168	crypto_release_minor(cm);
5169
5170	if (buffer != NULL)
5171		kmem_free(buffer, len);
5172
5173	if (error != 0)
5174		return (error);
5175
5176	STRUCT_FSET(find_update, fu_return_value, rv);
5177	if (copyout(STRUCT_BUF(find_update), arg,
5178	    STRUCT_SIZE(find_update)) != 0) {
5179		return (EFAULT);
5180	}
5181
5182	return (0);
5183}
5184
5185/*
5186 * Free provider-allocated storage used for find object searches.
5187 */
5188static int
5189crypto_free_find_ctx(crypto_session_data_t *sp)
5190{
5191	kcf_provider_desc_t *real_provider;
5192	kcf_req_params_t params;
5193	int rv;
5194
5195	if ((rv = kcf_get_hardware_provider_nomech(
5196	    CRYPTO_OPS_OFFSET(object_ops),
5197	    CRYPTO_OBJECT_OFFSET(object_find_final), CHECK_RESTRICT_FALSE,
5198	    sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
5199		return (rv);
5200	}
5201
5202	KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_FIND_FINAL,
5203	    sp->sd_provider_session->ps_session, 0, NULL, 0, NULL, 0,
5204	    NULL, sp->sd_find_init_cookie, 0, NULL);
5205
5206	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5207	KCF_PROV_REFRELE(real_provider);
5208	return (rv);
5209}
5210
5211/* ARGSUSED */
5212static int
5213object_find_final(dev_t dev, caddr_t arg, int mode, int *rval)
5214{
5215	STRUCT_DECL(crypto_object_find_final, object_find_final);
5216	crypto_session_id_t session_id;
5217	crypto_minor_t *cm;
5218	crypto_session_data_t *sp;
5219	int error = 0;
5220	int rv;
5221
5222	STRUCT_INIT(object_find_final, mode);
5223
5224	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5225		cmn_err(CE_WARN, "object_find_final: failed holding minor");
5226		return (ENXIO);
5227	}
5228
5229	if (copyin(arg, STRUCT_BUF(object_find_final),
5230	    STRUCT_SIZE(object_find_final)) != 0) {
5231		crypto_release_minor(cm);
5232		return (EFAULT);
5233	}
5234
5235	session_id = STRUCT_FGET(object_find_final, ff_session);
5236
5237	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5238		goto release_minor;
5239	}
5240
5241	if ((rv = crypto_free_find_ctx(sp)) == CRYPTO_SUCCESS) {
5242		sp->sd_find_init_cookie = NULL;
5243	}
5244
5245	CRYPTO_SESSION_RELE(sp);
5246
5247release_minor:
5248	crypto_release_minor(cm);
5249
5250	if (error != 0)
5251		return (error);
5252
5253	STRUCT_FSET(object_find_final, ff_return_value, rv);
5254
5255	if (copyout(STRUCT_BUF(object_find_final), arg,
5256	    STRUCT_SIZE(object_find_final)) != 0) {
5257		return (EFAULT);
5258	}
5259	return (0);
5260}
5261
5262/* ARGSUSED */
5263static int
5264object_generate_key(dev_t dev, caddr_t arg, int mode, int *rval)
5265{
5266	STRUCT_DECL(crypto_object_generate_key, generate_key);
5267	kcf_provider_desc_t *real_provider = NULL;
5268	kcf_req_params_t params;
5269	crypto_mechanism_t mech;
5270	crypto_object_attribute_t *k_attrs = NULL;
5271	crypto_session_id_t session_id;
5272	crypto_minor_t *cm;
5273	crypto_session_data_t *sp = NULL;
5274	crypto_object_id_t key_handle;
5275	caddr_t attributes;
5276	size_t k_attrs_size;
5277	size_t mech_rctl_bytes = 0, key_rctl_bytes = 0;
5278	boolean_t mech_rctl_chk = B_FALSE;
5279	boolean_t key_rctl_chk = B_FALSE;
5280	uint_t count;
5281	int error = 0;
5282	int rv;
5283	boolean_t allocated_by_crypto_module = B_FALSE;
5284
5285	STRUCT_INIT(generate_key, mode);
5286
5287	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5288		cmn_err(CE_WARN, "object_generate_key: failed holding minor");
5289		return (ENXIO);
5290	}
5291
5292	if (copyin(arg, STRUCT_BUF(generate_key),
5293	    STRUCT_SIZE(generate_key)) != 0) {
5294		crypto_release_minor(cm);
5295		return (EFAULT);
5296	}
5297
5298	session_id = STRUCT_FGET(generate_key, gk_session);
5299
5300	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5301		goto release_minor;
5302	}
5303
5304	bcopy(STRUCT_FADDR(generate_key, gk_mechanism), &mech.cm_type,
5305	    sizeof (crypto_mech_type_t));
5306
5307	if ((rv = kcf_get_hardware_provider(mech.cm_type, CRYPTO_MECH_INVALID,
5308	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider,
5309	    CRYPTO_FG_GENERATE)) != CRYPTO_SUCCESS) {
5310		goto release_minor;
5311	}
5312
5313	rv = crypto_provider_copyin_mech_param(real_provider,
5314	    STRUCT_FADDR(generate_key, gk_mechanism), &mech, mode, &error);
5315
5316	if (rv == CRYPTO_NOT_SUPPORTED) {
5317		allocated_by_crypto_module = B_TRUE;
5318		if (!copyin_mech(mode, sp,
5319		    STRUCT_FADDR(generate_key, gk_mechanism),
5320		    &mech, &mech_rctl_bytes, &mech_rctl_chk, &rv, &error)) {
5321			goto release_minor;
5322		}
5323	} else {
5324		if (rv != CRYPTO_SUCCESS)
5325			goto release_minor;
5326	}
5327
5328	count = STRUCT_FGET(generate_key, gk_count);
5329	attributes = STRUCT_FGETP(generate_key, gk_attributes);
5330	if (!copyin_attributes(mode, sp, count, attributes, &k_attrs,
5331	    &k_attrs_size, NULL, &rv, &error, &key_rctl_bytes,
5332	    &key_rctl_chk, B_TRUE)) {
5333		goto release_minor;
5334	}
5335
5336	KCF_WRAP_KEY_OPS_PARAMS(&params, KCF_OP_KEY_GENERATE,
5337	    sp->sd_provider_session->ps_session, &mech, k_attrs, count,
5338	    &key_handle, NULL, 0, NULL, NULL, NULL, 0);
5339
5340	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5341
5342	if (rv == CRYPTO_SUCCESS)
5343		STRUCT_FSET(generate_key, gk_handle, key_handle);
5344
5345release_minor:
5346	CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
5347	CRYPTO_DECREMENT_RCTL_SESSION(sp, key_rctl_bytes, key_rctl_chk);
5348
5349	if (k_attrs != NULL)
5350		kmem_free(k_attrs, k_attrs_size);
5351
5352	if (error != 0)
5353		goto out;
5354
5355	STRUCT_FSET(generate_key, gk_return_value, rv);
5356	if (copyout(STRUCT_BUF(generate_key), arg,
5357	    STRUCT_SIZE(generate_key)) != 0) {
5358		if (rv == CRYPTO_SUCCESS) {
5359			KCF_WRAP_OBJECT_OPS_PARAMS(&params,
5360			    KCF_OP_OBJECT_DESTROY,
5361			    sp->sd_provider_session->ps_session, key_handle,
5362			    NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
5363
5364			(void) kcf_submit_request(real_provider, NULL,
5365			    NULL, &params, B_FALSE);
5366
5367			error = EFAULT;
5368		}
5369	}
5370out:
5371	CRYPTO_SESSION_RELE(sp);
5372	crypto_release_minor(cm);
5373
5374	if (real_provider != NULL) {
5375		crypto_free_mech(real_provider,
5376		    allocated_by_crypto_module, &mech);
5377		KCF_PROV_REFRELE(real_provider);
5378	}
5379	return (error);
5380}
5381
5382/* ARGSUSED */
5383static int
5384nostore_generate_key(dev_t dev, caddr_t arg, int mode, int *rval)
5385{
5386	STRUCT_DECL(crypto_nostore_generate_key, generate_key);
5387	/* LINTED E_FUNC_SET_NOT_USED */
5388	STRUCT_DECL(crypto_object_attribute, oa);
5389	kcf_provider_desc_t *real_provider = NULL;
5390	kcf_req_params_t params;
5391	crypto_mechanism_t mech;
5392	crypto_object_attribute_t *k_in_attrs = NULL;
5393	crypto_object_attribute_t *k_out_attrs = NULL;
5394	crypto_session_id_t session_id;
5395	crypto_minor_t *cm;
5396	crypto_session_data_t *sp = NULL;
5397	caddr_t in_attributes;
5398	caddr_t out_attributes;
5399	size_t k_in_attrs_size;
5400	size_t k_out_attrs_size;
5401	size_t mech_rctl_bytes = 0;
5402	boolean_t mech_rctl_chk = B_FALSE;
5403	size_t in_key_rctl_bytes = 0, out_key_rctl_bytes = 0;
5404	boolean_t in_key_rctl_chk = B_FALSE;
5405	boolean_t out_key_rctl_chk = B_FALSE;
5406	uint_t in_count;
5407	uint_t out_count;
5408	int error = 0;
5409	int rv;
5410	boolean_t allocated_by_crypto_module = B_FALSE;
5411	caddr_t u_attrs = NULL;
5412
5413	STRUCT_INIT(generate_key, mode);
5414	STRUCT_INIT(oa, mode);
5415
5416	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5417		cmn_err(CE_WARN, "nostore_generate_key: failed holding minor");
5418		return (ENXIO);
5419	}
5420
5421	if (copyin(arg, STRUCT_BUF(generate_key),
5422	    STRUCT_SIZE(generate_key)) != 0) {
5423		crypto_release_minor(cm);
5424		return (EFAULT);
5425	}
5426
5427	session_id = STRUCT_FGET(generate_key, ngk_session);
5428
5429	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5430		goto release_minor;
5431	}
5432
5433	bcopy(STRUCT_FADDR(generate_key, ngk_mechanism), &mech.cm_type,
5434	    sizeof (crypto_mech_type_t));
5435
5436	if ((rv = kcf_get_hardware_provider(mech.cm_type, CRYPTO_MECH_INVALID,
5437	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider,
5438	    CRYPTO_FG_GENERATE)) != CRYPTO_SUCCESS) {
5439		goto release_minor;
5440	}
5441
5442	rv = crypto_provider_copyin_mech_param(real_provider,
5443	    STRUCT_FADDR(generate_key, ngk_mechanism), &mech, mode, &error);
5444
5445	if (rv == CRYPTO_NOT_SUPPORTED) {
5446		allocated_by_crypto_module = B_TRUE;
5447		if (!copyin_mech(mode, sp, STRUCT_FADDR(generate_key,
5448		    ngk_mechanism), &mech, &mech_rctl_bytes,
5449		    &mech_rctl_chk, &rv, &error)) {
5450			goto release_minor;
5451		}
5452	} else {
5453		if (rv != CRYPTO_SUCCESS)
5454			goto release_minor;
5455	}
5456
5457	in_count = STRUCT_FGET(generate_key, ngk_in_count);
5458	in_attributes = STRUCT_FGETP(generate_key, ngk_in_attributes);
5459	if (!copyin_attributes(mode, sp, in_count, in_attributes, &k_in_attrs,
5460	    &k_in_attrs_size, NULL, &rv, &error, &in_key_rctl_bytes,
5461	    &in_key_rctl_chk, B_TRUE)) {
5462		goto release_minor;
5463	}
5464
5465	out_count = STRUCT_FGET(generate_key, ngk_out_count);
5466	out_attributes = STRUCT_FGETP(generate_key, ngk_out_attributes);
5467	if (!copyin_attributes(mode, sp, out_count, out_attributes,
5468	    &k_out_attrs,
5469	    &k_out_attrs_size, &u_attrs, &rv, &error, &out_key_rctl_bytes,
5470	    &out_key_rctl_chk, B_FALSE)) {
5471		goto release_minor;
5472	}
5473
5474	KCF_WRAP_NOSTORE_KEY_OPS_PARAMS(&params, KCF_OP_KEY_GENERATE,
5475	    sp->sd_provider_session->ps_session, &mech, k_in_attrs, in_count,
5476	    NULL, 0, NULL, k_out_attrs, out_count, NULL, 0);
5477
5478	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5479
5480	if (rv == CRYPTO_SUCCESS) {
5481		error = copyout_attributes(mode, out_attributes,
5482		    out_count, k_out_attrs, u_attrs);
5483	}
5484release_minor:
5485	CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
5486	CRYPTO_DECREMENT_RCTL_SESSION(sp, in_key_rctl_bytes, in_key_rctl_chk);
5487	CRYPTO_DECREMENT_RCTL_SESSION(sp, out_key_rctl_bytes,
5488	    out_key_rctl_chk);
5489
5490	if (k_in_attrs != NULL)
5491		kmem_free(k_in_attrs, k_in_attrs_size);
5492	if (k_out_attrs != NULL) {
5493		bzero(k_out_attrs, k_out_attrs_size);
5494		kmem_free(k_out_attrs, k_out_attrs_size);
5495	}
5496
5497	if (u_attrs != NULL)
5498		kmem_free(u_attrs, out_count * STRUCT_SIZE(oa));
5499
5500	if (error != 0)
5501		goto out;
5502
5503	STRUCT_FSET(generate_key, ngk_return_value, rv);
5504	if (copyout(STRUCT_BUF(generate_key), arg,
5505	    STRUCT_SIZE(generate_key)) != 0) {
5506		error = EFAULT;
5507	}
5508out:
5509	CRYPTO_SESSION_RELE(sp);
5510	crypto_release_minor(cm);
5511
5512	if (real_provider != NULL) {
5513		crypto_free_mech(real_provider,
5514		    allocated_by_crypto_module, &mech);
5515		KCF_PROV_REFRELE(real_provider);
5516	}
5517	return (error);
5518}
5519
5520/* ARGSUSED */
5521static int
5522object_generate_key_pair(dev_t dev, caddr_t arg, int mode, int *rval)
5523{
5524	STRUCT_DECL(crypto_object_generate_key_pair, generate_key_pair);
5525	kcf_provider_desc_t *real_provider = NULL;
5526	kcf_req_params_t params;
5527	crypto_mechanism_t mech;
5528	crypto_object_attribute_t *k_pub_attrs = NULL;
5529	crypto_object_attribute_t *k_pri_attrs = NULL;
5530	crypto_session_id_t session_id;
5531	crypto_minor_t *cm;
5532	crypto_session_data_t *sp = NULL;
5533	crypto_object_id_t pub_handle;
5534	crypto_object_id_t pri_handle;
5535	caddr_t pri_attributes;
5536	caddr_t pub_attributes;
5537	size_t k_pub_attrs_size, k_pri_attrs_size;
5538	size_t mech_rctl_bytes = 0;
5539	boolean_t mech_rctl_chk = B_FALSE;
5540	size_t pub_rctl_bytes = 0;
5541	boolean_t pub_rctl_chk = B_FALSE;
5542	size_t pri_rctl_bytes = 0;
5543	boolean_t pri_rctl_chk = B_FALSE;
5544	uint_t pub_count;
5545	uint_t pri_count;
5546	int error = 0;
5547	int rv;
5548	boolean_t allocated_by_crypto_module = B_FALSE;
5549
5550	STRUCT_INIT(generate_key_pair, mode);
5551
5552	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5553		cmn_err(CE_WARN,
5554		    "object_generate_key_pair: failed holding minor");
5555		return (ENXIO);
5556	}
5557
5558	if (copyin(arg, STRUCT_BUF(generate_key_pair),
5559	    STRUCT_SIZE(generate_key_pair)) != 0) {
5560		crypto_release_minor(cm);
5561		return (EFAULT);
5562	}
5563
5564	session_id = STRUCT_FGET(generate_key_pair, kp_session);
5565
5566	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5567		goto release_minor;
5568	}
5569
5570	bcopy(STRUCT_FADDR(generate_key_pair, kp_mechanism), &mech.cm_type,
5571	    sizeof (crypto_mech_type_t));
5572
5573	if ((rv = kcf_get_hardware_provider(mech.cm_type, CRYPTO_MECH_INVALID,
5574	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider,
5575	    CRYPTO_FG_GENERATE_KEY_PAIR)) != CRYPTO_SUCCESS) {
5576		goto release_minor;
5577	}
5578
5579	rv = crypto_provider_copyin_mech_param(real_provider,
5580	    STRUCT_FADDR(generate_key_pair, kp_mechanism), &mech, mode, &error);
5581
5582	if (rv == CRYPTO_NOT_SUPPORTED) {
5583		allocated_by_crypto_module = B_TRUE;
5584		if (!copyin_mech(mode, sp, STRUCT_FADDR(generate_key_pair,
5585		    kp_mechanism), &mech, &mech_rctl_bytes,
5586		    &mech_rctl_chk, &rv, &error)) {
5587			goto release_minor;
5588		}
5589	} else {
5590		if (rv != CRYPTO_SUCCESS)
5591			goto release_minor;
5592	}
5593
5594	pub_count = STRUCT_FGET(generate_key_pair, kp_public_count);
5595	pri_count = STRUCT_FGET(generate_key_pair, kp_private_count);
5596
5597	pub_attributes = STRUCT_FGETP(generate_key_pair, kp_public_attributes);
5598	if (!copyin_attributes(mode, sp, pub_count, pub_attributes,
5599	    &k_pub_attrs, &k_pub_attrs_size, NULL, &rv, &error, &pub_rctl_bytes,
5600	    &pub_rctl_chk, B_TRUE)) {
5601		goto release_minor;
5602	}
5603
5604	pri_attributes = STRUCT_FGETP(generate_key_pair, kp_private_attributes);
5605	if (!copyin_attributes(mode, sp, pri_count, pri_attributes,
5606	    &k_pri_attrs, &k_pri_attrs_size, NULL, &rv, &error,
5607	    &pri_rctl_bytes, &pri_rctl_chk, B_TRUE)) {
5608		goto release_minor;
5609	}
5610
5611	KCF_WRAP_KEY_OPS_PARAMS(&params, KCF_OP_KEY_GENERATE_PAIR,
5612	    sp->sd_provider_session->ps_session, &mech, k_pub_attrs,
5613	    pub_count, &pub_handle, k_pri_attrs, pri_count, &pri_handle,
5614	    NULL, NULL, 0);
5615
5616	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5617
5618	if (rv == CRYPTO_SUCCESS) {
5619		STRUCT_FSET(generate_key_pair, kp_public_handle, pub_handle);
5620		STRUCT_FSET(generate_key_pair, kp_private_handle, pri_handle);
5621	}
5622
5623release_minor:
5624	CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
5625	CRYPTO_DECREMENT_RCTL_SESSION(sp, pub_rctl_bytes, pub_rctl_chk);
5626	CRYPTO_DECREMENT_RCTL_SESSION(sp, pri_rctl_bytes, pri_rctl_chk);
5627
5628	if (k_pub_attrs != NULL)
5629		kmem_free(k_pub_attrs, k_pub_attrs_size);
5630
5631	if (k_pri_attrs != NULL)
5632		kmem_free(k_pri_attrs, k_pri_attrs_size);
5633
5634	if (error != 0)
5635		goto out;
5636
5637	STRUCT_FSET(generate_key_pair, kp_return_value, rv);
5638	if (copyout(STRUCT_BUF(generate_key_pair), arg,
5639	    STRUCT_SIZE(generate_key_pair)) != 0) {
5640		if (rv == CRYPTO_SUCCESS) {
5641			KCF_WRAP_OBJECT_OPS_PARAMS(&params,
5642			    KCF_OP_OBJECT_DESTROY,
5643			    sp->sd_provider_session->ps_session, pub_handle,
5644			    NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
5645
5646			(void) kcf_submit_request(real_provider, NULL,
5647			    NULL, &params, B_FALSE);
5648
5649			KCF_WRAP_OBJECT_OPS_PARAMS(&params,
5650			    KCF_OP_OBJECT_DESTROY,
5651			    sp->sd_provider_session->ps_session, pri_handle,
5652			    NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
5653
5654			(void) kcf_submit_request(real_provider, NULL,
5655			    NULL, &params, B_FALSE);
5656
5657			error = EFAULT;
5658		}
5659	}
5660out:
5661	CRYPTO_SESSION_RELE(sp);
5662	crypto_release_minor(cm);
5663
5664	if (real_provider != NULL) {
5665		crypto_free_mech(real_provider,
5666		    allocated_by_crypto_module, &mech);
5667		KCF_PROV_REFRELE(real_provider);
5668	}
5669	return (error);
5670}
5671
5672/* ARGSUSED */
5673static int
5674nostore_generate_key_pair(dev_t dev, caddr_t arg, int mode, int *rval)
5675{
5676	STRUCT_DECL(crypto_nostore_generate_key_pair, generate_key_pair);
5677	/* LINTED E_FUNC_SET_NOT_USED */
5678	STRUCT_DECL(crypto_object_attribute, oa);
5679	kcf_provider_desc_t *real_provider = NULL;
5680	kcf_req_params_t params;
5681	crypto_mechanism_t mech;
5682	crypto_object_attribute_t *k_in_pub_attrs = NULL;
5683	crypto_object_attribute_t *k_in_pri_attrs = NULL;
5684	crypto_object_attribute_t *k_out_pub_attrs = NULL;
5685	crypto_object_attribute_t *k_out_pri_attrs = NULL;
5686	crypto_session_id_t session_id;
5687	crypto_minor_t *cm;
5688	crypto_session_data_t *sp = NULL;
5689	caddr_t in_pri_attributes;
5690	caddr_t in_pub_attributes;
5691	caddr_t out_pri_attributes;
5692	caddr_t out_pub_attributes;
5693	size_t k_in_pub_attrs_size, k_in_pri_attrs_size;
5694	size_t k_out_pub_attrs_size, k_out_pri_attrs_size;
5695	size_t mech_rctl_bytes = 0;
5696	boolean_t mech_rctl_chk = B_FALSE;
5697	size_t in_pub_rctl_bytes = 0;
5698	boolean_t in_pub_rctl_chk = B_FALSE;
5699	size_t in_pri_rctl_bytes = 0;
5700	boolean_t in_pri_rctl_chk = B_FALSE;
5701	size_t out_pub_rctl_bytes = 0;
5702	boolean_t out_pub_rctl_chk = B_FALSE;
5703	size_t out_pri_rctl_bytes = 0;
5704	boolean_t out_pri_rctl_chk = B_FALSE;
5705	uint_t in_pub_count;
5706	uint_t in_pri_count;
5707	uint_t out_pub_count;
5708	uint_t out_pri_count;
5709	int error = 0;
5710	int rv;
5711	boolean_t allocated_by_crypto_module = B_FALSE;
5712	caddr_t u_pub_attrs = NULL;
5713	caddr_t u_pri_attrs = NULL;
5714
5715	STRUCT_INIT(generate_key_pair, mode);
5716	STRUCT_INIT(oa, mode);
5717
5718	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5719		cmn_err(CE_WARN,
5720		    "nostore_generate_key_pair: failed holding minor");
5721		return (ENXIO);
5722	}
5723
5724	if (copyin(arg, STRUCT_BUF(generate_key_pair),
5725	    STRUCT_SIZE(generate_key_pair)) != 0) {
5726		crypto_release_minor(cm);
5727		return (EFAULT);
5728	}
5729
5730	session_id = STRUCT_FGET(generate_key_pair, nkp_session);
5731
5732	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5733		goto release_minor;
5734	}
5735
5736	bcopy(STRUCT_FADDR(generate_key_pair, nkp_mechanism), &mech.cm_type,
5737	    sizeof (crypto_mech_type_t));
5738
5739	if ((rv = kcf_get_hardware_provider(mech.cm_type, CRYPTO_MECH_INVALID,
5740	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider,
5741	    CRYPTO_FG_GENERATE_KEY_PAIR)) != CRYPTO_SUCCESS) {
5742		goto release_minor;
5743	}
5744
5745	rv = crypto_provider_copyin_mech_param(real_provider,
5746	    STRUCT_FADDR(generate_key_pair, nkp_mechanism), &mech, mode,
5747	    &error);
5748
5749	if (rv == CRYPTO_NOT_SUPPORTED) {
5750		allocated_by_crypto_module = B_TRUE;
5751		if (!copyin_mech(mode, sp, STRUCT_FADDR(generate_key_pair,
5752		    nkp_mechanism), &mech, &mech_rctl_bytes,
5753		    &mech_rctl_chk, &rv, &error)) {
5754			goto release_minor;
5755		}
5756	} else {
5757		if (rv != CRYPTO_SUCCESS)
5758			goto release_minor;
5759	}
5760
5761	in_pub_count = STRUCT_FGET(generate_key_pair, nkp_in_public_count);
5762	in_pri_count = STRUCT_FGET(generate_key_pair, nkp_in_private_count);
5763
5764	in_pub_attributes = STRUCT_FGETP(generate_key_pair,
5765	    nkp_in_public_attributes);
5766	if (!copyin_attributes(mode, sp, in_pub_count, in_pub_attributes,
5767	    &k_in_pub_attrs, &k_in_pub_attrs_size, NULL, &rv, &error,
5768	    &in_pub_rctl_bytes, &in_pub_rctl_chk, B_TRUE)) {
5769		goto release_minor;
5770	}
5771
5772	in_pri_attributes = STRUCT_FGETP(generate_key_pair,
5773	    nkp_in_private_attributes);
5774	if (!copyin_attributes(mode, sp, in_pri_count, in_pri_attributes,
5775	    &k_in_pri_attrs, &k_in_pri_attrs_size, NULL, &rv, &error,
5776	    &in_pri_rctl_bytes, &in_pri_rctl_chk, B_TRUE)) {
5777		goto release_minor;
5778	}
5779
5780	out_pub_count = STRUCT_FGET(generate_key_pair, nkp_out_public_count);
5781	out_pri_count = STRUCT_FGET(generate_key_pair, nkp_out_private_count);
5782
5783	out_pub_attributes = STRUCT_FGETP(generate_key_pair,
5784	    nkp_out_public_attributes);
5785	if (!copyin_attributes(mode, sp, out_pub_count, out_pub_attributes,
5786	    &k_out_pub_attrs, &k_out_pub_attrs_size, &u_pub_attrs, &rv, &error,
5787	    &out_pub_rctl_bytes, &out_pub_rctl_chk, B_FALSE)) {
5788		goto release_minor;
5789	}
5790
5791	out_pri_attributes = STRUCT_FGETP(generate_key_pair,
5792	    nkp_out_private_attributes);
5793	if (!copyin_attributes(mode, sp, out_pri_count, out_pri_attributes,
5794	    &k_out_pri_attrs, &k_out_pri_attrs_size, &u_pri_attrs, &rv, &error,
5795	    &out_pri_rctl_bytes, &out_pri_rctl_chk, B_FALSE)) {
5796		goto release_minor;
5797	}
5798
5799	KCF_WRAP_NOSTORE_KEY_OPS_PARAMS(&params, KCF_OP_KEY_GENERATE_PAIR,
5800	    sp->sd_provider_session->ps_session, &mech, k_in_pub_attrs,
5801	    in_pub_count, k_in_pri_attrs, in_pri_count, NULL, k_out_pub_attrs,
5802	    out_pub_count, k_out_pri_attrs, out_pri_count);
5803
5804	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5805
5806	if (rv == CRYPTO_SUCCESS) {
5807		error = copyout_attributes(mode, out_pub_attributes,
5808		    out_pub_count, k_out_pub_attrs, u_pub_attrs);
5809		if (error != CRYPTO_SUCCESS)
5810			goto release_minor;
5811		error = copyout_attributes(mode, out_pri_attributes,
5812		    out_pri_count, k_out_pri_attrs, u_pri_attrs);
5813	}
5814
5815release_minor:
5816	CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
5817	CRYPTO_DECREMENT_RCTL_SESSION(sp, in_pub_rctl_bytes, in_pub_rctl_chk);
5818	CRYPTO_DECREMENT_RCTL_SESSION(sp, in_pri_rctl_bytes, in_pri_rctl_chk);
5819	CRYPTO_DECREMENT_RCTL_SESSION(sp, out_pub_rctl_bytes,
5820	    out_pub_rctl_chk);
5821	CRYPTO_DECREMENT_RCTL_SESSION(sp, out_pri_rctl_bytes,
5822	    out_pri_rctl_chk);
5823
5824	if (k_in_pub_attrs != NULL)
5825		kmem_free(k_in_pub_attrs, k_in_pub_attrs_size);
5826
5827	if (k_in_pri_attrs != NULL)
5828		kmem_free(k_in_pri_attrs, k_in_pri_attrs_size);
5829
5830	if (k_out_pub_attrs != NULL)
5831		kmem_free(k_out_pub_attrs, k_out_pub_attrs_size);
5832
5833	if (k_out_pri_attrs != NULL) {
5834		bzero(k_out_pri_attrs, k_out_pri_attrs_size);
5835		kmem_free(k_out_pri_attrs, k_out_pri_attrs_size);
5836	}
5837
5838	if (u_pub_attrs != NULL)
5839		kmem_free(u_pub_attrs, out_pub_count * STRUCT_SIZE(oa));
5840
5841	if (u_pri_attrs != NULL)
5842		kmem_free(u_pri_attrs, out_pri_count * STRUCT_SIZE(oa));
5843
5844	if (error != 0)
5845		goto out;
5846
5847	STRUCT_FSET(generate_key_pair, nkp_return_value, rv);
5848	if (copyout(STRUCT_BUF(generate_key_pair), arg,
5849	    STRUCT_SIZE(generate_key_pair)) != 0) {
5850		error = EFAULT;
5851	}
5852out:
5853	CRYPTO_SESSION_RELE(sp);
5854	crypto_release_minor(cm);
5855
5856	if (real_provider != NULL) {
5857		crypto_free_mech(real_provider,
5858		    allocated_by_crypto_module, &mech);
5859		KCF_PROV_REFRELE(real_provider);
5860	}
5861	return (error);
5862}
5863
5864/* ARGSUSED */
5865static int
5866object_wrap_key(dev_t dev, caddr_t arg, int mode, int *rval)
5867{
5868	STRUCT_DECL(crypto_object_wrap_key, wrap_key);
5869	kcf_provider_desc_t *real_provider = NULL;
5870	kcf_req_params_t params;
5871	crypto_mechanism_t mech;
5872	crypto_key_t key;
5873	crypto_session_id_t session_id;
5874	crypto_minor_t *cm;
5875	crypto_session_data_t *sp = NULL;
5876	crypto_object_id_t handle;
5877	size_t mech_rctl_bytes = 0, key_rctl_bytes = 0;
5878	boolean_t mech_rctl_chk = B_FALSE;
5879	boolean_t key_rctl_chk = B_FALSE;
5880	size_t wrapped_key_rctl_bytes = 0;
5881	boolean_t wrapped_key_rctl_chk = B_FALSE;
5882	size_t wrapped_key_len, new_wrapped_key_len;
5883	uchar_t *wrapped_key = NULL;
5884	char *wrapped_key_buffer;
5885	int error = 0;
5886	int rv;
5887	boolean_t allocated_by_crypto_module = B_FALSE;
5888
5889	STRUCT_INIT(wrap_key, mode);
5890
5891	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5892		cmn_err(CE_WARN, "object_wrap_key: failed holding minor");
5893		return (ENXIO);
5894	}
5895
5896	if (copyin(arg, STRUCT_BUF(wrap_key), STRUCT_SIZE(wrap_key)) != 0) {
5897		crypto_release_minor(cm);
5898		return (EFAULT);
5899	}
5900
5901	bzero(&key, sizeof (crypto_key_t));
5902
5903	session_id = STRUCT_FGET(wrap_key, wk_session);
5904
5905	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5906		goto out;
5907	}
5908
5909	bcopy(STRUCT_FADDR(wrap_key, wk_mechanism), &mech.cm_type,
5910	    sizeof (crypto_mech_type_t));
5911
5912	if ((rv = kcf_get_hardware_provider(mech.cm_type, CRYPTO_MECH_INVALID,
5913	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider,
5914	    CRYPTO_FG_WRAP)) != CRYPTO_SUCCESS) {
5915		goto out;
5916	}
5917
5918	rv = crypto_provider_copyin_mech_param(real_provider,
5919	    STRUCT_FADDR(wrap_key, wk_mechanism), &mech, mode, &error);
5920
5921	if (rv == CRYPTO_NOT_SUPPORTED) {
5922		allocated_by_crypto_module = B_TRUE;
5923		if (!copyin_mech(mode, sp, STRUCT_FADDR(wrap_key, wk_mechanism),
5924		    &mech, &mech_rctl_bytes, &mech_rctl_chk, &rv, &error)) {
5925			goto out;
5926		}
5927	} else {
5928		if (rv != CRYPTO_SUCCESS)
5929			goto out;
5930	}
5931
5932	if (!copyin_key(mode, sp, STRUCT_FADDR(wrap_key, wk_wrapping_key), &key,
5933	    &key_rctl_bytes, &key_rctl_chk, &rv, &error)) {
5934		goto out;
5935	}
5936
5937	wrapped_key_len = STRUCT_FGET(wrap_key, wk_wrapped_key_len);
5938
5939	/*
5940	 * Don't allocate output buffer unless both buffer pointer and
5941	 * buffer length are not NULL or 0 (length).
5942	 */
5943	wrapped_key_buffer = STRUCT_FGETP(wrap_key, wk_wrapped_key);
5944	if (wrapped_key_buffer == NULL || wrapped_key_len == 0) {
5945		wrapped_key_len = 0;
5946	}
5947
5948	if (wrapped_key_len > crypto_max_buffer_len) {
5949		cmn_err(CE_NOTE, "object_wrap_key: buffer greater than %ld "
5950		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
5951		rv = CRYPTO_ARGUMENTS_BAD;
5952		goto out;
5953	}
5954
5955	if ((rv = CRYPTO_BUFFER_CHECK(sp, wrapped_key_len,
5956	    wrapped_key_rctl_chk)) != CRYPTO_SUCCESS) {
5957		goto out;
5958	}
5959
5960	/* new_wrapped_key_len can be modified by the provider */
5961	wrapped_key_rctl_bytes = new_wrapped_key_len = wrapped_key_len;
5962	wrapped_key = kmem_alloc(wrapped_key_len, KM_SLEEP);
5963
5964	handle = STRUCT_FGET(wrap_key, wk_object_handle);
5965	KCF_WRAP_KEY_OPS_PARAMS(&params, KCF_OP_KEY_WRAP,
5966	    sp->sd_provider_session->ps_session, &mech, NULL, 0, &handle,
5967	    NULL, 0, NULL, &key, wrapped_key, &new_wrapped_key_len);
5968
5969	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5970
5971	if (rv == CRYPTO_SUCCESS) {
5972		if (wrapped_key_len != 0 && copyout(wrapped_key,
5973		    wrapped_key_buffer, new_wrapped_key_len) != 0) {
5974			error = EFAULT;
5975		}
5976		STRUCT_FSET(wrap_key, wk_wrapped_key_len, new_wrapped_key_len);
5977	}
5978
5979	if (rv == CRYPTO_BUFFER_TOO_SMALL) {
5980		/*
5981		 * The providers return CRYPTO_BUFFER_TOO_SMALL even for case 1
5982		 * of section 11.2 of the pkcs11 spec. We catch it here and
5983		 * provide the correct pkcs11 return value.
5984		 */
5985		if (STRUCT_FGETP(wrap_key, wk_wrapped_key) == NULL)
5986			rv = CRYPTO_SUCCESS;
5987		STRUCT_FSET(wrap_key, wk_wrapped_key_len, new_wrapped_key_len);
5988	}
5989
5990out:
5991	CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
5992	CRYPTO_DECREMENT_RCTL_SESSION(sp, key_rctl_bytes, key_rctl_chk);
5993	CRYPTO_DECREMENT_RCTL_SESSION(sp, wrapped_key_rctl_bytes,
5994	    wrapped_key_rctl_chk);
5995	CRYPTO_SESSION_RELE(sp);
5996
5997	crypto_release_minor(cm);
5998
5999	if (real_provider != NULL) {
6000		crypto_free_mech(real_provider,
6001		    allocated_by_crypto_module, &mech);
6002		KCF_PROV_REFRELE(real_provider);
6003	}
6004
6005	if (wrapped_key != NULL)
6006		kmem_free(wrapped_key, wrapped_key_len);
6007
6008	free_crypto_key(&key);
6009
6010	if (error != 0)
6011		return (error);
6012
6013	STRUCT_FSET(wrap_key, wk_return_value, rv);
6014	if (copyout(STRUCT_BUF(wrap_key), arg, STRUCT_SIZE(wrap_key)) != 0) {
6015		return (EFAULT);
6016	}
6017	return (0);
6018}
6019
6020/* ARGSUSED */
6021static int
6022object_unwrap_key(dev_t dev, caddr_t arg, int mode, int *rval)
6023{
6024	STRUCT_DECL(crypto_object_unwrap_key, unwrap_key);
6025	kcf_provider_desc_t *real_provider = NULL;
6026	kcf_req_params_t params;
6027	crypto_mechanism_t mech;
6028	crypto_key_t unwrapping_key;
6029	crypto_session_id_t session_id;
6030	crypto_minor_t *cm;
6031	crypto_session_data_t *sp = NULL;
6032	crypto_object_id_t handle;
6033	crypto_object_attribute_t *k_attrs = NULL;
6034	size_t k_attrs_size;
6035	size_t mech_rctl_bytes = 0, unwrapping_key_rctl_bytes = 0;
6036	boolean_t mech_rctl_chk = B_FALSE;
6037	boolean_t unwrapping_key_rctl_chk = B_FALSE;
6038	size_t wrapped_key_rctl_bytes = 0, k_attrs_rctl_bytes = 0;
6039	boolean_t wrapped_key_rctl_chk = B_FALSE;
6040	boolean_t k_attrs_rctl_chk = B_FALSE;
6041	size_t wrapped_key_len;
6042	uchar_t *wrapped_key = NULL;
6043	int error = 0;
6044	int rv;
6045	uint_t count;
6046	caddr_t uk_attributes;
6047	boolean_t allocated_by_crypto_module = B_FALSE;
6048
6049	STRUCT_INIT(unwrap_key, mode);
6050
6051	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
6052		cmn_err(CE_WARN, "object_unwrap_key: failed holding minor");
6053		return (ENXIO);
6054	}
6055
6056	if (copyin(arg, STRUCT_BUF(unwrap_key), STRUCT_SIZE(unwrap_key)) != 0) {
6057		crypto_release_minor(cm);
6058		return (EFAULT);
6059	}
6060
6061	bzero(&unwrapping_key, sizeof (unwrapping_key));
6062
6063	session_id = STRUCT_FGET(unwrap_key, uk_session);
6064
6065	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
6066		goto release_minor;
6067	}
6068
6069	bcopy(STRUCT_FADDR(unwrap_key, uk_mechanism), &mech.cm_type,
6070	    sizeof (crypto_mech_type_t));
6071
6072	if ((rv = kcf_get_hardware_provider(mech.cm_type, CRYPTO_MECH_INVALID,
6073	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider,
6074	    CRYPTO_FG_UNWRAP)) != CRYPTO_SUCCESS) {
6075		goto release_minor;
6076	}
6077
6078	rv = crypto_provider_copyin_mech_param(real_provider,
6079	    STRUCT_FADDR(unwrap_key, uk_mechanism), &mech, mode, &error);
6080
6081	if (rv == CRYPTO_NOT_SUPPORTED) {
6082		allocated_by_crypto_module = B_TRUE;
6083		if (!copyin_mech(mode, sp,
6084		    STRUCT_FADDR(unwrap_key, uk_mechanism),
6085		    &mech, &mech_rctl_bytes, &mech_rctl_chk, &rv, &error)) {
6086			goto release_minor;
6087		}
6088	} else {
6089		if (rv != CRYPTO_SUCCESS)
6090			goto release_minor;
6091	}
6092
6093	if (!copyin_key(mode, sp, STRUCT_FADDR(unwrap_key, uk_unwrapping_key),
6094	    &unwrapping_key, &unwrapping_key_rctl_bytes,
6095	    &unwrapping_key_rctl_chk, &rv, &error)) {
6096		goto release_minor;
6097	}
6098
6099	count = STRUCT_FGET(unwrap_key, uk_count);
6100	uk_attributes = STRUCT_FGETP(unwrap_key, uk_attributes);
6101	if (!copyin_attributes(mode, sp, count, uk_attributes, &k_attrs,
6102	    &k_attrs_size, NULL, &rv, &error, &k_attrs_rctl_bytes,
6103	    &k_attrs_rctl_chk, B_TRUE)) {
6104		goto release_minor;
6105	}
6106
6107	wrapped_key_len = STRUCT_FGET(unwrap_key, uk_wrapped_key_len);
6108	if (wrapped_key_len > crypto_max_buffer_len) {
6109		cmn_err(CE_NOTE, "object_unwrap_key: buffer greater than %ld "
6110		    "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
6111		rv = CRYPTO_ARGUMENTS_BAD;
6112		goto release_minor;
6113	}
6114
6115	if ((rv = CRYPTO_BUFFER_CHECK(sp, wrapped_key_len,
6116	    wrapped_key_rctl_chk)) != CRYPTO_SUCCESS) {
6117		goto release_minor;
6118	}
6119	wrapped_key_rctl_bytes = wrapped_key_len;
6120	wrapped_key = kmem_alloc(wrapped_key_len, KM_SLEEP);
6121
6122	if (wrapped_key_len != 0 && copyin(STRUCT_FGETP(unwrap_key,
6123	    uk_wrapped_key), wrapped_key, wrapped_key_len) != 0) {
6124		error = EFAULT;
6125		goto release_minor;
6126	}
6127
6128	/* wrapped_key_len is not modified by the unwrap operation */
6129	KCF_WRAP_KEY_OPS_PARAMS(&params, KCF_OP_KEY_UNWRAP,
6130	    sp->sd_provider_session->ps_session, &mech, k_attrs, count, &handle,
6131	    NULL, 0, NULL, &unwrapping_key, wrapped_key, &wrapped_key_len);
6132
6133	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
6134
6135	if (rv == CRYPTO_SUCCESS)
6136		STRUCT_FSET(unwrap_key, uk_object_handle, handle);
6137
6138release_minor:
6139	CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
6140	CRYPTO_DECREMENT_RCTL_SESSION(sp, unwrapping_key_rctl_bytes,
6141	    unwrapping_key_rctl_chk);
6142	CRYPTO_DECREMENT_RCTL_SESSION(sp, wrapped_key_rctl_bytes,
6143	    wrapped_key_rctl_chk);
6144	CRYPTO_DECREMENT_RCTL_SESSION(sp, k_attrs_rctl_bytes,
6145	    k_attrs_rctl_chk);
6146
6147	if (k_attrs != NULL)
6148		kmem_free(k_attrs, k_attrs_size);
6149
6150	if (wrapped_key != NULL)
6151		kmem_free(wrapped_key, wrapped_key_len);
6152
6153	free_crypto_key(&unwrapping_key);
6154
6155	if (error != 0)
6156		goto out;
6157
6158	STRUCT_FSET(unwrap_key, uk_return_value, rv);
6159	if (copyout(STRUCT_BUF(unwrap_key), arg,
6160	    STRUCT_SIZE(unwrap_key)) != 0) {
6161		if (rv == CRYPTO_SUCCESS) {
6162			KCF_WRAP_OBJECT_OPS_PARAMS(&params,
6163			    KCF_OP_OBJECT_DESTROY,
6164			    sp->sd_provider_session->ps_session, handle,
6165			    NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
6166
6167			(void) kcf_submit_request(real_provider, NULL,
6168			    NULL, &params, B_FALSE);
6169
6170			error = EFAULT;
6171		}
6172	}
6173out:
6174	CRYPTO_SESSION_RELE(sp);
6175	crypto_release_minor(cm);
6176
6177	if (real_provider != NULL) {
6178		crypto_free_mech(real_provider,
6179		    allocated_by_crypto_module, &mech);
6180		KCF_PROV_REFRELE(real_provider);
6181	}
6182
6183	return (error);
6184}
6185
6186/* ARGSUSED */
6187static int
6188object_derive_key(dev_t dev, caddr_t arg, int mode, int *rval)
6189{
6190	STRUCT_DECL(crypto_derive_key, derive_key);
6191	kcf_provider_desc_t *real_provider = NULL;
6192	kcf_req_params_t params;
6193	crypto_object_attribute_t *k_attrs = NULL;
6194	crypto_mechanism_t mech;
6195	crypto_key_t base_key;
6196	crypto_session_id_t session_id;
6197	crypto_minor_t *cm;
6198	crypto_session_data_t *sp = NULL;
6199	crypto_object_id_t handle;
6200	size_t k_attrs_size;
6201	size_t key_rctl_bytes = 0, mech_rctl_bytes = 0;
6202	boolean_t mech_rctl_chk = B_FALSE;
6203	boolean_t key_rctl_chk = B_FALSE;
6204	size_t attributes_rctl_bytes = 0;
6205	boolean_t attributes_rctl_chk = B_FALSE;
6206	caddr_t attributes;
6207	uint_t count;
6208	int error = 0;
6209	int rv;
6210	boolean_t allocated_by_crypto_module = B_FALSE;
6211	boolean_t please_destroy_object = B_FALSE;
6212
6213	STRUCT_INIT(derive_key, mode);
6214
6215	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
6216		cmn_err(CE_WARN, "object_derive_key: failed holding minor");
6217		return (ENXIO);
6218	}
6219
6220	if (copyin(arg, STRUCT_BUF(derive_key), STRUCT_SIZE(derive_key)) != 0) {
6221		crypto_release_minor(cm);
6222		return (EFAULT);
6223	}
6224
6225	bzero(&base_key, sizeof (base_key));
6226
6227	session_id = STRUCT_FGET(derive_key, dk_session);
6228
6229	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
6230		goto release_minor;
6231	}
6232
6233	bcopy(STRUCT_FADDR(derive_key, dk_mechanism), &mech.cm_type,
6234	    sizeof (crypto_mech_type_t));
6235
6236	if ((rv = kcf_get_hardware_provider(mech.cm_type, CRYPTO_MECH_INVALID,
6237	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider,
6238	    CRYPTO_FG_DERIVE)) != CRYPTO_SUCCESS) {
6239		goto release_minor;
6240	}
6241
6242	rv = crypto_provider_copyin_mech_param(real_provider,
6243	    STRUCT_FADDR(derive_key, dk_mechanism), &mech, mode, &error);
6244
6245	if (rv == CRYPTO_NOT_SUPPORTED) {
6246		allocated_by_crypto_module = B_TRUE;
6247		if (!copyin_mech(mode, sp,
6248		    STRUCT_FADDR(derive_key, dk_mechanism),
6249		    &mech, &mech_rctl_bytes, &mech_rctl_chk, &rv, &error)) {
6250			goto release_minor;
6251		}
6252	} else {
6253		if (rv != CRYPTO_SUCCESS)
6254			goto release_minor;
6255	}
6256
6257	if (!copyin_key(mode, sp, STRUCT_FADDR(derive_key, dk_base_key),
6258	    &base_key, &key_rctl_bytes, &key_rctl_chk, &rv, &error)) {
6259		goto release_minor;
6260	}
6261
6262	count = STRUCT_FGET(derive_key, dk_count);
6263
6264	attributes = STRUCT_FGETP(derive_key, dk_attributes);
6265	if (!copyin_attributes(mode, sp, count, attributes, &k_attrs,
6266	    &k_attrs_size, NULL, &rv, &error,
6267	    &attributes_rctl_bytes, &attributes_rctl_chk, B_TRUE)) {
6268		goto release_minor;
6269	}
6270
6271	KCF_WRAP_KEY_OPS_PARAMS(&params, KCF_OP_KEY_DERIVE,
6272	    sp->sd_provider_session->ps_session, &mech, k_attrs, count,
6273	    &handle, NULL, 0, NULL, &base_key, NULL, NULL);
6274
6275	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
6276
6277	if (rv == CRYPTO_SUCCESS) {
6278		STRUCT_FSET(derive_key, dk_object_handle, handle);
6279
6280		rv = crypto_provider_copyout_mech_param(real_provider,
6281		    &mech, STRUCT_FADDR(derive_key, dk_mechanism),
6282		    mode, &error);
6283
6284		if (rv == CRYPTO_NOT_SUPPORTED) {
6285			rv = CRYPTO_SUCCESS;
6286			goto release_minor;
6287		}
6288
6289		if (rv != CRYPTO_SUCCESS)
6290			please_destroy_object = B_TRUE;
6291	}
6292
6293release_minor:
6294	CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
6295	CRYPTO_DECREMENT_RCTL_SESSION(sp, key_rctl_bytes, key_rctl_chk);
6296	CRYPTO_DECREMENT_RCTL_SESSION(sp, attributes_rctl_bytes,
6297	    attributes_rctl_chk);
6298
6299	if (k_attrs != NULL)
6300		kmem_free(k_attrs, k_attrs_size);
6301
6302	free_crypto_key(&base_key);
6303
6304	if (error != 0)
6305		goto out;
6306
6307	STRUCT_FSET(derive_key, dk_return_value, rv);
6308	if (copyout(STRUCT_BUF(derive_key), arg,
6309	    STRUCT_SIZE(derive_key)) != 0) {
6310		if (rv == CRYPTO_SUCCESS) {
6311			please_destroy_object = B_TRUE;
6312			error = EFAULT;
6313		}
6314	}
6315out:
6316	if (please_destroy_object) {
6317		KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_DESTROY,
6318		    sp->sd_provider_session->ps_session, handle,
6319		    NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
6320
6321		(void) kcf_submit_request(real_provider, NULL,
6322		    NULL, &params, B_FALSE);
6323	}
6324
6325	CRYPTO_SESSION_RELE(sp);
6326	crypto_release_minor(cm);
6327
6328	if (real_provider != NULL) {
6329		crypto_free_mech(real_provider,
6330		    allocated_by_crypto_module, &mech);
6331		KCF_PROV_REFRELE(real_provider);
6332	}
6333	return (error);
6334}
6335
6336/* ARGSUSED */
6337static int
6338nostore_derive_key(dev_t dev, caddr_t arg, int mode, int *rval)
6339{
6340	STRUCT_DECL(crypto_nostore_derive_key, derive_key);
6341	/* LINTED E_FUNC_SET_NOT_USED */
6342	STRUCT_DECL(crypto_object_attribute, oa);
6343	kcf_provider_desc_t *real_provider = NULL;
6344	kcf_req_params_t params;
6345	crypto_object_attribute_t *k_in_attrs = NULL;
6346	crypto_object_attribute_t *k_out_attrs = NULL;
6347	crypto_mechanism_t mech;
6348	crypto_key_t base_key;
6349	crypto_session_id_t session_id;
6350	crypto_minor_t *cm;
6351	crypto_session_data_t *sp = NULL;
6352	size_t k_in_attrs_size, k_out_attrs_size;
6353	size_t key_rctl_bytes = 0, mech_rctl_bytes = 0;
6354	boolean_t mech_rctl_chk = B_FALSE;
6355	boolean_t key_rctl_chk = B_FALSE;
6356	size_t in_attributes_rctl_bytes = 0;
6357	size_t out_attributes_rctl_bytes = 0;
6358	boolean_t in_attributes_rctl_chk = B_FALSE;
6359	boolean_t out_attributes_rctl_chk = B_FALSE;
6360	caddr_t in_attributes, out_attributes;
6361	uint_t in_count, out_count;
6362	int error = 0;
6363	int rv;
6364	boolean_t allocated_by_crypto_module = B_FALSE;
6365	caddr_t u_attrs = NULL;
6366
6367	STRUCT_INIT(derive_key, mode);
6368	STRUCT_INIT(oa, mode);
6369
6370	if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
6371		cmn_err(CE_WARN, "nostore_derive_key: failed holding minor");
6372		return (ENXIO);
6373	}
6374
6375	if (copyin(arg, STRUCT_BUF(derive_key), STRUCT_SIZE(derive_key)) != 0) {
6376		crypto_release_minor(cm);
6377		return (EFAULT);
6378	}
6379
6380	bzero(&base_key, sizeof (base_key));
6381
6382	session_id = STRUCT_FGET(derive_key, ndk_session);
6383
6384	if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
6385		goto release_minor;
6386	}
6387
6388	bcopy(STRUCT_FADDR(derive_key, ndk_mechanism), &mech.cm_type,
6389	    sizeof (crypto_mech_type_t));
6390
6391	if ((rv = kcf_get_hardware_provider(mech.cm_type, CRYPTO_MECH_INVALID,
6392	    CHECK_RESTRICT_FALSE, sp->sd_provider, &real_provider,
6393	    CRYPTO_FG_DERIVE)) != CRYPTO_SUCCESS) {
6394		goto release_minor;
6395	}
6396
6397	rv = crypto_provider_copyin_mech_param(real_provider,
6398	    STRUCT_FADDR(derive_key, ndk_mechanism), &mech, mode, &error);
6399
6400	if (rv == CRYPTO_NOT_SUPPORTED) {
6401		allocated_by_crypto_module = B_TRUE;
6402		if (!copyin_mech(mode, sp,
6403		    STRUCT_FADDR(derive_key, ndk_mechanism),
6404		    &mech, &mech_rctl_bytes, &mech_rctl_chk, &rv, &error)) {
6405			goto release_minor;
6406		}
6407	} else {
6408		if (rv != CRYPTO_SUCCESS)
6409			goto release_minor;
6410	}
6411
6412	if (!copyin_key(mode, sp, STRUCT_FADDR(derive_key, ndk_base_key),
6413	    &base_key, &key_rctl_bytes, &key_rctl_chk, &rv, &error)) {
6414		goto release_minor;
6415	}
6416
6417	in_count = STRUCT_FGET(derive_key, ndk_in_count);
6418	out_count = STRUCT_FGET(derive_key, ndk_out_count);
6419
6420	in_attributes = STRUCT_FGETP(derive_key, ndk_in_attributes);
6421	if (!copyin_attributes(mode, sp, in_count, in_attributes, &k_in_attrs,
6422	    &k_in_attrs_size, NULL, &rv, &error, &in_attributes_rctl_bytes,
6423	    &in_attributes_rctl_chk, B_TRUE)) {
6424		goto release_minor;
6425	}
6426
6427	out_attributes = STRUCT_FGETP(derive_key, ndk_out_attributes);
6428	if (!copyin_attributes(mode, sp, out_count, out_attributes,
6429	    &k_out_attrs, &k_out_attrs_size, &u_attrs, &rv, &error,
6430	    &out_attributes_rctl_bytes,
6431	    &out_attributes_rctl_chk, B_FALSE)) {
6432		goto release_minor;
6433	}
6434
6435	KCF_WRAP_NOSTORE_KEY_OPS_PARAMS(&params, KCF_OP_KEY_DERIVE,
6436	    sp->sd_provider_session->ps_session, &mech, k_in_attrs, in_count,
6437	    NULL, 0, &base_key, k_out_attrs, out_count, NULL, 0);
6438
6439	rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
6440
6441	if (rv == CRYPTO_SUCCESS) {
6442		rv = crypto_provider_copyout_mech_param(real_provider,
6443		    &mech, STRUCT_FADDR(derive_key, ndk_mechanism),
6444		    mode, &error);
6445
6446		if (rv == CRYPTO_NOT_SUPPORTED) {
6447			rv = CRYPTO_SUCCESS;
6448		}
6449		/* copyout the derived secret */
6450		if (copyout_attributes(mode, out_attributes, out_count,
6451		    k_out_attrs, u_attrs) != 0)
6452			error = EFAULT;
6453	}
6454
6455release_minor:
6456	CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
6457	CRYPTO_DECREMENT_RCTL_SESSION(sp, key_rctl_bytes, key_rctl_chk);
6458	CRYPTO_DECREMENT_RCTL_SESSION(sp, in_attributes_rctl_bytes,
6459	    in_attributes_rctl_chk);
6460	CRYPTO_DECREMENT_RCTL_SESSION(sp, out_attributes_rctl_bytes,
6461	    out_attributes_rctl_chk);
6462
6463	if (k_in_attrs != NULL)
6464		kmem_free(k_in_attrs, k_in_attrs_size);
6465	if (k_out_attrs != NULL) {
6466		bzero(k_out_attrs, k_out_attrs_size);
6467		kmem_free(k_out_attrs, k_out_attrs_size);
6468	}
6469
6470	if (u_attrs != NULL)
6471		kmem_free(u_attrs, out_count * STRUCT_SIZE(oa));
6472
6473	free_crypto_key(&base_key);
6474
6475	if (error != 0)
6476		goto out;
6477
6478	STRUCT_FSET(derive_key, ndk_return_value, rv);
6479	if (copyout(STRUCT_BUF(derive_key), arg,
6480	    STRUCT_SIZE(derive_key)) != 0) {
6481		error = EFAULT;
6482	}
6483out:
6484	CRYPTO_SESSION_RELE(sp);
6485	crypto_release_minor(cm);
6486
6487	if (real_provider != NULL) {
6488		crypto_free_mech(real_provider,
6489		    allocated_by_crypto_module, &mech);
6490		KCF_PROV_REFRELE(real_provider);
6491	}
6492	return (error);
6493}
6494
6495/* ARGSUSED */
6496static int
6497crypto_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *c,
6498    int *rval)
6499{
6500#define	ARG	((caddr_t)arg)
6501
6502	switch (cmd) {
6503	case CRYPTO_GET_FUNCTION_LIST:
6504		return (get_function_list(dev, ARG, mode, rval));
6505
6506	case CRYPTO_GET_MECHANISM_NUMBER:
6507		return (get_mechanism_number(dev, ARG, mode, rval));
6508
6509	case CRYPTO_GET_MECHANISM_LIST:
6510		return (get_mechanism_list(dev, ARG, mode, rval));
6511
6512	case CRYPTO_GET_ALL_MECHANISM_INFO:
6513		return (get_all_mechanism_info(dev, ARG, mode, rval));
6514
6515	case CRYPTO_GET_PROVIDER_LIST:
6516		return (get_provider_list(dev, ARG, mode, rval));
6517
6518	case CRYPTO_GET_PROVIDER_INFO:
6519		return (get_provider_info(dev, ARG, mode, rval));
6520
6521	case CRYPTO_GET_PROVIDER_MECHANISMS:
6522		return (get_provider_mechanisms(dev, ARG, mode, rval));
6523
6524	case CRYPTO_GET_PROVIDER_MECHANISM_INFO:
6525		return (get_provider_mechanism_info(dev, ARG, mode, rval));
6526
6527	case CRYPTO_OPEN_SESSION:
6528		return (open_session(dev, ARG, mode, rval));
6529
6530	case CRYPTO_CLOSE_SESSION:
6531		return (close_session(dev, ARG, mode, rval));
6532
6533	case CRYPTO_ENCRYPT_INIT:
6534		return (encrypt_init(dev, ARG, mode, rval));
6535
6536	case CRYPTO_DECRYPT_INIT:
6537		return (decrypt_init(dev, ARG, mode, rval));
6538
6539	case CRYPTO_ENCRYPT:
6540		return (encrypt(dev, ARG, mode, rval));
6541
6542	case CRYPTO_DECRYPT:
6543		return (decrypt(dev, ARG, mode, rval));
6544
6545	case CRYPTO_ENCRYPT_UPDATE:
6546		return (encrypt_update(dev, ARG, mode, rval));
6547
6548	case CRYPTO_DECRYPT_UPDATE:
6549		return (decrypt_update(dev, ARG, mode, rval));
6550
6551	case CRYPTO_ENCRYPT_FINAL:
6552		return (encrypt_final(dev, ARG, mode, rval));
6553
6554	case CRYPTO_DECRYPT_FINAL:
6555		return (decrypt_final(dev, ARG, mode, rval));
6556
6557	case CRYPTO_DIGEST_INIT:
6558		return (digest_init(dev, ARG, mode, rval));
6559
6560	case CRYPTO_DIGEST:
6561		return (digest(dev, ARG, mode, rval));
6562
6563	case CRYPTO_DIGEST_UPDATE:
6564		return (digest_update(dev, ARG, mode, rval));
6565
6566	case CRYPTO_DIGEST_KEY:
6567		return (digest_key(dev, ARG, mode, rval));
6568
6569	case CRYPTO_DIGEST_FINAL:
6570		return (digest_final(dev, ARG, mode, rval));
6571
6572	case CRYPTO_SIGN_INIT:
6573		return (sign_init(dev, ARG, mode, rval));
6574
6575	case CRYPTO_SIGN:
6576		return (sign(dev, ARG, mode, rval));
6577
6578	case CRYPTO_SIGN_UPDATE:
6579		return (sign_update(dev, ARG, mode, rval));
6580
6581	case CRYPTO_SIGN_FINAL:
6582		return (sign_final(dev, ARG, mode, rval));
6583
6584	case CRYPTO_SIGN_RECOVER_INIT:
6585		return (sign_recover_init(dev, ARG, mode, rval));
6586
6587	case CRYPTO_SIGN_RECOVER:
6588		return (sign_recover(dev, ARG, mode, rval));
6589
6590	case CRYPTO_VERIFY_INIT:
6591		return (verify_init(dev, ARG, mode, rval));
6592
6593	case CRYPTO_VERIFY:
6594		return (verify(dev, ARG, mode, rval));
6595
6596	case CRYPTO_VERIFY_UPDATE:
6597		return (verify_update(dev, ARG, mode, rval));
6598
6599	case CRYPTO_VERIFY_FINAL:
6600		return (verify_final(dev, ARG, mode, rval));
6601
6602	case CRYPTO_VERIFY_RECOVER_INIT:
6603		return (verify_recover_init(dev, ARG, mode, rval));
6604
6605	case CRYPTO_VERIFY_RECOVER:
6606		return (verify_recover(dev, ARG, mode, rval));
6607
6608	case CRYPTO_SET_PIN:
6609		return (set_pin(dev, ARG, mode, rval));
6610
6611	case CRYPTO_LOGIN:
6612		return (login(dev, ARG, mode, rval));
6613
6614	case CRYPTO_LOGOUT:
6615		return (logout(dev, ARG, mode, rval));
6616
6617	case CRYPTO_SEED_RANDOM:
6618		return (seed_random(dev, ARG, mode, rval));
6619
6620	case CRYPTO_GENERATE_RANDOM:
6621		return (generate_random(dev, ARG, mode, rval));
6622
6623	case CRYPTO_OBJECT_CREATE:
6624		return (object_create(dev, ARG, mode, rval));
6625
6626	case CRYPTO_OBJECT_COPY:
6627		return (object_copy(dev, ARG, mode, rval));
6628
6629	case CRYPTO_OBJECT_DESTROY:
6630		return (object_destroy(dev, ARG, mode, rval));
6631
6632	case CRYPTO_OBJECT_GET_ATTRIBUTE_VALUE:
6633		return (object_get_attribute_value(dev, ARG, mode, rval));
6634
6635	case CRYPTO_OBJECT_GET_SIZE:
6636		return (object_get_size(dev, ARG, mode, rval));
6637
6638	case CRYPTO_OBJECT_SET_ATTRIBUTE_VALUE:
6639		return (object_set_attribute_value(dev, ARG, mode, rval));
6640
6641	case CRYPTO_OBJECT_FIND_INIT:
6642		return (object_find_init(dev, ARG, mode, rval));
6643
6644	case CRYPTO_OBJECT_FIND_UPDATE:
6645		return (object_find_update(dev, ARG, mode, rval));
6646
6647	case CRYPTO_OBJECT_FIND_FINAL:
6648		return (object_find_final(dev, ARG, mode, rval));
6649
6650	case CRYPTO_GENERATE_KEY:
6651		return (object_generate_key(dev, ARG, mode, rval));
6652
6653	case CRYPTO_GENERATE_KEY_PAIR:
6654		return (object_generate_key_pair(dev, ARG, mode, rval));
6655
6656	case CRYPTO_WRAP_KEY:
6657		return (object_wrap_key(dev, ARG, mode, rval));
6658
6659	case CRYPTO_UNWRAP_KEY:
6660		return (object_unwrap_key(dev, ARG, mode, rval));
6661
6662	case CRYPTO_DERIVE_KEY:
6663		return (object_derive_key(dev, ARG, mode, rval));
6664
6665	case CRYPTO_NOSTORE_GENERATE_KEY:
6666		return (nostore_generate_key(dev, ARG, mode, rval));
6667
6668	case CRYPTO_NOSTORE_GENERATE_KEY_PAIR:
6669		return (nostore_generate_key_pair(dev, ARG, mode, rval));
6670
6671	case CRYPTO_NOSTORE_DERIVE_KEY:
6672		return (nostore_derive_key(dev, ARG, mode, rval));
6673	}
6674	return (EINVAL);
6675}
6676
6677/*
6678 * Check for the project.max-crypto-memory resource control.
6679 */
6680static int
6681crypto_buffer_check(size_t need)
6682{
6683	kproject_t *kpj;
6684
6685	if (need == 0)
6686		return (CRYPTO_SUCCESS);
6687
6688	mutex_enter(&curproc->p_lock);
6689	kpj = curproc->p_task->tk_proj;
6690	mutex_enter(&(kpj->kpj_data.kpd_crypto_lock));
6691
6692	if (kpj->kpj_data.kpd_crypto_mem + need >
6693	    kpj->kpj_data.kpd_crypto_mem_ctl) {
6694		if (rctl_test(rc_project_crypto_mem,
6695		    kpj->kpj_rctls, curproc, need, 0) & RCT_DENY) {
6696			mutex_exit(&(kpj->kpj_data.kpd_crypto_lock));
6697			mutex_exit(&curproc->p_lock);
6698			return (CRYPTO_HOST_MEMORY);
6699		}
6700	}
6701
6702	kpj->kpj_data.kpd_crypto_mem += need;
6703	mutex_exit(&(kpj->kpj_data.kpd_crypto_lock));
6704
6705	curproc->p_crypto_mem += need;
6706	mutex_exit(&curproc->p_lock);
6707
6708	return (CRYPTO_SUCCESS);
6709}
6710