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