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