Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / crypto / io / crypto.c
blob19c590ae296eb19dcfd65a2ddd06ad9e898966d9
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 * Copyright 2018, Joyent, Inc.
29 * The ioctl interface for cryptographic commands.
32 #include <sys/types.h>
33 #include <sys/modctl.h>
34 #include <sys/conf.h>
35 #include <sys/stat.h>
36 #include <sys/ddi.h>
37 #include <sys/sunddi.h>
38 #include <sys/kmem.h>
39 #include <sys/errno.h>
40 #include <sys/ksynch.h>
41 #include <sys/file.h>
42 #include <sys/open.h>
43 #include <sys/cred.h>
44 #include <sys/proc.h>
45 #include <sys/task.h>
46 #include <sys/mkdev.h>
47 #include <sys/model.h>
48 #include <sys/sysmacros.h>
49 #include <sys/crypto/common.h>
50 #include <sys/crypto/api.h>
51 #include <sys/crypto/impl.h>
52 #include <sys/crypto/sched_impl.h>
53 #include <sys/crypto/ioctl.h>
55 extern int kcf_des3_threshold;
56 extern int kcf_aes_threshold;
57 extern int kcf_rc4_threshold;
58 extern int kcf_md5_threshold;
59 extern int kcf_sha1_threshold;
62 * Locking notes:
64 * crypto_locks protects the global array of minor structures.
65 * crypto_locks is an array of locks indexed by the cpuid. A reader needs
66 * to hold a single lock while a writer needs to hold all locks.
67 * krwlock_t is not an option here because the hold time
68 * is very small for these locks.
70 * The fields in the minor structure are protected by the cm_lock member
71 * of the minor structure. The cm_cv is used to signal decrements
72 * in the cm_refcnt, and is used with the cm_lock.
74 * The locking order is crypto_locks followed by cm_lock.
78 * DDI entry points.
80 static int crypto_attach(dev_info_t *, ddi_attach_cmd_t);
81 static int crypto_detach(dev_info_t *, ddi_detach_cmd_t);
82 static int crypto_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
83 static int crypto_open(dev_t *, int, int, cred_t *);
84 static int crypto_close(dev_t, int, int, cred_t *);
85 static int crypto_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
87 static int cipher_init(dev_t, caddr_t, int, int (*)(crypto_provider_t,
88 crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
89 crypto_ctx_template_t, crypto_context_t *, crypto_call_req_t *));
91 static int common_digest(dev_t, caddr_t, int, int (*)(crypto_context_t,
92 crypto_data_t *, crypto_data_t *, crypto_call_req_t *));
94 static int cipher(dev_t, caddr_t, int, int (*)(crypto_context_t,
95 crypto_data_t *, crypto_data_t *, crypto_call_req_t *));
97 static int cipher_update(dev_t, caddr_t, int, int (*)(crypto_context_t,
98 crypto_data_t *, crypto_data_t *, crypto_call_req_t *));
100 static int common_final(dev_t, caddr_t, int, int (*)(crypto_context_t,
101 crypto_data_t *, crypto_call_req_t *));
103 static int sign_verify_init(dev_t, caddr_t, int, int (*)(crypto_provider_t,
104 crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
105 crypto_ctx_template_t, crypto_context_t *, crypto_call_req_t *));
107 static int sign_verify_update(dev_t dev, caddr_t arg, int mode,
108 int (*)(crypto_context_t, crypto_data_t *, crypto_call_req_t *));
110 static void crypto_release_provider_session(crypto_minor_t *,
111 crypto_provider_session_t *);
112 static int crypto_buffer_check(size_t);
113 static int crypto_free_find_ctx(crypto_session_data_t *);
114 static int crypto_get_provider_list(crypto_minor_t *, uint_t *,
115 crypto_provider_entry_t **, boolean_t);
117 static int crypto_create_provider_session(crypto_minor_t *,
118 kcf_provider_desc_t *, crypto_session_id_t, crypto_provider_session_t **,
119 kcf_provider_desc_t *);
120 static int crypto_create_session_ptr(crypto_minor_t *, kcf_provider_desc_t *,
121 crypto_provider_session_t *, crypto_session_id_t *);
123 /* number of minor numbers to allocate at a time */
124 #define CRYPTO_MINOR_CHUNK 16
127 * There are two limits associated with kernel memory. The first,
128 * CRYPTO_MAX_BUFFER_LEN, is the maximum number of bytes that can be
129 * allocated for a single copyin/copyout buffer. The second limit is
130 * the total number of bytes that can be allocated by a process
131 * for copyin/copyout buffers. The latter is enforced by the
132 * project.max-crypto-memory resource control.
135 #define CRYPTO_MAX_BUFFER_LEN (2 * 1024 * 1024)
136 #define CRYPTO_MAX_FIND_COUNT 512
139 * We preapprove some bytes for each session to avoid making the costly
140 * crypto_buffer_check() calls. The preapproval is done when a new session
141 * is created and that cost is amortized over later crypto calls.
142 * Most applications create a session and then do a bunch of crypto calls
143 * in that session. So, they benefit from this optimization.
145 * Note that we may hit the project.max-crypto-memory limit a bit sooner
146 * because of this preapproval. But it is acceptable since the preapproved
147 * amount is insignificant compared to the default max-crypto-memory limit
148 * which is quarter of the machine's memory. The preapproved amount is
149 * roughly 2 * 16K(maximum SSL record size).
151 #define CRYPTO_PRE_APPROVED_LIMIT (32 * 1024)
153 /* The session table grows by CRYPTO_SESSION_CHUNK increments */
154 #define CRYPTO_SESSION_CHUNK 100
156 size_t crypto_max_buffer_len = CRYPTO_MAX_BUFFER_LEN;
157 size_t crypto_pre_approved_limit = CRYPTO_PRE_APPROVED_LIMIT;
159 #define INIT_RAW_CRYPTO_DATA(data, len) \
160 (data).cd_format = CRYPTO_DATA_RAW; \
161 (data).cd_raw.iov_base = (len > 0) ? kmem_alloc(len, KM_SLEEP) : NULL; \
162 (data).cd_raw.iov_len = len; \
163 (data).cd_offset = 0; \
164 (data).cd_length = len;
166 static struct kmem_cache *crypto_session_cache;
167 static crypto_minor_t **crypto_minors = NULL;
168 static dev_info_t *crypto_dip = NULL;
169 static minor_t crypto_minor_chunk = CRYPTO_MINOR_CHUNK;
170 static minor_t crypto_minors_table_count = 0;
173 * Minors are started from 1 because vmem_alloc()
174 * returns 0 in case of failure.
176 static vmem_t *crypto_arena = NULL; /* Arena for device minors */
177 static minor_t crypto_minors_count = 0;
178 static kcf_lock_withpad_t *crypto_locks;
180 #define CRYPTO_ENTER_ALL_LOCKS() \
181 for (i = 0; i < max_ncpus; i++) \
182 mutex_enter(&crypto_locks[i].kl_lock);
184 #define CRYPTO_EXIT_ALL_LOCKS() \
185 for (i = 0; i < max_ncpus; i++) \
186 mutex_exit(&crypto_locks[i].kl_lock);
188 #define RETURN_LIST B_TRUE
189 #define DONT_RETURN_LIST B_FALSE
191 #define CRYPTO_OPS_OFFSET(f) offsetof(crypto_ops_t, co_##f)
192 #define CRYPTO_RANDOM_OFFSET(f) offsetof(crypto_random_number_ops_t, f)
193 #define CRYPTO_SESSION_OFFSET(f) offsetof(crypto_session_ops_t, f)
194 #define CRYPTO_OBJECT_OFFSET(f) offsetof(crypto_object_ops_t, f)
195 #define CRYPTO_PROVIDER_OFFSET(f) \
196 offsetof(crypto_provider_management_ops_t, f)
198 #define CRYPTO_CANCEL_CTX(spp) { \
199 crypto_cancel_ctx(*(spp)); \
200 *(spp) = NULL; \
203 #define CRYPTO_CANCEL_ALL_CTX(sp) { \
204 if ((sp)->sd_digest_ctx != NULL) { \
205 crypto_cancel_ctx((sp)->sd_digest_ctx); \
206 (sp)->sd_digest_ctx = NULL; \
208 if ((sp)->sd_encr_ctx != NULL) { \
209 crypto_cancel_ctx((sp)->sd_encr_ctx); \
210 (sp)->sd_encr_ctx = NULL; \
212 if ((sp)->sd_decr_ctx != NULL) { \
213 crypto_cancel_ctx((sp)->sd_decr_ctx); \
214 (sp)->sd_decr_ctx = NULL; \
216 if ((sp)->sd_sign_ctx != NULL) { \
217 crypto_cancel_ctx((sp)->sd_sign_ctx); \
218 (sp)->sd_sign_ctx = NULL; \
220 if ((sp)->sd_verify_ctx != NULL) { \
221 crypto_cancel_ctx((sp)->sd_verify_ctx); \
222 (sp)->sd_verify_ctx = NULL; \
224 if ((sp)->sd_sign_recover_ctx != NULL) { \
225 crypto_cancel_ctx((sp)->sd_sign_recover_ctx); \
226 (sp)->sd_sign_recover_ctx = NULL; \
228 if ((sp)->sd_verify_recover_ctx != NULL) { \
229 crypto_cancel_ctx((sp)->sd_verify_recover_ctx); \
230 (sp)->sd_verify_recover_ctx = NULL; \
232 if ((sp)->sd_mac_ctx != NULL) { \
233 crypto_cancel_ctx((sp)->sd_mac_ctx); \
234 (sp)->sd_mac_ctx = NULL; \
238 #define CRYPTO_DECREMENT_RCTL(val) if ((val) != 0) { \
239 kproject_t *projp; \
240 mutex_enter(&curproc->p_lock); \
241 projp = curproc->p_task->tk_proj; \
242 ASSERT(projp != NULL); \
243 mutex_enter(&(projp->kpj_data.kpd_crypto_lock)); \
244 projp->kpj_data.kpd_crypto_mem -= (val); \
245 mutex_exit(&(projp->kpj_data.kpd_crypto_lock)); \
246 curproc->p_crypto_mem -= (val); \
247 mutex_exit(&curproc->p_lock); \
251 * We do not need to hold sd_lock in the macros below
252 * as they are called after doing a get_session_ptr() which
253 * sets the CRYPTO_SESSION_IS_BUSY flag.
255 #define CRYPTO_DECREMENT_RCTL_SESSION(sp, val, rctl_chk) \
256 if (((val) != 0) && ((sp) != NULL)) { \
257 ASSERT(((sp)->sd_flags & CRYPTO_SESSION_IS_BUSY) != 0); \
258 if (rctl_chk) { \
259 CRYPTO_DECREMENT_RCTL(val); \
260 } else { \
261 (sp)->sd_pre_approved_amount += (val); \
265 #define CRYPTO_BUFFER_CHECK(sp, need, rctl_chk) \
266 ((sp->sd_pre_approved_amount >= need) ? \
267 (sp->sd_pre_approved_amount -= need, \
268 rctl_chk = B_FALSE, CRYPTO_SUCCESS) : \
269 (rctl_chk = B_TRUE, crypto_buffer_check(need)))
272 * Module linkage.
274 static struct cb_ops cbops = {
275 crypto_open, /* cb_open */
276 crypto_close, /* cb_close */
277 nodev, /* cb_strategy */
278 nodev, /* cb_print */
279 nodev, /* cb_dump */
280 nodev, /* cb_read */
281 nodev, /* cb_write */
282 crypto_ioctl, /* cb_ioctl */
283 nodev, /* cb_devmap */
284 nodev, /* cb_mmap */
285 nodev, /* cb_segmap */
286 nochpoll, /* cb_chpoll */
287 ddi_prop_op, /* cb_prop_op */
288 NULL, /* cb_streamtab */
289 D_MP, /* cb_flag */
290 CB_REV, /* cb_rev */
291 nodev, /* cb_aread */
292 nodev, /* cb_awrite */
295 static struct dev_ops devops = {
296 DEVO_REV, /* devo_rev */
297 0, /* devo_refcnt */
298 crypto_getinfo, /* devo_getinfo */
299 nulldev, /* devo_identify */
300 nulldev, /* devo_probe */
301 crypto_attach, /* devo_attach */
302 crypto_detach, /* devo_detach */
303 nodev, /* devo_reset */
304 &cbops, /* devo_cb_ops */
305 NULL, /* devo_bus_ops */
306 NULL, /* devo_power */
307 ddi_quiesce_not_needed, /* devo_quiesce */
310 static struct modldrv modldrv = {
311 &mod_driverops, /* drv_modops */
312 "Cryptographic Library Interface", /* drv_linkinfo */
313 &devops,
316 static struct modlinkage modlinkage = {
317 MODREV_1, /* ml_rev */
318 &modldrv, /* ml_linkage */
319 NULL
323 * DDI entry points.
326 _init(void)
328 return (mod_install(&modlinkage));
332 _fini(void)
334 return (mod_remove(&modlinkage));
338 _info(struct modinfo *modinfop)
340 return (mod_info(&modlinkage, modinfop));
343 /* ARGSUSED */
344 static int
345 crypto_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
347 switch (cmd) {
348 case DDI_INFO_DEVT2DEVINFO:
349 *result = crypto_dip;
350 return (DDI_SUCCESS);
352 case DDI_INFO_DEVT2INSTANCE:
353 *result = NULL;
354 return (DDI_SUCCESS);
356 return (DDI_FAILURE);
359 static int
360 crypto_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
362 int i;
364 if (cmd != DDI_ATTACH) {
365 return (DDI_FAILURE);
368 if (ddi_get_instance(dip) != 0) {
369 /* we only allow instance 0 to attach */
370 return (DDI_FAILURE);
373 crypto_session_cache = kmem_cache_create("crypto_session_cache",
374 sizeof (crypto_session_data_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
376 if (crypto_session_cache == NULL)
377 return (DDI_FAILURE);
379 /* create the minor node */
380 if (ddi_create_minor_node(dip, "crypto", S_IFCHR, 0,
381 DDI_PSEUDO, 0) != DDI_SUCCESS) {
382 kmem_cache_destroy(crypto_session_cache);
383 crypto_session_cache = NULL;
384 cmn_err(CE_WARN, "crypto_attach: failed creating minor node");
385 ddi_remove_minor_node(dip, NULL);
386 return (DDI_FAILURE);
389 crypto_locks = kmem_zalloc(max_ncpus * sizeof (kcf_lock_withpad_t),
390 KM_SLEEP);
391 for (i = 0; i < max_ncpus; i++)
392 mutex_init(&crypto_locks[i].kl_lock, NULL, MUTEX_DRIVER, NULL);
394 crypto_dip = dip;
396 /* allocate integer space for minor numbers */
397 crypto_arena = vmem_create("crypto", (void *)1,
398 CRYPTO_MINOR_CHUNK, 1, NULL, NULL, NULL, 0,
399 VM_SLEEP | VMC_IDENTIFIER);
401 return (DDI_SUCCESS);
404 static int
405 crypto_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
407 minor_t i;
408 kcf_lock_withpad_t *mp;
410 if (cmd != DDI_DETACH)
411 return (DDI_FAILURE);
413 mp = &crypto_locks[CPU_SEQID];
414 mutex_enter(&mp->kl_lock);
416 /* check if device is open */
417 for (i = 0; i < crypto_minors_table_count; i++) {
418 if (crypto_minors[i] != NULL) {
419 mutex_exit(&mp->kl_lock);
420 return (DDI_FAILURE);
423 mutex_exit(&mp->kl_lock);
425 crypto_dip = NULL;
426 ddi_remove_minor_node(dip, NULL);
428 kmem_cache_destroy(crypto_session_cache);
429 crypto_session_cache = NULL;
431 kmem_free(crypto_minors,
432 sizeof (crypto_minor_t *) * crypto_minors_table_count);
433 crypto_minors = NULL;
434 crypto_minors_table_count = 0;
435 for (i = 0; i < max_ncpus; i++)
436 mutex_destroy(&crypto_locks[i].kl_lock);
437 kmem_free(crypto_locks, max_ncpus * sizeof (kcf_lock_withpad_t));
438 crypto_locks = NULL;
440 vmem_destroy(crypto_arena);
441 crypto_arena = NULL;
443 return (DDI_SUCCESS);
446 /* ARGSUSED3 */
447 static int
448 crypto_open(dev_t *devp, int flag, int otyp, cred_t *credp)
450 crypto_minor_t *cm = NULL;
451 minor_t mn;
452 kcf_lock_withpad_t *mp;
453 int i;
455 if (otyp != OTYP_CHR)
456 return (ENXIO);
458 if (crypto_dip == NULL)
459 return (ENXIO);
461 /* exclusive opens are not supported */
462 if (flag & FEXCL)
463 return (ENOTSUP);
465 again:
466 mp = &crypto_locks[CPU_SEQID];
467 mutex_enter(&mp->kl_lock);
469 /* grow the minors table if needed */
470 if (crypto_minors_count >= crypto_minors_table_count) {
471 crypto_minor_t **newtable;
472 minor_t chunk = crypto_minor_chunk;
473 minor_t saved_count;
474 size_t new_size;
475 ulong_t big_count;
477 big_count = crypto_minors_count + chunk;
478 if (big_count > MAXMIN) {
479 mutex_exit(&mp->kl_lock);
480 return (ENOMEM);
483 saved_count = crypto_minors_table_count;
484 new_size = sizeof (crypto_minor_t *) *
485 (crypto_minors_table_count + chunk);
487 mutex_exit(&mp->kl_lock);
489 newtable = kmem_zalloc(new_size, KM_SLEEP);
490 CRYPTO_ENTER_ALL_LOCKS();
492 * Check if table grew while we were sleeping.
493 * The minors table never shrinks.
495 if (crypto_minors_table_count > saved_count) {
496 CRYPTO_EXIT_ALL_LOCKS();
497 kmem_free(newtable, new_size);
498 goto again;
501 /* we assume that bcopy() will return if count is 0 */
502 bcopy(crypto_minors, newtable,
503 sizeof (crypto_minor_t *) * crypto_minors_table_count);
505 kmem_free(crypto_minors,
506 sizeof (crypto_minor_t *) * crypto_minors_table_count);
508 /* grow the minors number space */
509 if (crypto_minors_table_count != 0) {
510 (void) vmem_add(crypto_arena,
511 (void *)(uintptr_t)(crypto_minors_table_count + 1),
512 crypto_minor_chunk, VM_SLEEP);
515 crypto_minors = newtable;
516 crypto_minors_table_count += chunk;
517 CRYPTO_EXIT_ALL_LOCKS();
518 } else {
519 mutex_exit(&mp->kl_lock);
522 /* allocate a new minor number starting with 1 */
523 mn = (minor_t)(uintptr_t)vmem_alloc(crypto_arena, 1, VM_SLEEP);
525 cm = kmem_zalloc(sizeof (crypto_minor_t), KM_SLEEP);
526 mutex_init(&cm->cm_lock, NULL, MUTEX_DRIVER, NULL);
527 cv_init(&cm->cm_cv, NULL, CV_DRIVER, NULL);
529 CRYPTO_ENTER_ALL_LOCKS();
530 cm->cm_refcnt = 1;
531 crypto_minors[mn - 1] = cm;
532 crypto_minors_count++;
533 CRYPTO_EXIT_ALL_LOCKS();
535 *devp = makedevice(getmajor(*devp), mn);
537 return (0);
540 /* ARGSUSED1 */
541 static int
542 crypto_close(dev_t dev, int flag, int otyp, cred_t *credp)
544 crypto_minor_t *cm = NULL;
545 crypto_session_data_t *sp;
546 minor_t mn = getminor(dev);
547 uint_t i;
548 size_t total = 0;
549 kcf_lock_withpad_t *mp;
551 mp = &crypto_locks[CPU_SEQID];
552 mutex_enter(&mp->kl_lock);
554 if (mn > crypto_minors_table_count) {
555 mutex_exit(&mp->kl_lock);
556 cmn_err(CE_WARN, "crypto_close: bad minor (too big) %d", mn);
557 return (ENODEV);
560 cm = crypto_minors[mn - 1];
561 if (cm == NULL) {
562 mutex_exit(&mp->kl_lock);
563 cmn_err(CE_WARN, "crypto_close: duplicate close of minor %d",
564 getminor(dev));
565 return (ENODEV);
568 mutex_exit(&mp->kl_lock);
570 CRYPTO_ENTER_ALL_LOCKS();
572 * We free the minor number, mn, from the crypto_arena
573 * only later. This ensures that we won't race with another
574 * thread in crypto_open with the same minor number.
576 crypto_minors[mn - 1] = NULL;
577 crypto_minors_count--;
578 CRYPTO_EXIT_ALL_LOCKS();
580 mutex_enter(&cm->cm_lock);
581 cm->cm_refcnt --; /* decrement refcnt held in open */
582 while (cm->cm_refcnt > 0) {
583 cv_wait(&cm->cm_cv, &cm->cm_lock);
586 vmem_free(crypto_arena, (void *)(uintptr_t)mn, 1);
588 /* free all session table entries starting with 1 */
589 for (i = 1; i < cm->cm_session_table_count; i++) {
590 if (cm->cm_session_table[i] == NULL)
591 continue;
593 sp = cm->cm_session_table[i];
594 ASSERT((sp->sd_flags & CRYPTO_SESSION_IS_BUSY) == 0);
595 ASSERT(sp->sd_pre_approved_amount == 0 ||
596 sp->sd_pre_approved_amount == crypto_pre_approved_limit);
597 total += sp->sd_pre_approved_amount;
598 if (sp->sd_find_init_cookie != NULL) {
599 (void) crypto_free_find_ctx(sp);
601 crypto_release_provider_session(cm, sp->sd_provider_session);
602 KCF_PROV_REFRELE(sp->sd_provider);
603 CRYPTO_CANCEL_ALL_CTX(sp);
604 mutex_destroy(&sp->sd_lock);
605 cv_destroy(&sp->sd_cv);
606 kmem_cache_free(crypto_session_cache, sp);
607 cm->cm_session_table[i] = NULL;
610 /* free the session table */
611 if (cm->cm_session_table != NULL && cm->cm_session_table_count > 0)
612 kmem_free(cm->cm_session_table, cm->cm_session_table_count *
613 sizeof (void *));
615 total += (cm->cm_session_table_count * sizeof (void *));
616 CRYPTO_DECREMENT_RCTL(total);
618 kcf_free_provider_tab(cm->cm_provider_count,
619 cm->cm_provider_array);
621 mutex_exit(&cm->cm_lock);
622 mutex_destroy(&cm->cm_lock);
623 cv_destroy(&cm->cm_cv);
624 kmem_free(cm, sizeof (crypto_minor_t));
626 return (0);
629 static crypto_minor_t *
630 crypto_hold_minor(minor_t minor)
632 crypto_minor_t *cm;
633 kcf_lock_withpad_t *mp;
635 if (minor > crypto_minors_table_count)
636 return (NULL);
638 mp = &crypto_locks[CPU_SEQID];
639 mutex_enter(&mp->kl_lock);
641 if ((cm = crypto_minors[minor - 1]) != NULL) {
642 atomic_inc_32(&cm->cm_refcnt);
644 mutex_exit(&mp->kl_lock);
645 return (cm);
648 static void
649 crypto_release_minor(crypto_minor_t *cm)
651 if (atomic_dec_32_nv(&cm->cm_refcnt) == 0) {
652 cv_signal(&cm->cm_cv);
657 * Build a list of functions and other information for the provider, pd.
659 static void
660 crypto_build_function_list(crypto_function_list_t *fl, kcf_provider_desc_t *pd)
662 crypto_ops_t *ops;
663 crypto_digest_ops_t *digest_ops;
664 crypto_cipher_ops_t *cipher_ops;
665 crypto_mac_ops_t *mac_ops;
666 crypto_sign_ops_t *sign_ops;
667 crypto_verify_ops_t *verify_ops;
668 crypto_dual_ops_t *dual_ops;
669 crypto_random_number_ops_t *random_number_ops;
670 crypto_session_ops_t *session_ops;
671 crypto_object_ops_t *object_ops;
672 crypto_key_ops_t *key_ops;
673 crypto_provider_management_ops_t *provider_ops;
675 if ((ops = pd->pd_ops_vector) == NULL)
676 return;
678 if ((digest_ops = ops->co_digest_ops) != NULL) {
679 if (digest_ops->digest_init != NULL)
680 fl->fl_digest_init = B_TRUE;
681 if (digest_ops->digest != NULL)
682 fl->fl_digest = B_TRUE;
683 if (digest_ops->digest_update != NULL)
684 fl->fl_digest_update = B_TRUE;
685 if (digest_ops->digest_key != NULL)
686 fl->fl_digest_key = B_TRUE;
687 if (digest_ops->digest_final != NULL)
688 fl->fl_digest_final = B_TRUE;
690 if ((cipher_ops = ops->co_cipher_ops) != NULL) {
691 if (cipher_ops->encrypt_init != NULL)
692 fl->fl_encrypt_init = B_TRUE;
693 if (cipher_ops->encrypt != NULL)
694 fl->fl_encrypt = B_TRUE;
695 if (cipher_ops->encrypt_update != NULL)
696 fl->fl_encrypt_update = B_TRUE;
697 if (cipher_ops->encrypt_final != NULL)
698 fl->fl_encrypt_final = B_TRUE;
699 if (cipher_ops->decrypt_init != NULL)
700 fl->fl_decrypt_init = B_TRUE;
701 if (cipher_ops->decrypt != NULL)
702 fl->fl_decrypt = B_TRUE;
703 if (cipher_ops->decrypt_update != NULL)
704 fl->fl_decrypt_update = B_TRUE;
705 if (cipher_ops->decrypt_final != NULL)
706 fl->fl_decrypt_final = B_TRUE;
708 if ((mac_ops = ops->co_mac_ops) != NULL) {
709 if (mac_ops->mac_init != NULL)
710 fl->fl_mac_init = B_TRUE;
711 if (mac_ops->mac != NULL)
712 fl->fl_mac = B_TRUE;
713 if (mac_ops->mac_update != NULL)
714 fl->fl_mac_update = B_TRUE;
715 if (mac_ops->mac_final != NULL)
716 fl->fl_mac_final = B_TRUE;
718 if ((sign_ops = ops->co_sign_ops) != NULL) {
719 if (sign_ops->sign_init != NULL)
720 fl->fl_sign_init = B_TRUE;
721 if (sign_ops->sign != NULL)
722 fl->fl_sign = B_TRUE;
723 if (sign_ops->sign_update != NULL)
724 fl->fl_sign_update = B_TRUE;
725 if (sign_ops->sign_final != NULL)
726 fl->fl_sign_final = B_TRUE;
727 if (sign_ops->sign_recover_init != NULL)
728 fl->fl_sign_recover_init = B_TRUE;
729 if (sign_ops->sign_recover != NULL)
730 fl->fl_sign_recover = B_TRUE;
732 if ((verify_ops = ops->co_verify_ops) != NULL) {
733 if (verify_ops->verify_init != NULL)
734 fl->fl_verify_init = B_TRUE;
735 if (verify_ops->verify != NULL)
736 fl->fl_verify = B_TRUE;
737 if (verify_ops->verify_update != NULL)
738 fl->fl_verify_update = B_TRUE;
739 if (verify_ops->verify_final != NULL)
740 fl->fl_verify_final = B_TRUE;
741 if (verify_ops->verify_recover_init != NULL)
742 fl->fl_verify_recover_init = B_TRUE;
743 if (verify_ops->verify_recover != NULL)
744 fl->fl_verify_recover = B_TRUE;
746 if ((dual_ops = ops->co_dual_ops) != NULL) {
747 if (dual_ops->digest_encrypt_update != NULL)
748 fl->fl_digest_encrypt_update = B_TRUE;
749 if (dual_ops->decrypt_digest_update != NULL)
750 fl->fl_decrypt_digest_update = B_TRUE;
751 if (dual_ops->sign_encrypt_update != NULL)
752 fl->fl_sign_encrypt_update = B_TRUE;
753 if (dual_ops->decrypt_verify_update != NULL)
754 fl->fl_decrypt_verify_update = B_TRUE;
756 if ((random_number_ops = ops->co_random_ops) != NULL) {
757 if (random_number_ops->seed_random != NULL)
758 fl->fl_seed_random = B_TRUE;
759 if (random_number_ops->generate_random != NULL)
760 fl->fl_generate_random = B_TRUE;
762 if ((session_ops = ops->co_session_ops) != NULL) {
763 if (session_ops->session_open != NULL)
764 fl->fl_session_open = B_TRUE;
765 if (session_ops->session_close != NULL)
766 fl->fl_session_close = B_TRUE;
767 if (session_ops->session_login != NULL)
768 fl->fl_session_login = B_TRUE;
769 if (session_ops->session_logout != NULL)
770 fl->fl_session_logout = B_TRUE;
772 if ((object_ops = ops->co_object_ops) != NULL) {
773 if (object_ops->object_create != NULL)
774 fl->fl_object_create = B_TRUE;
775 if (object_ops->object_copy != NULL)
776 fl->fl_object_copy = B_TRUE;
777 if (object_ops->object_destroy != NULL)
778 fl->fl_object_destroy = B_TRUE;
779 if (object_ops->object_get_size != NULL)
780 fl->fl_object_get_size = B_TRUE;
781 if (object_ops->object_get_attribute_value != NULL)
782 fl->fl_object_get_attribute_value = B_TRUE;
783 if (object_ops->object_set_attribute_value != NULL)
784 fl->fl_object_set_attribute_value = B_TRUE;
785 if (object_ops->object_find_init != NULL)
786 fl->fl_object_find_init = B_TRUE;
787 if (object_ops->object_find != NULL)
788 fl->fl_object_find = B_TRUE;
789 if (object_ops->object_find_final != NULL)
790 fl->fl_object_find_final = B_TRUE;
792 if ((key_ops = ops->co_key_ops) != NULL) {
793 if (key_ops->key_generate != NULL)
794 fl->fl_key_generate = B_TRUE;
795 if (key_ops->key_generate_pair != NULL)
796 fl->fl_key_generate_pair = B_TRUE;
797 if (key_ops->key_wrap != NULL)
798 fl->fl_key_wrap = B_TRUE;
799 if (key_ops->key_unwrap != NULL)
800 fl->fl_key_unwrap = B_TRUE;
801 if (key_ops->key_derive != NULL)
802 fl->fl_key_derive = B_TRUE;
804 if ((provider_ops = ops->co_provider_ops) != NULL) {
805 if (provider_ops->init_token != NULL)
806 fl->fl_init_token = B_TRUE;
807 if (provider_ops->init_pin != NULL)
808 fl->fl_init_pin = B_TRUE;
809 if (provider_ops->set_pin != NULL)
810 fl->fl_set_pin = B_TRUE;
813 fl->prov_is_hash_limited = pd->pd_flags & CRYPTO_HASH_NO_UPDATE;
814 if (fl->prov_is_hash_limited) {
815 fl->prov_hash_limit = min(pd->pd_hash_limit,
816 min(CRYPTO_MAX_BUFFER_LEN,
817 curproc->p_task->tk_proj->kpj_data.kpd_crypto_mem_ctl));
820 fl->prov_is_hmac_limited = pd->pd_flags & CRYPTO_HMAC_NO_UPDATE;
821 if (fl->prov_is_hmac_limited) {
822 fl->prov_hmac_limit = min(pd->pd_hmac_limit,
823 min(CRYPTO_MAX_BUFFER_LEN,
824 curproc->p_task->tk_proj->kpj_data.kpd_crypto_mem_ctl));
827 if (fl->prov_is_hash_limited || fl->prov_is_hmac_limited) {
829 * XXX - The threshold should ideally be per hash/HMAC
830 * mechanism. For now, we use the same value for all
831 * hash/HMAC mechanisms. Empirical evidence suggests this
832 * is fine.
834 fl->prov_hash_threshold = kcf_md5_threshold;
837 fl->total_threshold_count = MAX_NUM_THRESHOLD;
838 fl->fl_threshold[0].mech_type = CKM_DES3_CBC;
839 fl->fl_threshold[0].mech_threshold = kcf_des3_threshold;
840 fl->fl_threshold[1].mech_type = CKM_DES3_ECB;
841 fl->fl_threshold[1].mech_threshold = kcf_des3_threshold;
842 fl->fl_threshold[2].mech_type = CKM_AES_CBC;
843 fl->fl_threshold[2].mech_threshold = kcf_aes_threshold;
844 fl->fl_threshold[3].mech_type = CKM_AES_ECB;
845 fl->fl_threshold[3].mech_threshold = kcf_aes_threshold;
846 fl->fl_threshold[4].mech_type = CKM_RC4;
847 fl->fl_threshold[4].mech_threshold = kcf_rc4_threshold;
848 fl->fl_threshold[5].mech_type = CKM_MD5;
849 fl->fl_threshold[5].mech_threshold = kcf_md5_threshold;
850 fl->fl_threshold[6].mech_type = CKM_SHA_1;
851 fl->fl_threshold[6].mech_threshold = kcf_sha1_threshold;
854 /* ARGSUSED */
855 static int
856 get_function_list(dev_t dev, caddr_t arg, int mode, int *rval)
858 crypto_get_function_list_t get_function_list;
859 crypto_minor_t *cm;
860 crypto_provider_id_t provider_id;
861 crypto_function_list_t *fl;
862 kcf_provider_desc_t *provider;
863 int rv;
865 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
866 cmn_err(CE_WARN, "get_function_list: failed holding minor");
867 return (ENXIO);
870 if (copyin(arg, &get_function_list, sizeof (get_function_list)) != 0) {
871 crypto_release_minor(cm);
872 return (EFAULT);
875 /* initialize provider_array */
876 if (cm->cm_provider_array == NULL) {
877 rv = crypto_get_provider_list(cm, NULL, NULL, DONT_RETURN_LIST);
878 if (rv != CRYPTO_SUCCESS) {
879 goto release_minor;
883 provider_id = get_function_list.fl_provider_id;
884 mutex_enter(&cm->cm_lock);
885 /* index must be less than count of providers */
886 if (provider_id >= cm->cm_provider_count) {
887 mutex_exit(&cm->cm_lock);
888 rv = CRYPTO_ARGUMENTS_BAD;
889 goto release_minor;
892 ASSERT(cm->cm_provider_array != NULL);
893 provider = cm->cm_provider_array[provider_id];
894 mutex_exit(&cm->cm_lock);
896 fl = &get_function_list.fl_list;
897 bzero(fl, sizeof (crypto_function_list_t));
899 if (provider->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
900 crypto_build_function_list(fl, provider);
901 } else {
902 kcf_provider_desc_t *prev = NULL, *pd;
904 mutex_enter(&provider->pd_lock);
905 while (kcf_get_next_logical_provider_member(provider,
906 prev, &pd)) {
907 prev = pd;
908 crypto_build_function_list(fl, pd);
909 KCF_PROV_REFRELE(pd);
911 mutex_exit(&provider->pd_lock);
914 rv = CRYPTO_SUCCESS;
916 release_minor:
917 crypto_release_minor(cm);
919 get_function_list.fl_return_value = rv;
921 if (copyout(&get_function_list, arg, sizeof (get_function_list)) != 0) {
922 return (EFAULT);
924 return (0);
928 * This ioctl maps a PKCS#11 mechanism string into an internal number
929 * that is used by the kernel. pn_internal_number is set to the
930 * internal number.
932 /* ARGSUSED */
933 static int
934 get_mechanism_number(dev_t dev, caddr_t arg, int mode, int *rval)
936 STRUCT_DECL(crypto_get_mechanism_number, get_number);
937 crypto_mech_type_t number;
938 size_t len;
939 char *mechanism_name;
940 int rv;
942 STRUCT_INIT(get_number, mode);
944 if (copyin(arg, STRUCT_BUF(get_number), STRUCT_SIZE(get_number)) != 0)
945 return (EFAULT);
947 len = STRUCT_FGET(get_number, pn_mechanism_len);
948 if (len == 0 || len > CRYPTO_MAX_MECH_NAME) {
949 rv = CRYPTO_ARGUMENTS_BAD;
950 goto out;
952 mechanism_name = kmem_alloc(len, KM_SLEEP);
954 if (copyin(STRUCT_FGETP(get_number, pn_mechanism_string),
955 mechanism_name, len) != 0) {
956 kmem_free(mechanism_name, len);
957 return (EFAULT);
961 * Get mechanism number from kcf. We set the load_module
962 * flag to false since we use only hardware providers.
964 number = crypto_mech2id_common(mechanism_name, B_FALSE);
965 kmem_free(mechanism_name, len);
966 if (number == CRYPTO_MECH_INVALID) {
967 rv = CRYPTO_ARGUMENTS_BAD;
968 goto out;
971 bcopy((char *)&number, (char *)STRUCT_FADDR(get_number,
972 pn_internal_number), sizeof (number));
974 rv = CRYPTO_SUCCESS;
975 out:
976 STRUCT_FSET(get_number, pn_return_value, rv);
978 if (copyout(STRUCT_BUF(get_number), arg,
979 STRUCT_SIZE(get_number)) != 0) {
980 return (EFAULT);
982 return (0);
986 * This ioctl returns an array of crypto_mech_name_t entries.
987 * It lists all the PKCS#11 mechanisms available in the kernel.
989 /* ARGSUSED */
990 static int
991 get_mechanism_list(dev_t dev, caddr_t arg, int mode, int *rval)
993 STRUCT_DECL(crypto_get_mechanism_list, get_list);
994 crypto_mech_name_t *entries;
995 size_t copyout_size;
996 uint_t req_count;
997 uint_t count;
998 ulong_t offset;
999 int error = 0;
1001 STRUCT_INIT(get_list, mode);
1003 if (copyin(arg, STRUCT_BUF(get_list), STRUCT_SIZE(get_list)) != 0) {
1004 return (EFAULT);
1007 entries = crypto_get_mech_list(&count, KM_SLEEP);
1009 /* Number of entries caller thinks we have */
1010 req_count = STRUCT_FGET(get_list, ml_count);
1012 STRUCT_FSET(get_list, ml_count, count);
1013 STRUCT_FSET(get_list, ml_return_value, CRYPTO_SUCCESS);
1015 /* check if buffer is too small */
1016 if (count > req_count) {
1017 STRUCT_FSET(get_list, ml_return_value, CRYPTO_BUFFER_TOO_SMALL);
1020 /* copyout the first stuff */
1021 if (copyout(STRUCT_BUF(get_list), arg, STRUCT_SIZE(get_list)) != 0) {
1022 error = EFAULT;
1026 * If only requesting number of entries or buffer too small or an
1027 * error occurred, stop here
1029 if (req_count == 0 || count > req_count || error != 0) {
1030 goto out;
1033 copyout_size = count * sizeof (crypto_mech_name_t);
1035 /* copyout entries */
1036 offset = (ulong_t)STRUCT_FADDR(get_list, ml_list);
1037 offset -= (ulong_t)STRUCT_BUF(get_list);
1038 if (copyout(entries, arg + offset, copyout_size) != 0) {
1039 error = EFAULT;
1042 out:
1043 crypto_free_mech_list(entries, count);
1044 return (error);
1048 * Copyout kernel array of mech_infos to user space.
1050 /* ARGSUSED */
1051 static int
1052 copyout_mechinfos(int mode, caddr_t out, uint_t count,
1053 crypto_mechanism_info_t *k_minfos, caddr_t u_minfos)
1055 STRUCT_DECL(crypto_mechanism_info, mi);
1056 caddr_t p;
1057 size_t len;
1058 int i;
1060 if (count == 0)
1061 return (0);
1063 STRUCT_INIT(mi, mode);
1065 len = count * STRUCT_SIZE(mi);
1067 ASSERT(u_minfos != NULL);
1068 p = u_minfos;
1069 for (i = 0; i < count; i++) {
1070 STRUCT_FSET(mi, mi_min_key_size, k_minfos[i].mi_min_key_size);
1071 STRUCT_FSET(mi, mi_max_key_size, k_minfos[i].mi_max_key_size);
1072 STRUCT_FSET(mi, mi_keysize_unit, k_minfos[i].mi_keysize_unit);
1073 STRUCT_FSET(mi, mi_usage, k_minfos[i].mi_usage);
1074 bcopy(STRUCT_BUF(mi), p, STRUCT_SIZE(mi));
1075 p += STRUCT_SIZE(mi);
1078 if (copyout(u_minfos, out, len) != 0)
1079 return (EFAULT);
1081 return (0);
1085 * This ioctl returns information for the specified mechanism.
1087 /* ARGSUSED */
1088 static int
1089 get_all_mechanism_info(dev_t dev, caddr_t arg, int mode, int *rval)
1091 STRUCT_DECL(crypto_get_all_mechanism_info, get_all_mech);
1092 #ifdef _LP64
1093 STRUCT_DECL(crypto_mechanism_info, mi);
1094 #else
1095 /* LINTED E_FUNC_SET_NOT_USED */
1096 STRUCT_DECL(crypto_mechanism_info, mi);
1097 #endif
1098 crypto_mech_name_t mech_name;
1099 crypto_mech_type_t mech_type;
1100 crypto_mechanism_info_t *mech_infos = NULL;
1101 uint_t num_mech_infos = 0;
1102 uint_t req_count;
1103 caddr_t u_minfos;
1104 ulong_t offset;
1105 int error = 0;
1106 int rv;
1108 STRUCT_INIT(get_all_mech, mode);
1109 STRUCT_INIT(mi, mode);
1111 if (copyin(arg, STRUCT_BUF(get_all_mech),
1112 STRUCT_SIZE(get_all_mech)) != 0) {
1113 return (EFAULT);
1116 (void) strncpy(mech_name, STRUCT_FGET(get_all_mech, mi_mechanism_name),
1117 CRYPTO_MAX_MECH_NAME);
1118 mech_type = crypto_mech2id(mech_name);
1120 if (mech_type == CRYPTO_MECH_INVALID) {
1121 rv = CRYPTO_ARGUMENTS_BAD;
1122 goto out1;
1125 rv = crypto_get_all_mech_info(mech_type, &mech_infos, &num_mech_infos,
1126 KM_SLEEP);
1127 if (rv != CRYPTO_SUCCESS) {
1128 goto out1;
1130 /* rv is CRYPTO_SUCCESS at this point */
1132 /* Number of entries caller thinks we have */
1133 req_count = STRUCT_FGET(get_all_mech, mi_count);
1135 STRUCT_FSET(get_all_mech, mi_count, num_mech_infos);
1137 /* check if buffer is too small */
1138 if (num_mech_infos > req_count) {
1139 rv = CRYPTO_BUFFER_TOO_SMALL;
1142 out1:
1143 STRUCT_FSET(get_all_mech, mi_return_value, rv);
1145 /* copy the first part */
1146 if (copyout(STRUCT_BUF(get_all_mech), arg,
1147 STRUCT_SIZE(get_all_mech)) != 0) {
1148 error = EFAULT;
1152 * If only requesting number of entries, or there are no entries,
1153 * or rv is not CRYPTO_SUCCESS due to buffer too small or some other
1154 * crypto error, or an error occurred with copyout, stop here
1156 if (req_count == 0 || num_mech_infos == 0 || rv != CRYPTO_SUCCESS ||
1157 error != 0) {
1158 goto out2;
1161 /* copyout mech_infos */
1162 offset = (ulong_t)STRUCT_FADDR(get_all_mech, mi_list);
1163 offset -= (ulong_t)STRUCT_BUF(get_all_mech);
1165 u_minfos = kmem_alloc(num_mech_infos * STRUCT_SIZE(mi), KM_SLEEP);
1166 error = copyout_mechinfos(mode, arg + offset, num_mech_infos,
1167 mech_infos, u_minfos);
1168 kmem_free(u_minfos, num_mech_infos * STRUCT_SIZE(mi));
1169 out2:
1170 if (mech_infos != NULL)
1171 crypto_free_all_mech_info(mech_infos, num_mech_infos);
1172 return (error);
1176 * Side-effects:
1177 * 1. This routine stores provider descriptor pointers in an array
1178 * and increments each descriptor's reference count. The array
1179 * is stored in per-minor number storage.
1180 * 2. Destroys the old array and creates a new one every time
1181 * this routine is called.
1184 crypto_get_provider_list(crypto_minor_t *cm, uint_t *count,
1185 crypto_provider_entry_t **array, boolean_t return_slot_list)
1187 kcf_provider_desc_t **provider_array;
1188 crypto_provider_entry_t *p = NULL;
1189 uint_t provider_count;
1190 int rval;
1191 int i;
1194 * Take snapshot of provider table returning only HW entries
1195 * that are in a usable state. Also returns logical provider entries.
1197 rval = kcf_get_slot_list(&provider_count, &provider_array, B_FALSE);
1198 if (rval != CRYPTO_SUCCESS)
1199 return (rval);
1201 /* allocate memory before taking cm->cm_lock */
1202 if (return_slot_list) {
1203 if (provider_count != 0) {
1204 p = kmem_alloc(provider_count *
1205 sizeof (crypto_provider_entry_t), KM_SLEEP);
1206 for (i = 0; i < provider_count; i++) {
1207 p[i].pe_provider_id = i;
1208 p[i].pe_mechanism_count =
1209 provider_array[i]->pd_mech_list_count;
1212 *array = p;
1213 *count = provider_count;
1217 * Free existing array of providers and replace with new list.
1219 mutex_enter(&cm->cm_lock);
1220 if (cm->cm_provider_array != NULL) {
1221 ASSERT(cm->cm_provider_count > 0);
1222 kcf_free_provider_tab(cm->cm_provider_count,
1223 cm->cm_provider_array);
1226 cm->cm_provider_array = provider_array;
1227 cm->cm_provider_count = provider_count;
1228 mutex_exit(&cm->cm_lock);
1230 return (CRYPTO_SUCCESS);
1234 * This ioctl returns an array of crypto_provider_entry_t entries.
1235 * This is how consumers learn which hardware providers are available.
1237 /* ARGSUSED */
1238 static int
1239 get_provider_list(dev_t dev, caddr_t arg, int mode, int *rval)
1241 STRUCT_DECL(crypto_get_provider_list, get_list);
1242 crypto_provider_entry_t *entries;
1243 crypto_minor_t *cm;
1244 size_t copyout_size;
1245 uint_t req_count;
1246 uint_t count;
1247 ulong_t offset;
1248 int rv;
1250 STRUCT_INIT(get_list, mode);
1252 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
1253 cmn_err(CE_WARN, "get_provider_list: failed holding minor");
1254 return (ENXIO);
1257 if (copyin(arg, STRUCT_BUF(get_list), STRUCT_SIZE(get_list)) != 0) {
1258 crypto_release_minor(cm);
1259 return (EFAULT);
1262 rv = crypto_get_provider_list(cm, &count, &entries, RETURN_LIST);
1263 if (rv != CRYPTO_SUCCESS) {
1264 crypto_release_minor(cm);
1265 STRUCT_FSET(get_list, pl_return_value, rv);
1266 if (copyout(STRUCT_BUF(get_list), arg,
1267 STRUCT_SIZE(get_list)) != 0) {
1268 return (EFAULT);
1270 return (0);
1272 crypto_release_minor(cm);
1274 /* Number of slots caller thinks we have */
1275 req_count = STRUCT_FGET(get_list, pl_count);
1277 /* Check if only requesting number of slots */
1278 if (req_count == 0) {
1280 STRUCT_FSET(get_list, pl_count, count);
1281 STRUCT_FSET(get_list, pl_return_value, CRYPTO_SUCCESS);
1283 crypto_free_provider_list(entries, count);
1284 if (copyout(STRUCT_BUF(get_list), arg,
1285 STRUCT_SIZE(get_list)) != 0) {
1286 return (EFAULT);
1288 return (0);
1291 /* check if buffer is too small */
1292 req_count = STRUCT_FGET(get_list, pl_count);
1293 if (count > req_count) {
1294 STRUCT_FSET(get_list, pl_count, count);
1295 STRUCT_FSET(get_list, pl_return_value, CRYPTO_BUFFER_TOO_SMALL);
1296 crypto_free_provider_list(entries, count);
1297 if (copyout(STRUCT_BUF(get_list), arg,
1298 STRUCT_SIZE(get_list)) != 0) {
1299 return (EFAULT);
1301 return (0);
1304 STRUCT_FSET(get_list, pl_count, count);
1305 STRUCT_FSET(get_list, pl_return_value, CRYPTO_SUCCESS);
1307 copyout_size = count * sizeof (crypto_provider_entry_t);
1309 /* copyout the first stuff */
1310 if (copyout(STRUCT_BUF(get_list), arg, STRUCT_SIZE(get_list)) != 0) {
1311 crypto_free_provider_list(entries, count);
1312 return (EFAULT);
1315 if (count == 0) {
1316 crypto_free_provider_list(entries, count);
1317 return (0);
1320 /* copyout entries */
1321 offset = (ulong_t)STRUCT_FADDR(get_list, pl_list);
1322 offset -= (ulong_t)STRUCT_BUF(get_list);
1323 if (copyout(entries, arg + offset, copyout_size) != 0) {
1324 crypto_free_provider_list(entries, count);
1325 return (EFAULT);
1328 crypto_free_provider_list(entries, count);
1329 return (0);
1332 static void
1333 ext_to_provider_data(int mode, kcf_provider_desc_t *provider,
1334 crypto_provider_ext_info_t *ei, void *out)
1336 STRUCT_DECL(crypto_provider_data, pd);
1337 STRUCT_DECL(crypto_version, version);
1339 STRUCT_INIT(pd, mode);
1340 STRUCT_INIT(version, mode);
1342 bcopy(provider->pd_description, STRUCT_FGET(pd, pd_prov_desc),
1343 CRYPTO_PROVIDER_DESCR_MAX_LEN);
1345 bcopy(ei->ei_label, STRUCT_FGET(pd, pd_label), CRYPTO_EXT_SIZE_LABEL);
1346 bcopy(ei->ei_manufacturerID, STRUCT_FGET(pd, pd_manufacturerID),
1347 CRYPTO_EXT_SIZE_MANUF);
1348 bcopy(ei->ei_model, STRUCT_FGET(pd, pd_model), CRYPTO_EXT_SIZE_MODEL);
1349 bcopy(ei->ei_serial_number, STRUCT_FGET(pd, pd_serial_number),
1350 CRYPTO_EXT_SIZE_SERIAL);
1352 * We do not support ioctls for dual-function crypto operations yet.
1353 * So, we clear this flag as it might have been set by a provider.
1355 ei->ei_flags &= ~CRYPTO_EXTF_DUAL_CRYPTO_OPERATIONS;
1357 STRUCT_FSET(pd, pd_flags, ei->ei_flags);
1358 STRUCT_FSET(pd, pd_max_session_count, ei->ei_max_session_count);
1359 STRUCT_FSET(pd, pd_session_count, (int)CRYPTO_UNAVAILABLE_INFO);
1360 STRUCT_FSET(pd, pd_max_rw_session_count, ei->ei_max_session_count);
1361 STRUCT_FSET(pd, pd_rw_session_count, (int)CRYPTO_UNAVAILABLE_INFO);
1362 STRUCT_FSET(pd, pd_max_pin_len, ei->ei_max_pin_len);
1363 STRUCT_FSET(pd, pd_min_pin_len, ei->ei_min_pin_len);
1364 STRUCT_FSET(pd, pd_total_public_memory, ei->ei_total_public_memory);
1365 STRUCT_FSET(pd, pd_free_public_memory, ei->ei_free_public_memory);
1366 STRUCT_FSET(pd, pd_total_private_memory, ei->ei_total_private_memory);
1367 STRUCT_FSET(pd, pd_free_private_memory, ei->ei_free_private_memory);
1368 STRUCT_FSET(version, cv_major, ei->ei_hardware_version.cv_major);
1369 STRUCT_FSET(version, cv_minor, ei->ei_hardware_version.cv_minor);
1370 bcopy(STRUCT_BUF(version), STRUCT_FADDR(pd, pd_hardware_version),
1371 STRUCT_SIZE(version));
1372 STRUCT_FSET(version, cv_major, ei->ei_firmware_version.cv_major);
1373 STRUCT_FSET(version, cv_minor, ei->ei_firmware_version.cv_minor);
1374 bcopy(STRUCT_BUF(version), STRUCT_FADDR(pd, pd_firmware_version),
1375 STRUCT_SIZE(version));
1376 bcopy(ei->ei_time, STRUCT_FGET(pd, pd_time), CRYPTO_EXT_SIZE_TIME);
1377 bcopy(STRUCT_BUF(pd), out, STRUCT_SIZE(pd));
1381 * Utility routine to construct a crypto_provider_ext_info structure. Some
1382 * of the fields are constructed from information in the provider structure.
1383 * The rest of the fields have default values. We need to do this for
1384 * providers which do not support crypto_provider_management_ops routines.
1386 static void
1387 fabricate_ext_info(kcf_provider_desc_t *provider,
1388 crypto_provider_ext_info_t *ei)
1390 /* empty label */
1391 (void) memset(ei->ei_label, ' ', CRYPTO_EXT_SIZE_LABEL);
1393 (void) memset(ei->ei_manufacturerID, ' ', CRYPTO_EXT_SIZE_MANUF);
1394 (void) strncpy((char *)ei->ei_manufacturerID, "Unknown", 7);
1396 (void) memset(ei->ei_model, ' ', CRYPTO_EXT_SIZE_MODEL);
1397 (void) strncpy((char *)ei->ei_model, "Unknown", 7);
1399 (void) memset(ei->ei_serial_number, ' ', CRYPTO_EXT_SIZE_SERIAL);
1400 (void) strncpy((char *)ei->ei_serial_number, "Unknown", 7);
1402 if (KCF_PROV_RANDOM_OPS(provider) != NULL)
1403 ei->ei_flags |= CRYPTO_EXTF_RNG;
1404 if (KCF_PROV_DUAL_OPS(provider) != NULL)
1405 ei->ei_flags |= CRYPTO_EXTF_DUAL_CRYPTO_OPERATIONS;
1407 ei->ei_max_session_count = CRYPTO_UNAVAILABLE_INFO;
1408 ei->ei_max_pin_len = 0;
1409 ei->ei_min_pin_len = 0;
1410 ei->ei_total_public_memory = CRYPTO_UNAVAILABLE_INFO;
1411 ei->ei_free_public_memory = CRYPTO_UNAVAILABLE_INFO;
1412 ei->ei_total_private_memory = CRYPTO_UNAVAILABLE_INFO;
1413 ei->ei_free_private_memory = CRYPTO_UNAVAILABLE_INFO;
1414 ei->ei_hardware_version.cv_major = 1;
1415 ei->ei_hardware_version.cv_minor = 0;
1416 ei->ei_firmware_version.cv_major = 1;
1417 ei->ei_firmware_version.cv_minor = 0;
1420 /* ARGSUSED */
1421 static int
1422 get_provider_info(dev_t dev, caddr_t arg, int mode, int *rval)
1424 STRUCT_DECL(crypto_get_provider_info, get_info);
1425 crypto_minor_t *cm;
1426 crypto_provider_id_t provider_id;
1427 kcf_provider_desc_t *provider, *real_provider;
1428 crypto_provider_ext_info_t *ext_info = NULL;
1429 size_t need;
1430 int error = 0;
1431 int rv;
1432 kcf_req_params_t params;
1434 STRUCT_INIT(get_info, mode);
1436 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
1437 cmn_err(CE_WARN, "get_provider_info: failed holding minor");
1438 return (ENXIO);
1441 if (copyin(arg, STRUCT_BUF(get_info), STRUCT_SIZE(get_info)) != 0) {
1442 crypto_release_minor(cm);
1443 return (EFAULT);
1446 need = sizeof (crypto_provider_ext_info_t);
1447 if ((rv = crypto_buffer_check(need)) != CRYPTO_SUCCESS) {
1448 need = 0;
1449 goto release_minor;
1452 /* initialize provider_array */
1453 if (cm->cm_provider_array == NULL) {
1454 rv = crypto_get_provider_list(cm, NULL, NULL, DONT_RETURN_LIST);
1455 if (rv != CRYPTO_SUCCESS) {
1456 goto release_minor;
1460 ext_info = kmem_zalloc(need, KM_SLEEP);
1462 provider_id = STRUCT_FGET(get_info, gi_provider_id);
1463 mutex_enter(&cm->cm_lock);
1464 /* index must be less than count of providers */
1465 if (provider_id >= cm->cm_provider_count) {
1466 mutex_exit(&cm->cm_lock);
1467 rv = CRYPTO_ARGUMENTS_BAD;
1468 goto release_minor;
1471 ASSERT(cm->cm_provider_array != NULL);
1472 provider = cm->cm_provider_array[provider_id];
1473 KCF_PROV_REFHOLD(provider);
1474 mutex_exit(&cm->cm_lock);
1476 (void) kcf_get_hardware_provider_nomech(
1477 CRYPTO_OPS_OFFSET(provider_ops), CRYPTO_PROVIDER_OFFSET(ext_info),
1478 provider, &real_provider);
1480 if (real_provider != NULL) {
1481 ASSERT(real_provider == provider ||
1482 provider->pd_prov_type == CRYPTO_LOGICAL_PROVIDER);
1483 KCF_WRAP_PROVMGMT_OPS_PARAMS(&params, KCF_OP_MGMT_EXTINFO,
1484 0, NULL, 0, NULL, 0, NULL, ext_info, provider);
1485 rv = kcf_submit_request(real_provider, NULL, NULL, &params,
1486 B_FALSE);
1487 ASSERT(rv != CRYPTO_NOT_SUPPORTED);
1488 KCF_PROV_REFRELE(real_provider);
1489 } else {
1490 /* do the best we can */
1491 fabricate_ext_info(provider, ext_info);
1492 rv = CRYPTO_SUCCESS;
1494 KCF_PROV_REFRELE(provider);
1496 if (rv == CRYPTO_SUCCESS) {
1497 ext_to_provider_data(mode, provider, ext_info,
1498 STRUCT_FADDR(get_info, gi_provider_data));
1501 release_minor:
1502 CRYPTO_DECREMENT_RCTL(need);
1503 crypto_release_minor(cm);
1505 if (ext_info != NULL)
1506 kmem_free(ext_info, sizeof (crypto_provider_ext_info_t));
1508 if (error != 0)
1509 return (error);
1511 STRUCT_FSET(get_info, gi_return_value, rv);
1512 if (copyout(STRUCT_BUF(get_info), arg, STRUCT_SIZE(get_info)) != 0) {
1513 return (EFAULT);
1515 return (0);
1519 * This ioctl returns an array of crypto_mech_name_t entries.
1520 * This is how consumers learn which mechanisms are permitted
1521 * by a provider.
1523 /* ARGSUSED */
1524 static int
1525 get_provider_mechanisms(dev_t dev, caddr_t arg, int mode, int *rval)
1527 STRUCT_DECL(crypto_get_provider_mechanisms, get_mechanisms);
1528 crypto_mech_name_t *entries;
1529 crypto_minor_t *cm;
1530 size_t copyout_size;
1531 uint_t req_count;
1532 uint_t count;
1533 ulong_t offset;
1534 int err;
1536 STRUCT_INIT(get_mechanisms, mode);
1538 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
1539 cmn_err(CE_WARN,
1540 "get_provider_mechanisms: failed holding minor");
1541 return (ENXIO);
1544 if (copyin(arg, STRUCT_BUF(get_mechanisms),
1545 STRUCT_SIZE(get_mechanisms)) != 0) {
1546 crypto_release_minor(cm);
1547 return (EFAULT);
1550 /* get array of mechanisms from the core module */
1551 if ((err = crypto_get_provider_mechanisms(cm,
1552 STRUCT_FGET(get_mechanisms, pm_provider_id),
1553 &count, &entries)) != 0) {
1554 crypto_release_minor(cm);
1555 STRUCT_FSET(get_mechanisms, pm_return_value, err);
1556 if (copyout(STRUCT_BUF(get_mechanisms), arg,
1557 STRUCT_SIZE(get_mechanisms)) != 0) {
1558 return (EFAULT);
1560 return (0);
1562 crypto_release_minor(cm);
1563 /* Number of mechs caller thinks we have */
1564 req_count = STRUCT_FGET(get_mechanisms, pm_count);
1566 /* Check if caller is just requesting a count of mechanisms */
1567 if (req_count == 0) {
1568 STRUCT_FSET(get_mechanisms, pm_count, count);
1569 STRUCT_FSET(get_mechanisms, pm_return_value, CRYPTO_SUCCESS);
1571 crypto_free_mech_list(entries, count);
1572 if (copyout(STRUCT_BUF(get_mechanisms), arg,
1573 STRUCT_SIZE(get_mechanisms)) != 0) {
1574 return (EFAULT);
1576 return (0);
1579 /* check if buffer is too small */
1580 if (count > req_count) {
1581 STRUCT_FSET(get_mechanisms, pm_count, count);
1582 STRUCT_FSET(get_mechanisms, pm_return_value,
1583 CRYPTO_BUFFER_TOO_SMALL);
1584 crypto_free_mech_list(entries, count);
1585 if (copyout(STRUCT_BUF(get_mechanisms), arg,
1586 STRUCT_SIZE(get_mechanisms)) != 0) {
1587 return (EFAULT);
1589 return (0);
1592 STRUCT_FSET(get_mechanisms, pm_count, count);
1593 STRUCT_FSET(get_mechanisms, pm_return_value, CRYPTO_SUCCESS);
1595 copyout_size = count * sizeof (crypto_mech_name_t);
1597 /* copyout the first stuff */
1598 if (copyout(STRUCT_BUF(get_mechanisms), arg,
1599 STRUCT_SIZE(get_mechanisms)) != 0) {
1600 crypto_free_mech_list(entries, count);
1601 return (EFAULT);
1604 if (count == 0) {
1605 return (0);
1608 /* copyout entries */
1609 offset = (ulong_t)STRUCT_FADDR(get_mechanisms, pm_list);
1610 offset -= (ulong_t)STRUCT_BUF(get_mechanisms);
1611 if (copyout(entries, arg + offset, copyout_size) != 0) {
1612 crypto_free_mech_list(entries, count);
1613 return (EFAULT);
1616 crypto_free_mech_list(entries, count);
1617 return (0);
1621 * This ioctl returns information about a provider's mechanism.
1623 /* ARGSUSED */
1624 static int
1625 get_provider_mechanism_info(dev_t dev, caddr_t arg, int mode, int *rval)
1627 crypto_get_provider_mechanism_info_t mechanism_info;
1628 crypto_minor_t *cm;
1629 kcf_provider_desc_t *pd;
1630 crypto_mech_info_t *mi = NULL;
1631 int rv = CRYPTO_SUCCESS;
1632 int i;
1634 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
1635 cmn_err(CE_WARN,
1636 "get_provider_mechanism_info: failed holding minor");
1637 return (ENXIO);
1640 if (copyin(arg, &mechanism_info, sizeof (mechanism_info)) != 0) {
1641 crypto_release_minor(cm);
1642 return (EFAULT);
1645 /* initialize provider table */
1646 if (cm->cm_provider_array == NULL) {
1647 rv = crypto_get_provider_list(cm, NULL, NULL, DONT_RETURN_LIST);
1648 if (rv != CRYPTO_SUCCESS) {
1649 mutex_enter(&cm->cm_lock);
1650 goto fail;
1655 * Provider ID must be less than the count of providers
1656 * obtained by calling get_provider_list().
1658 mutex_enter(&cm->cm_lock);
1659 if (mechanism_info.mi_provider_id >= cm->cm_provider_count) {
1660 rv = CRYPTO_ARGUMENTS_BAD;
1661 goto fail;
1664 pd = cm->cm_provider_array[mechanism_info.mi_provider_id];
1666 /* First check if the provider supports the mechanism. */
1667 for (i = 0; i < pd->pd_mech_list_count; i++) {
1668 if (strncmp(pd->pd_mechanisms[i].cm_mech_name,
1669 mechanism_info.mi_mechanism_name,
1670 CRYPTO_MAX_MECH_NAME) == 0) {
1671 mi = &pd->pd_mechanisms[i];
1672 break;
1676 if (mi == NULL) {
1677 rv = CRYPTO_ARGUMENTS_BAD;
1678 goto fail;
1681 /* Now check if the mechanism is enabled for the provider. */
1682 if (is_mech_disabled(pd, mechanism_info.mi_mechanism_name)) {
1683 rv = CRYPTO_MECHANISM_INVALID;
1684 goto fail;
1687 mechanism_info.mi_min_key_size = mi->cm_min_key_length;
1688 mechanism_info.mi_max_key_size = mi->cm_max_key_length;
1689 mechanism_info.mi_flags = mi->cm_func_group_mask;
1691 fail:
1692 mutex_exit(&cm->cm_lock);
1693 crypto_release_minor(cm);
1694 mechanism_info.mi_return_value = rv;
1695 if (copyout(&mechanism_info, arg, sizeof (mechanism_info)) != 0) {
1696 return (EFAULT);
1699 return (0);
1703 * Every open of /dev/crypto multiplexes all PKCS#11 sessions across
1704 * a single session to each provider. Calls to open and close session
1705 * are not made to providers that do not support sessions. For these
1706 * providers, a session number of 0 is passed during subsequent operations,
1707 * and it is ignored by the provider.
1709 static int
1710 crypto_get_provider_session(crypto_minor_t *cm,
1711 crypto_provider_id_t provider_index, crypto_provider_session_t **output_ps)
1713 kcf_provider_desc_t *pd, *real_provider;
1714 kcf_req_params_t params;
1715 crypto_provider_session_t *ps;
1716 crypto_session_id_t provider_session_id = 0;
1717 int rv;
1719 ASSERT(MUTEX_HELD(&cm->cm_lock));
1721 /* pd may be a logical provider */
1722 pd = cm->cm_provider_array[provider_index];
1724 again:
1726 * Check if there is already a session to the provider.
1727 * Sessions may be to a logical provider or a real provider.
1729 for (ps = cm->cm_provider_session; ps != NULL; ps = ps->ps_next) {
1730 if (ps->ps_provider == pd)
1731 break;
1734 /* found existing session */
1735 if (ps != NULL) {
1736 ps->ps_refcnt++;
1737 *output_ps = ps;
1738 return (CRYPTO_SUCCESS);
1740 mutex_exit(&cm->cm_lock);
1742 /* find a hardware provider that supports session ops */
1743 (void) kcf_get_hardware_provider_nomech(CRYPTO_OPS_OFFSET(session_ops),
1744 CRYPTO_SESSION_OFFSET(session_open), pd, &real_provider);
1746 if (real_provider != NULL) {
1747 ASSERT(real_provider == pd ||
1748 pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER);
1749 /* open session to provider */
1750 KCF_WRAP_SESSION_OPS_PARAMS(&params, KCF_OP_SESSION_OPEN,
1751 &provider_session_id, 0, CRYPTO_USER, NULL, 0, pd);
1752 rv = kcf_submit_request(real_provider, NULL, NULL, &params,
1753 B_FALSE);
1754 if (rv != CRYPTO_SUCCESS) {
1755 mutex_enter(&cm->cm_lock);
1756 KCF_PROV_REFRELE(real_provider);
1757 return (rv);
1762 * Check if someone opened a session to the provider
1763 * while we dropped the lock.
1765 mutex_enter(&cm->cm_lock);
1766 for (ps = cm->cm_provider_session; ps != NULL; ps = ps->ps_next) {
1767 if (ps->ps_provider == pd) {
1768 mutex_exit(&cm->cm_lock);
1769 if (real_provider != NULL) {
1770 KCF_WRAP_SESSION_OPS_PARAMS(&params,
1771 KCF_OP_SESSION_CLOSE, NULL,
1772 provider_session_id, CRYPTO_USER, NULL, 0,
1773 pd);
1774 (void) kcf_submit_request(real_provider, NULL,
1775 NULL, &params, B_FALSE);
1776 KCF_PROV_REFRELE(real_provider);
1778 mutex_enter(&cm->cm_lock);
1779 goto again;
1784 return (crypto_create_provider_session(cm, pd, provider_session_id,
1785 output_ps, real_provider));
1788 static int
1789 crypto_create_provider_session(crypto_minor_t *cm, kcf_provider_desc_t *pd,
1790 crypto_session_id_t sid, crypto_provider_session_t **out_ps,
1791 kcf_provider_desc_t *real)
1793 crypto_provider_session_t *ps;
1795 /* allocate crypto_provider_session structure */
1796 ps = kmem_zalloc(sizeof (crypto_provider_session_t), KM_SLEEP);
1798 /* increment refcnt and attach to crypto_minor structure */
1799 ps->ps_session = sid;
1800 ps->ps_refcnt = 1;
1801 KCF_PROV_REFHOLD(pd);
1802 ps->ps_provider = pd;
1803 if (real != NULL) {
1804 ps->ps_real_provider = real;
1806 ps->ps_next = cm->cm_provider_session;
1807 cm->cm_provider_session = ps;
1809 *out_ps = ps;
1810 return (CRYPTO_SUCCESS);
1814 * Release a provider session.
1815 * If the reference count goes to zero, then close the session
1816 * to the provider.
1818 static void
1819 crypto_release_provider_session(crypto_minor_t *cm,
1820 crypto_provider_session_t *provider_session)
1822 kcf_req_params_t params;
1823 crypto_provider_session_t *ps = NULL, **prev;
1825 ASSERT(MUTEX_HELD(&cm->cm_lock));
1827 /* verify that provider_session is valid */
1828 for (ps = cm->cm_provider_session, prev = &cm->cm_provider_session;
1829 ps != NULL; prev = &ps->ps_next, ps = ps->ps_next) {
1830 if (ps == provider_session) {
1831 break;
1835 if (ps == NULL)
1836 return;
1838 ps->ps_refcnt--;
1840 if (ps->ps_refcnt > 0)
1841 return;
1843 if (ps->ps_real_provider != NULL) {
1844 /* close session with provider */
1845 KCF_WRAP_SESSION_OPS_PARAMS(&params, KCF_OP_SESSION_CLOSE, NULL,
1846 ps->ps_session, CRYPTO_USER, NULL, 0, ps->ps_provider);
1847 (void) kcf_submit_request(ps->ps_real_provider,
1848 NULL, NULL, &params, B_FALSE);
1849 KCF_PROV_REFRELE(ps->ps_real_provider);
1851 KCF_PROV_REFRELE(ps->ps_provider);
1852 *prev = ps->ps_next;
1853 kmem_free(ps, sizeof (*ps));
1856 static int
1857 grow_session_table(crypto_minor_t *cm)
1859 crypto_session_data_t **session_table;
1860 crypto_session_data_t **new;
1861 uint_t session_table_count;
1862 uint_t need;
1863 size_t current_allocation;
1864 size_t new_allocation;
1865 int rv;
1867 ASSERT(MUTEX_HELD(&cm->cm_lock));
1869 session_table_count = cm->cm_session_table_count;
1870 session_table = cm->cm_session_table;
1871 need = session_table_count + CRYPTO_SESSION_CHUNK;
1873 current_allocation = session_table_count * sizeof (void *);
1874 new_allocation = need * sizeof (void *);
1877 * Memory needed to grow the session table is checked
1878 * against the project.max-crypto-memory resource control.
1880 if ((rv = crypto_buffer_check(new_allocation - current_allocation)) !=
1881 CRYPTO_SUCCESS) {
1882 return (rv);
1885 /* drop lock while we allocate memory */
1886 mutex_exit(&cm->cm_lock);
1887 new = kmem_zalloc(new_allocation, KM_SLEEP);
1888 mutex_enter(&cm->cm_lock);
1890 /* check if another thread increased the table size */
1891 if (session_table_count != cm->cm_session_table_count) {
1892 kmem_free(new, new_allocation);
1893 return (CRYPTO_SUCCESS);
1896 bcopy(session_table, new, current_allocation);
1897 kmem_free(session_table, current_allocation);
1898 cm->cm_session_table = new;
1899 cm->cm_session_table_count += CRYPTO_SESSION_CHUNK;
1901 return (CRYPTO_SUCCESS);
1905 * Find unused entry in session table and return its index.
1906 * Initialize session table entry.
1908 /* ARGSUSED */
1909 static int
1910 crypto_open_session(dev_t dev, uint_t flags, crypto_session_id_t *session_index,
1911 crypto_provider_id_t provider_id)
1913 crypto_minor_t *cm;
1914 int rv;
1915 crypto_provider_session_t *ps;
1916 kcf_provider_desc_t *provider;
1918 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
1919 cmn_err(CE_WARN, "crypto_open_session: failed holding minor");
1920 return (CRYPTO_FAILED);
1923 /* initialize provider_array */
1924 if (cm->cm_provider_array == NULL) {
1925 rv = crypto_get_provider_list(cm, NULL, NULL, DONT_RETURN_LIST);
1926 if (rv != 0) {
1927 crypto_release_minor(cm);
1928 return (rv);
1932 mutex_enter(&cm->cm_lock);
1933 /* index must be less than count of providers */
1934 if (provider_id >= cm->cm_provider_count) {
1935 mutex_exit(&cm->cm_lock);
1936 crypto_release_minor(cm);
1937 return (CRYPTO_INVALID_PROVIDER_ID);
1939 ASSERT(cm->cm_provider_array != NULL);
1941 rv = crypto_get_provider_session(cm, provider_id, &ps);
1942 if (rv != CRYPTO_SUCCESS) {
1943 mutex_exit(&cm->cm_lock);
1944 crypto_release_minor(cm);
1945 return (rv);
1947 provider = cm->cm_provider_array[provider_id];
1949 rv = crypto_create_session_ptr(cm, provider, ps, session_index);
1950 mutex_exit(&cm->cm_lock);
1951 crypto_release_minor(cm);
1952 return (rv);
1956 static int
1957 crypto_create_session_ptr(crypto_minor_t *cm, kcf_provider_desc_t *provider,
1958 crypto_provider_session_t *ps, crypto_session_id_t *session_index)
1960 crypto_session_data_t **session_table;
1961 crypto_session_data_t *sp;
1962 uint_t session_table_count;
1963 uint_t i;
1964 int rv;
1966 ASSERT(MUTEX_HELD(&cm->cm_lock));
1968 again:
1969 session_table_count = cm->cm_session_table_count;
1970 session_table = cm->cm_session_table;
1972 /* session handles start with 1 */
1973 for (i = 1; i < session_table_count; i++) {
1974 if (session_table[i] == NULL)
1975 break;
1978 if (i == session_table_count || session_table_count == 0) {
1979 if ((rv = grow_session_table(cm)) != CRYPTO_SUCCESS) {
1980 crypto_release_provider_session(cm, ps);
1981 return (rv);
1983 goto again;
1986 sp = kmem_cache_alloc(crypto_session_cache, KM_SLEEP);
1987 sp->sd_flags = 0;
1988 sp->sd_find_init_cookie = NULL;
1989 sp->sd_digest_ctx = NULL;
1990 sp->sd_encr_ctx = NULL;
1991 sp->sd_decr_ctx = NULL;
1992 sp->sd_sign_ctx = NULL;
1993 sp->sd_verify_ctx = NULL;
1994 sp->sd_mac_ctx = NULL;
1995 sp->sd_sign_recover_ctx = NULL;
1996 sp->sd_verify_recover_ctx = NULL;
1997 mutex_init(&sp->sd_lock, NULL, MUTEX_DRIVER, NULL);
1998 cv_init(&sp->sd_cv, NULL, CV_DRIVER, NULL);
1999 KCF_PROV_REFHOLD(provider);
2000 sp->sd_provider = provider;
2001 sp->sd_provider_session = ps;
2003 /* See the comment for CRYPTO_PRE_APPROVED_LIMIT. */
2004 if ((rv = crypto_buffer_check(crypto_pre_approved_limit)) !=
2005 CRYPTO_SUCCESS) {
2006 sp->sd_pre_approved_amount = 0;
2007 } else {
2008 sp->sd_pre_approved_amount = (int)crypto_pre_approved_limit;
2011 cm->cm_session_table[i] = sp;
2012 if (session_index != NULL)
2013 *session_index = i;
2015 return (CRYPTO_SUCCESS);
2019 * Close a session.
2021 static int
2022 crypto_close_session(dev_t dev, crypto_session_id_t session_index)
2024 crypto_session_data_t **session_table;
2025 crypto_session_data_t *sp;
2026 crypto_minor_t *cm;
2028 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
2029 cmn_err(CE_WARN, "crypto_close_session: failed holding minor");
2030 return (CRYPTO_FAILED);
2033 mutex_enter(&cm->cm_lock);
2034 session_table = cm->cm_session_table;
2036 if ((session_index) == 0 ||
2037 (session_index >= cm->cm_session_table_count)) {
2038 mutex_exit(&cm->cm_lock);
2039 crypto_release_minor(cm);
2040 return (CRYPTO_SESSION_HANDLE_INVALID);
2043 sp = session_table[session_index];
2044 if (sp == NULL) {
2045 mutex_exit(&cm->cm_lock);
2046 crypto_release_minor(cm);
2047 return (CRYPTO_SESSION_HANDLE_INVALID);
2050 * If session is in use, free it when the thread
2051 * finishes with the session.
2053 mutex_enter(&sp->sd_lock);
2054 if (sp->sd_flags & CRYPTO_SESSION_IS_BUSY) {
2055 sp->sd_flags |= CRYPTO_SESSION_IS_CLOSED;
2056 mutex_exit(&sp->sd_lock);
2057 } else {
2058 ASSERT(sp->sd_pre_approved_amount == 0 ||
2059 sp->sd_pre_approved_amount == crypto_pre_approved_limit);
2060 CRYPTO_DECREMENT_RCTL(sp->sd_pre_approved_amount);
2062 if (sp->sd_find_init_cookie != NULL) {
2063 (void) crypto_free_find_ctx(sp);
2066 crypto_release_provider_session(cm, sp->sd_provider_session);
2067 KCF_PROV_REFRELE(sp->sd_provider);
2068 CRYPTO_CANCEL_ALL_CTX(sp);
2069 mutex_destroy(&sp->sd_lock);
2070 cv_destroy(&sp->sd_cv);
2071 kmem_cache_free(crypto_session_cache, sp);
2072 session_table[session_index] = NULL;
2075 mutex_exit(&cm->cm_lock);
2076 crypto_release_minor(cm);
2078 return (CRYPTO_SUCCESS);
2082 * This ioctl opens a session and returns the session ID in os_session.
2084 /* ARGSUSED */
2085 static int
2086 open_session(dev_t dev, caddr_t arg, int mode, int *rval)
2088 crypto_open_session_t open_session;
2089 crypto_session_id_t session;
2090 int rv;
2092 if (copyin(arg, &open_session, sizeof (open_session)) != 0)
2093 return (EFAULT);
2095 rv = crypto_open_session(dev, open_session.os_flags,
2096 &session, open_session.os_provider_id);
2097 if (rv != CRYPTO_SUCCESS) {
2098 open_session.os_return_value = rv;
2099 if (copyout(&open_session, arg, sizeof (open_session)) != 0) {
2100 return (EFAULT);
2102 return (0);
2105 open_session.os_session = session;
2106 open_session.os_return_value = CRYPTO_SUCCESS;
2108 if (copyout(&open_session, arg, sizeof (open_session)) != 0) {
2109 return (EFAULT);
2111 return (0);
2115 * This ioctl closes a session.
2117 /* ARGSUSED */
2118 static int
2119 close_session(dev_t dev, caddr_t arg, int mode, int *rval)
2121 crypto_close_session_t close_session;
2122 int rv;
2124 if (copyin(arg, &close_session, sizeof (close_session)) != 0)
2125 return (EFAULT);
2127 rv = crypto_close_session(dev, close_session.cs_session);
2128 close_session.cs_return_value = rv;
2129 if (copyout(&close_session, arg, sizeof (close_session)) != 0) {
2130 return (EFAULT);
2132 return (0);
2136 * Copy data model dependent mechanism structure into a kernel mechanism
2137 * structure. Allocate param storage if necessary.
2139 static boolean_t
2140 copyin_mech(int mode, crypto_session_data_t *sp, crypto_mechanism_t *in_mech,
2141 crypto_mechanism_t *out_mech, size_t *out_rctl_bytes,
2142 boolean_t *out_rctl_chk, int *out_rv, int *out_error)
2144 STRUCT_DECL(crypto_mechanism, mech);
2145 caddr_t param;
2146 size_t param_len;
2147 size_t rctl_bytes = 0;
2148 int error = 0;
2149 int rv = 0;
2151 STRUCT_INIT(mech, mode);
2152 bcopy(in_mech, STRUCT_BUF(mech), STRUCT_SIZE(mech));
2153 param = STRUCT_FGETP(mech, cm_param);
2154 param_len = STRUCT_FGET(mech, cm_param_len);
2155 out_mech->cm_type = STRUCT_FGET(mech, cm_type);
2156 out_mech->cm_param = NULL;
2157 out_mech->cm_param_len = 0;
2158 if (param != NULL && param_len != 0) {
2159 if (param_len > crypto_max_buffer_len) {
2160 cmn_err(CE_NOTE, "copyin_mech: buffer greater than "
2161 "%ld bytes, pid = %d", crypto_max_buffer_len,
2162 curproc->p_pid);
2163 rv = CRYPTO_ARGUMENTS_BAD;
2164 goto out;
2167 rv = CRYPTO_BUFFER_CHECK(sp, param_len, *out_rctl_chk);
2168 if (rv != CRYPTO_SUCCESS) {
2169 goto out;
2171 rctl_bytes = param_len;
2173 out_mech->cm_param = kmem_alloc(param_len, KM_SLEEP);
2174 if (copyin((char *)param, out_mech->cm_param, param_len) != 0) {
2175 kmem_free(out_mech->cm_param, param_len);
2176 out_mech->cm_param = NULL;
2177 error = EFAULT;
2178 goto out;
2180 out_mech->cm_param_len = param_len;
2182 out:
2183 *out_rctl_bytes = rctl_bytes;
2184 *out_rv = rv;
2185 *out_error = error;
2186 return ((rv | error) ? B_FALSE : B_TRUE);
2190 * Free key attributes when key type is CRYPTO_KEY_ATTR_LIST.
2191 * The crypto_key structure is not freed.
2193 static void
2194 crypto_free_key_attributes(crypto_key_t *key)
2196 crypto_object_attribute_t *attrs;
2197 size_t len = 0;
2198 int i;
2200 ASSERT(key->ck_format == CRYPTO_KEY_ATTR_LIST);
2201 if (key->ck_count == 0 || key->ck_attrs == NULL)
2202 return;
2204 /* compute the size of the container */
2205 len = key->ck_count * sizeof (crypto_object_attribute_t);
2207 /* total up the size of all attributes in the container */
2208 for (i = 0; i < key->ck_count; i++) {
2209 attrs = &key->ck_attrs[i];
2210 if (attrs->oa_value_len != 0 &&
2211 attrs->oa_value != NULL) {
2212 len += roundup(attrs->oa_value_len, sizeof (caddr_t));
2216 bzero(key->ck_attrs, len);
2217 kmem_free(key->ck_attrs, len);
2221 * Frees allocated storage in the key structure, but doesn't free
2222 * the key structure.
2224 static void
2225 free_crypto_key(crypto_key_t *key)
2227 switch (key->ck_format) {
2228 case CRYPTO_KEY_RAW: {
2229 size_t len;
2231 if (key->ck_length == 0 || key->ck_data == NULL)
2232 break;
2234 len = CRYPTO_BITS2BYTES(key->ck_length);
2235 bzero(key->ck_data, len);
2236 kmem_free(key->ck_data, len);
2237 break;
2240 case CRYPTO_KEY_ATTR_LIST:
2241 crypto_free_key_attributes(key);
2242 break;
2244 default:
2245 break;
2250 * Copy in an array of crypto_object_attribute structures from user-space.
2251 * Kernel memory is allocated for the array and the value of each attribute
2252 * in the array. Since unprivileged users can specify the size of attributes,
2253 * the amount of memory needed is charged against the
2254 * project.max-crypto-memory resource control.
2256 * Attribute values are copied in from user-space if copyin_value is set to
2257 * B_TRUE. This routine returns B_TRUE if the copyin was successful.
2259 static boolean_t
2260 copyin_attributes(int mode, crypto_session_data_t *sp,
2261 uint_t count, caddr_t oc_attributes,
2262 crypto_object_attribute_t **k_attrs_out, size_t *k_attrs_size_out,
2263 caddr_t *u_attrs_out, int *out_rv, int *out_error, size_t *out_rctl_bytes,
2264 boolean_t *out_rctl_chk, boolean_t copyin_value)
2266 STRUCT_DECL(crypto_object_attribute, oa);
2267 crypto_object_attribute_t *k_attrs = NULL;
2268 caddr_t attrs = NULL, ap, p, value;
2269 caddr_t k_attrs_buf;
2270 size_t k_attrs_len;
2271 size_t k_attrs_buf_len = 0;
2272 size_t k_attrs_total_len = 0;
2273 size_t tmp_len;
2274 size_t rctl_bytes = 0;
2275 size_t len = 0;
2276 size_t value_len;
2277 int error = 0;
2278 int rv = 0;
2279 int i;
2281 STRUCT_INIT(oa, mode);
2283 if (count == 0) {
2284 rv = CRYPTO_SUCCESS;
2285 goto out;
2288 if (count > CRYPTO_MAX_ATTRIBUTE_COUNT) {
2289 rv = CRYPTO_ARGUMENTS_BAD;
2290 goto out;
2293 /* compute size of crypto_object_attribute array */
2294 len = count * STRUCT_SIZE(oa);
2296 /* this allocation is not charged against the user's resource limit */
2297 attrs = kmem_alloc(len, KM_SLEEP);
2298 if (copyin(oc_attributes, attrs, len) != 0) {
2299 error = EFAULT;
2300 goto out;
2303 /* figure out how much memory to allocate for all of the attributes */
2304 ap = attrs;
2305 for (i = 0; i < count; i++) {
2306 bcopy(ap, STRUCT_BUF(oa), STRUCT_SIZE(oa));
2307 tmp_len = roundup(STRUCT_FGET(oa, oa_value_len),
2308 sizeof (caddr_t));
2309 if (tmp_len > crypto_max_buffer_len) {
2310 cmn_err(CE_NOTE, "copyin_attributes: buffer greater "
2311 "than %ld bytes, pid = %d", crypto_max_buffer_len,
2312 curproc->p_pid);
2313 rv = CRYPTO_ARGUMENTS_BAD;
2314 goto out;
2316 if (STRUCT_FGETP(oa, oa_value) != NULL)
2317 k_attrs_buf_len += tmp_len;
2318 ap += STRUCT_SIZE(oa);
2321 k_attrs_len = count * sizeof (crypto_object_attribute_t);
2322 k_attrs_total_len = k_attrs_buf_len + k_attrs_len;
2324 rv = CRYPTO_BUFFER_CHECK(sp, k_attrs_total_len, *out_rctl_chk);
2325 if (rv != CRYPTO_SUCCESS) {
2326 goto out;
2328 rctl_bytes = k_attrs_total_len;
2330 /* one big allocation for everything */
2331 k_attrs = kmem_alloc(k_attrs_total_len, KM_SLEEP);
2332 k_attrs_buf = (char *)k_attrs + k_attrs_len;
2334 ap = attrs;
2335 p = k_attrs_buf;
2336 for (i = 0; i < count; i++) {
2337 bcopy(ap, STRUCT_BUF(oa), STRUCT_SIZE(oa));
2338 k_attrs[i].oa_type = STRUCT_FGET(oa, oa_type);
2339 value = STRUCT_FGETP(oa, oa_value);
2340 value_len = STRUCT_FGET(oa, oa_value_len);
2341 if (value != NULL && value_len != 0 && copyin_value) {
2342 if (copyin(value, p, value_len) != 0) {
2343 kmem_free(k_attrs, k_attrs_total_len);
2344 k_attrs = NULL;
2345 error = EFAULT;
2346 goto out;
2350 if (value != NULL) {
2351 k_attrs[i].oa_value = p;
2352 p += roundup(value_len, sizeof (caddr_t));
2353 } else {
2354 k_attrs[i].oa_value = NULL;
2356 k_attrs[i].oa_value_len = value_len;
2357 ap += STRUCT_SIZE(oa);
2359 out:
2360 if (attrs != NULL) {
2362 * Free the array if there is a failure or the caller
2363 * doesn't want the array to be returned.
2365 if (error != 0 || rv != CRYPTO_SUCCESS || u_attrs_out == NULL) {
2366 kmem_free(attrs, len);
2367 attrs = NULL;
2371 if (u_attrs_out != NULL)
2372 *u_attrs_out = attrs;
2373 if (k_attrs_size_out != NULL)
2374 *k_attrs_size_out = k_attrs_total_len;
2375 *k_attrs_out = k_attrs;
2376 *out_rctl_bytes = rctl_bytes;
2377 *out_rv = rv;
2378 *out_error = error;
2379 return ((rv | error) ? B_FALSE : B_TRUE);
2383 * Copy data model dependent raw key into a kernel key
2384 * structure. Checks key length or attribute lengths against
2385 * resource controls before allocating memory. Returns B_TRUE
2386 * if both error and rv are set to 0.
2388 static boolean_t
2389 copyin_key(int mode, crypto_session_data_t *sp, crypto_key_t *in_key,
2390 crypto_key_t *out_key, size_t *out_rctl_bytes,
2391 boolean_t *out_rctl_chk, int *out_rv, int *out_error)
2393 STRUCT_DECL(crypto_key, key);
2394 crypto_object_attribute_t *k_attrs = NULL;
2395 size_t key_bits;
2396 size_t key_bytes = 0;
2397 size_t rctl_bytes = 0;
2398 int count;
2399 int error = 0;
2400 int rv = CRYPTO_SUCCESS;
2402 STRUCT_INIT(key, mode);
2403 bcopy(in_key, STRUCT_BUF(key), STRUCT_SIZE(key));
2404 out_key->ck_format = STRUCT_FGET(key, ck_format);
2405 switch (out_key->ck_format) {
2406 case CRYPTO_KEY_RAW:
2407 key_bits = STRUCT_FGET(key, ck_length);
2408 if (key_bits != 0) {
2409 if (key_bits >
2410 (CRYPTO_BYTES2BITS(crypto_max_buffer_len))) {
2411 cmn_err(CE_NOTE, "copyin_key: buffer greater "
2412 "than %ld bytes, pid = %d",
2413 crypto_max_buffer_len, curproc->p_pid);
2414 rv = CRYPTO_ARGUMENTS_BAD;
2415 goto out;
2417 key_bytes = CRYPTO_BITS2BYTES(key_bits);
2419 rv = CRYPTO_BUFFER_CHECK(sp, key_bytes,
2420 *out_rctl_chk);
2421 if (rv != CRYPTO_SUCCESS) {
2422 goto out;
2424 rctl_bytes = key_bytes;
2426 out_key->ck_data = kmem_alloc(key_bytes, KM_SLEEP);
2428 if (copyin((char *)STRUCT_FGETP(key, ck_data),
2429 out_key->ck_data, key_bytes) != 0) {
2430 kmem_free(out_key->ck_data, key_bytes);
2431 out_key->ck_data = NULL;
2432 out_key->ck_length = 0;
2433 error = EFAULT;
2434 goto out;
2437 out_key->ck_length = (ulong_t)key_bits;
2438 break;
2440 case CRYPTO_KEY_ATTR_LIST:
2441 count = STRUCT_FGET(key, ck_count);
2443 if (copyin_attributes(mode, sp, count,
2444 (caddr_t)STRUCT_FGETP(key, ck_attrs), &k_attrs, NULL, NULL,
2445 &rv, &error, &rctl_bytes, out_rctl_chk, B_TRUE)) {
2446 out_key->ck_count = count;
2447 out_key->ck_attrs = k_attrs;
2448 k_attrs = NULL;
2449 } else {
2450 out_key->ck_count = 0;
2451 out_key->ck_attrs = NULL;
2453 break;
2455 case CRYPTO_KEY_REFERENCE:
2456 out_key->ck_obj_id = STRUCT_FGET(key, ck_obj_id);
2457 break;
2459 default:
2460 rv = CRYPTO_ARGUMENTS_BAD;
2463 out:
2464 *out_rctl_bytes = rctl_bytes;
2465 *out_rv = rv;
2466 *out_error = error;
2467 return ((rv | error) ? B_FALSE : B_TRUE);
2471 * This routine does two things:
2472 * 1. Given a crypto_minor structure and a session ID, it returns
2473 * a valid session pointer.
2474 * 2. It checks that the provider, to which the session has been opened,
2475 * has not been removed.
2477 static boolean_t
2478 get_session_ptr(crypto_session_id_t i, crypto_minor_t *cm,
2479 crypto_session_data_t **session_ptr, int *out_error, int *out_rv)
2481 crypto_session_data_t *sp = NULL;
2482 int rv = CRYPTO_SESSION_HANDLE_INVALID;
2483 int error = 0;
2485 mutex_enter(&cm->cm_lock);
2486 if ((i < cm->cm_session_table_count) &&
2487 (cm->cm_session_table[i] != NULL)) {
2488 sp = cm->cm_session_table[i];
2489 mutex_enter(&sp->sd_lock);
2490 mutex_exit(&cm->cm_lock);
2491 while (sp->sd_flags & CRYPTO_SESSION_IS_BUSY) {
2492 if (cv_wait_sig(&sp->sd_cv, &sp->sd_lock) == 0) {
2493 mutex_exit(&sp->sd_lock);
2494 sp = NULL;
2495 error = EINTR;
2496 goto out;
2500 if (sp->sd_flags & CRYPTO_SESSION_IS_CLOSED) {
2501 mutex_exit(&sp->sd_lock);
2502 sp = NULL;
2503 goto out;
2506 if (KCF_IS_PROV_REMOVED(sp->sd_provider)) {
2507 mutex_exit(&sp->sd_lock);
2508 sp = NULL;
2509 rv = CRYPTO_DEVICE_ERROR;
2510 goto out;
2513 rv = CRYPTO_SUCCESS;
2514 sp->sd_flags |= CRYPTO_SESSION_IS_BUSY;
2515 mutex_exit(&sp->sd_lock);
2516 } else {
2517 mutex_exit(&cm->cm_lock);
2519 out:
2520 *session_ptr = sp;
2521 *out_error = error;
2522 *out_rv = rv;
2523 return ((rv == CRYPTO_SUCCESS && error == 0) ? B_TRUE : B_FALSE);
2526 #define CRYPTO_SESSION_RELE(s) if ((s) != NULL) { \
2527 mutex_enter(&((s)->sd_lock)); \
2528 (s)->sd_flags &= ~CRYPTO_SESSION_IS_BUSY; \
2529 cv_broadcast(&(s)->sd_cv); \
2530 mutex_exit(&((s)->sd_lock)); \
2533 /* ARGSUSED */
2534 static int
2535 encrypt_init(dev_t dev, caddr_t arg, int mode, int *rval)
2537 return (cipher_init(dev, arg, mode, crypto_encrypt_init_prov));
2540 /* ARGSUSED */
2541 static int
2542 decrypt_init(dev_t dev, caddr_t arg, int mode, int *rval)
2544 return (cipher_init(dev, arg, mode, crypto_decrypt_init_prov));
2548 * umech is a mechanism structure that has been copied from user address
2549 * space into kernel address space. Only one copyin has been done.
2550 * The mechanism parameter, if non-null, still points to user address space.
2551 * If the mechanism parameter contains pointers, they are pointers into
2552 * user address space.
2554 * kmech is a umech with all pointers and structures in kernel address space.
2556 * This routine calls the provider's entry point to copy a umech parameter
2557 * into kernel address space. Kernel memory is allocated by the provider.
2559 static int
2560 crypto_provider_copyin_mech_param(kcf_provider_desc_t *pd,
2561 crypto_mechanism_t *umech, crypto_mechanism_t *kmech, int mode, int *error)
2563 crypto_mech_type_t provider_mech_type;
2564 int rv;
2566 /* get the provider's mech number */
2567 provider_mech_type = KCF_TO_PROV_MECHNUM(pd, umech->cm_type);
2569 kmech->cm_param = NULL;
2570 kmech->cm_param_len = 0;
2571 kmech->cm_type = provider_mech_type;
2572 rv = KCF_PROV_COPYIN_MECH(pd, umech, kmech, error, mode);
2573 kmech->cm_type = umech->cm_type;
2575 return (rv);
2579 * umech is a mechanism structure that has been copied from user address
2580 * space into kernel address space. Only one copyin has been done.
2581 * The mechanism parameter, if non-null, still points to user address space.
2582 * If the mechanism parameter contains pointers, they are pointers into
2583 * user address space.
2585 * kmech is a umech with all pointers and structures in kernel address space.
2587 * This routine calls the provider's entry point to copy a kmech parameter
2588 * into user address space using umech as a template containing
2589 * user address pointers.
2591 static int
2592 crypto_provider_copyout_mech_param(kcf_provider_desc_t *pd,
2593 crypto_mechanism_t *kmech, crypto_mechanism_t *umech, int mode, int *error)
2595 crypto_mech_type_t provider_mech_type;
2596 int rv;
2598 /* get the provider's mech number */
2599 provider_mech_type = KCF_TO_PROV_MECHNUM(pd, umech->cm_type);
2601 kmech->cm_type = provider_mech_type;
2602 rv = KCF_PROV_COPYOUT_MECH(pd, kmech, umech, error, mode);
2603 kmech->cm_type = umech->cm_type;
2605 return (rv);
2609 * Call the provider's entry point to free kernel memory that has been
2610 * allocated for the mechanism's parameter.
2612 static void
2613 crypto_free_mech(kcf_provider_desc_t *pd, boolean_t allocated_by_crypto_module,
2614 crypto_mechanism_t *mech)
2616 crypto_mech_type_t provider_mech_type;
2618 if (allocated_by_crypto_module) {
2619 if (mech->cm_param != NULL)
2620 kmem_free(mech->cm_param, mech->cm_param_len);
2621 } else {
2622 /* get the provider's mech number */
2623 provider_mech_type = KCF_TO_PROV_MECHNUM(pd, mech->cm_type);
2625 if (mech->cm_param != NULL && mech->cm_param_len != 0) {
2626 mech->cm_type = provider_mech_type;
2627 (void) KCF_PROV_FREE_MECH(pd, mech);
2633 * ASSUMPTION: crypto_encrypt_init and crypto_decrypt_init
2634 * structures are identical except for field names.
2636 static int
2637 cipher_init(dev_t dev, caddr_t arg, int mode, int (*init)(crypto_provider_t,
2638 crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
2639 crypto_ctx_template_t, crypto_context_t *, crypto_call_req_t *))
2641 STRUCT_DECL(crypto_encrypt_init, encrypt_init);
2642 kcf_provider_desc_t *real_provider = NULL;
2643 crypto_session_id_t session_id;
2644 crypto_mechanism_t mech;
2645 crypto_key_t key;
2646 crypto_minor_t *cm;
2647 crypto_session_data_t *sp = NULL;
2648 crypto_context_t cc;
2649 crypto_ctx_t **ctxpp;
2650 size_t mech_rctl_bytes = 0;
2651 boolean_t mech_rctl_chk = B_FALSE;
2652 size_t key_rctl_bytes = 0;
2653 boolean_t key_rctl_chk = B_FALSE;
2654 int error = 0;
2655 int rv;
2656 boolean_t allocated_by_crypto_module = B_FALSE;
2657 crypto_func_group_t fg;
2659 STRUCT_INIT(encrypt_init, mode);
2661 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
2662 cmn_err(CE_WARN, "cipher_init: failed holding minor");
2663 return (ENXIO);
2666 if (copyin(arg, STRUCT_BUF(encrypt_init),
2667 STRUCT_SIZE(encrypt_init)) != 0) {
2668 crypto_release_minor(cm);
2669 return (EFAULT);
2672 mech.cm_param = NULL;
2673 bzero(&key, sizeof (crypto_key_t));
2675 session_id = STRUCT_FGET(encrypt_init, ei_session);
2677 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
2678 goto out;
2681 bcopy(STRUCT_FADDR(encrypt_init, ei_mech), &mech.cm_type,
2682 sizeof (crypto_mech_type_t));
2684 if (init == crypto_encrypt_init_prov) {
2685 fg = CRYPTO_FG_ENCRYPT;
2686 } else {
2687 fg = CRYPTO_FG_DECRYPT;
2690 /* We need the key length for provider selection so copy it in now. */
2691 if (!copyin_key(mode, sp, STRUCT_FADDR(encrypt_init, ei_key), &key,
2692 &key_rctl_bytes, &key_rctl_chk, &rv, &error)) {
2693 goto out;
2696 if ((rv = kcf_get_hardware_provider(mech.cm_type, &key,
2697 CRYPTO_MECH_INVALID, NULL, sp->sd_provider, &real_provider, fg))
2698 != CRYPTO_SUCCESS) {
2699 goto out;
2702 rv = crypto_provider_copyin_mech_param(real_provider,
2703 STRUCT_FADDR(encrypt_init, ei_mech), &mech, mode, &error);
2705 if (rv == CRYPTO_NOT_SUPPORTED) {
2706 allocated_by_crypto_module = B_TRUE;
2707 if (!copyin_mech(mode, sp, STRUCT_FADDR(encrypt_init, ei_mech),
2708 &mech, &mech_rctl_bytes, &mech_rctl_chk, &rv, &error)) {
2709 goto out;
2711 } else {
2712 if (rv != CRYPTO_SUCCESS)
2713 goto out;
2716 rv = (init)(real_provider, sp->sd_provider_session->ps_session,
2717 &mech, &key, NULL, &cc, NULL);
2720 * Check if a context already exists. If so, it means it is being
2721 * abandoned. So, cancel it to avoid leaking it.
2723 ctxpp = (init == crypto_encrypt_init_prov) ?
2724 &sp->sd_encr_ctx : &sp->sd_decr_ctx;
2726 if (*ctxpp != NULL)
2727 CRYPTO_CANCEL_CTX(ctxpp);
2728 *ctxpp = (rv == CRYPTO_SUCCESS) ? cc : NULL;
2730 out:
2731 CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
2732 CRYPTO_DECREMENT_RCTL_SESSION(sp, key_rctl_bytes, key_rctl_chk);
2733 CRYPTO_SESSION_RELE(sp);
2734 crypto_release_minor(cm);
2736 if (real_provider != NULL) {
2737 crypto_free_mech(real_provider,
2738 allocated_by_crypto_module, &mech);
2739 KCF_PROV_REFRELE(real_provider);
2742 free_crypto_key(&key);
2744 if (error != 0)
2745 /* XXX free context */
2746 return (error);
2748 STRUCT_FSET(encrypt_init, ei_return_value, rv);
2749 if (copyout(STRUCT_BUF(encrypt_init), arg,
2750 STRUCT_SIZE(encrypt_init)) != 0) {
2751 /* XXX free context */
2752 return (EFAULT);
2754 return (0);
2757 /* ARGSUSED */
2758 static int
2759 encrypt(dev_t dev, caddr_t arg, int mode, int *rval)
2761 return (cipher(dev, arg, mode, crypto_encrypt_single));
2764 /* ARGSUSED */
2765 static int
2766 decrypt(dev_t dev, caddr_t arg, int mode, int *rval)
2768 return (cipher(dev, arg, mode, crypto_decrypt_single));
2772 * ASSUMPTION: crypto_encrypt and crypto_decrypt structures
2773 * are identical except for field names.
2775 static int
2776 cipher(dev_t dev, caddr_t arg, int mode,
2777 int (*single)(crypto_context_t, crypto_data_t *, crypto_data_t *,
2778 crypto_call_req_t *))
2780 STRUCT_DECL(crypto_encrypt, encrypt);
2781 crypto_session_id_t session_id;
2782 crypto_minor_t *cm;
2783 crypto_session_data_t *sp = NULL;
2784 crypto_ctx_t **ctxpp;
2785 crypto_data_t data, encr;
2786 size_t datalen, encrlen, need = 0;
2787 boolean_t do_inplace;
2788 char *encrbuf;
2789 int error = 0;
2790 int rv;
2791 boolean_t rctl_chk = B_FALSE;
2793 STRUCT_INIT(encrypt, mode);
2795 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
2796 cmn_err(CE_WARN, "cipher: failed holding minor");
2797 return (ENXIO);
2800 if (copyin(arg, STRUCT_BUF(encrypt), STRUCT_SIZE(encrypt)) != 0) {
2801 crypto_release_minor(cm);
2802 return (EFAULT);
2805 data.cd_raw.iov_base = NULL;
2806 encr.cd_raw.iov_base = NULL;
2808 datalen = STRUCT_FGET(encrypt, ce_datalen);
2809 encrlen = STRUCT_FGET(encrypt, ce_encrlen);
2812 * Don't allocate output buffer unless both buffer pointer and
2813 * buffer length are not NULL or 0 (length).
2815 encrbuf = STRUCT_FGETP(encrypt, ce_encrbuf);
2816 if (encrbuf == NULL || encrlen == 0) {
2817 encrlen = 0;
2820 if (datalen > crypto_max_buffer_len ||
2821 encrlen > crypto_max_buffer_len) {
2822 cmn_err(CE_NOTE, "cipher: buffer greater than %ld bytes, "
2823 "pid = %d", crypto_max_buffer_len, curproc->p_pid);
2824 rv = CRYPTO_ARGUMENTS_BAD;
2825 goto release_minor;
2828 session_id = STRUCT_FGET(encrypt, ce_session);
2830 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
2831 goto release_minor;
2834 do_inplace = (STRUCT_FGET(encrypt, ce_flags) &
2835 CRYPTO_INPLACE_OPERATION) != 0;
2836 need = do_inplace ? datalen : datalen + encrlen;
2838 if ((rv = CRYPTO_BUFFER_CHECK(sp, need, rctl_chk)) !=
2839 CRYPTO_SUCCESS) {
2840 need = 0;
2841 goto release_minor;
2844 INIT_RAW_CRYPTO_DATA(data, datalen);
2845 data.cd_miscdata = NULL;
2847 if (datalen != 0 && copyin(STRUCT_FGETP(encrypt, ce_databuf),
2848 data.cd_raw.iov_base, datalen) != 0) {
2849 error = EFAULT;
2850 goto release_minor;
2853 if (do_inplace) {
2854 /* set out = in for in-place */
2855 encr = data;
2856 } else {
2857 INIT_RAW_CRYPTO_DATA(encr, encrlen);
2860 ctxpp = (single == crypto_encrypt_single) ?
2861 &sp->sd_encr_ctx : &sp->sd_decr_ctx;
2863 if (do_inplace)
2864 /* specify in-place buffers with output = NULL */
2865 rv = (single)(*ctxpp, &encr, NULL, NULL);
2866 else
2867 rv = (single)(*ctxpp, &data, &encr, NULL);
2869 if (KCF_CONTEXT_DONE(rv))
2870 *ctxpp = NULL;
2872 if (rv == CRYPTO_SUCCESS) {
2873 ASSERT(encr.cd_length <= encrlen);
2874 if (encr.cd_length != 0 && copyout(encr.cd_raw.iov_base,
2875 encrbuf, encr.cd_length) != 0) {
2876 error = EFAULT;
2877 goto release_minor;
2879 STRUCT_FSET(encrypt, ce_encrlen,
2880 (ulong_t)encr.cd_length);
2883 if (rv == CRYPTO_BUFFER_TOO_SMALL) {
2885 * The providers return CRYPTO_BUFFER_TOO_SMALL even for case 1
2886 * of section 11.2 of the pkcs11 spec. We catch it here and
2887 * provide the correct pkcs11 return value.
2889 if (STRUCT_FGETP(encrypt, ce_encrbuf) == NULL)
2890 rv = CRYPTO_SUCCESS;
2891 STRUCT_FSET(encrypt, ce_encrlen,
2892 (ulong_t)encr.cd_length);
2895 release_minor:
2896 CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
2897 CRYPTO_SESSION_RELE(sp);
2898 crypto_release_minor(cm);
2900 if (data.cd_raw.iov_base != NULL)
2901 kmem_free(data.cd_raw.iov_base, datalen);
2903 if (!do_inplace && encr.cd_raw.iov_base != NULL)
2904 kmem_free(encr.cd_raw.iov_base, encrlen);
2906 if (error != 0)
2907 return (error);
2909 STRUCT_FSET(encrypt, ce_return_value, rv);
2910 if (copyout(STRUCT_BUF(encrypt), arg, STRUCT_SIZE(encrypt)) != 0) {
2911 return (EFAULT);
2913 return (0);
2916 /* ARGSUSED */
2917 static int
2918 encrypt_update(dev_t dev, caddr_t arg, int mode, int *rval)
2920 return (cipher_update(dev, arg, mode, crypto_encrypt_update));
2923 /* ARGSUSED */
2924 static int
2925 decrypt_update(dev_t dev, caddr_t arg, int mode, int *rval)
2927 return (cipher_update(dev, arg, mode, crypto_decrypt_update));
2931 * ASSUMPTION: crypto_encrypt_update and crypto_decrypt_update
2932 * structures are identical except for field names.
2934 static int
2935 cipher_update(dev_t dev, caddr_t arg, int mode,
2936 int (*update)(crypto_context_t, crypto_data_t *, crypto_data_t *,
2937 crypto_call_req_t *))
2939 STRUCT_DECL(crypto_encrypt_update, encrypt_update);
2940 crypto_session_id_t session_id;
2941 crypto_minor_t *cm;
2942 crypto_session_data_t *sp = NULL;
2943 crypto_ctx_t **ctxpp;
2944 crypto_data_t data, encr;
2945 size_t datalen, encrlen, need = 0;
2946 boolean_t do_inplace;
2947 char *encrbuf;
2948 int error = 0;
2949 int rv;
2950 boolean_t rctl_chk = B_FALSE;
2952 STRUCT_INIT(encrypt_update, mode);
2954 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
2955 cmn_err(CE_WARN, "cipher_update: failed holding minor");
2956 return (ENXIO);
2959 if (copyin(arg, STRUCT_BUF(encrypt_update),
2960 STRUCT_SIZE(encrypt_update)) != 0) {
2961 crypto_release_minor(cm);
2962 return (EFAULT);
2965 data.cd_raw.iov_base = NULL;
2966 encr.cd_raw.iov_base = NULL;
2968 datalen = STRUCT_FGET(encrypt_update, eu_datalen);
2969 encrlen = STRUCT_FGET(encrypt_update, eu_encrlen);
2972 * Don't allocate output buffer unless both buffer pointer and
2973 * buffer length are not NULL or 0 (length).
2975 encrbuf = STRUCT_FGETP(encrypt_update, eu_encrbuf);
2976 if (encrbuf == NULL || encrlen == 0) {
2977 encrlen = 0;
2980 if (datalen > crypto_max_buffer_len ||
2981 encrlen > crypto_max_buffer_len) {
2982 cmn_err(CE_NOTE, "cipher_update: buffer greater than %ld "
2983 "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
2984 rv = CRYPTO_ARGUMENTS_BAD;
2985 goto out;
2988 session_id = STRUCT_FGET(encrypt_update, eu_session);
2990 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
2991 goto out;
2994 do_inplace = (STRUCT_FGET(encrypt_update, eu_flags) &
2995 CRYPTO_INPLACE_OPERATION) != 0;
2996 need = do_inplace ? datalen : datalen + encrlen;
2998 if ((rv = CRYPTO_BUFFER_CHECK(sp, need, rctl_chk)) !=
2999 CRYPTO_SUCCESS) {
3000 need = 0;
3001 goto out;
3004 INIT_RAW_CRYPTO_DATA(data, datalen);
3005 data.cd_miscdata = NULL;
3007 if (datalen != 0 && copyin(STRUCT_FGETP(encrypt_update, eu_databuf),
3008 data.cd_raw.iov_base, datalen) != 0) {
3009 error = EFAULT;
3010 goto out;
3013 if (do_inplace) {
3014 /* specify in-place buffers with output = input */
3015 encr = data;
3016 } else {
3017 INIT_RAW_CRYPTO_DATA(encr, encrlen);
3020 ctxpp = (update == crypto_encrypt_update) ?
3021 &sp->sd_encr_ctx : &sp->sd_decr_ctx;
3023 if (do_inplace)
3024 /* specify in-place buffers with output = NULL */
3025 rv = (update)(*ctxpp, &encr, NULL, NULL);
3026 else
3027 rv = (update)(*ctxpp, &data, &encr, NULL);
3029 if (rv == CRYPTO_SUCCESS || rv == CRYPTO_BUFFER_TOO_SMALL) {
3030 if (rv == CRYPTO_SUCCESS) {
3031 ASSERT(encr.cd_length <= encrlen);
3032 if (encr.cd_length != 0 && copyout(encr.cd_raw.iov_base,
3033 encrbuf, encr.cd_length) != 0) {
3034 error = EFAULT;
3035 goto out;
3037 } else {
3039 * The providers return CRYPTO_BUFFER_TOO_SMALL even
3040 * for case 1 of section 11.2 of the pkcs11 spec.
3041 * We catch it here and provide the correct pkcs11
3042 * return value.
3044 if (STRUCT_FGETP(encrypt_update, eu_encrbuf) == NULL)
3045 rv = CRYPTO_SUCCESS;
3047 STRUCT_FSET(encrypt_update, eu_encrlen,
3048 (ulong_t)encr.cd_length);
3049 } else {
3050 CRYPTO_CANCEL_CTX(ctxpp);
3052 out:
3053 CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
3054 CRYPTO_SESSION_RELE(sp);
3055 crypto_release_minor(cm);
3057 if (data.cd_raw.iov_base != NULL)
3058 kmem_free(data.cd_raw.iov_base, datalen);
3060 if (!do_inplace && (encr.cd_raw.iov_base != NULL))
3061 kmem_free(encr.cd_raw.iov_base, encrlen);
3063 if (error != 0)
3064 return (error);
3066 STRUCT_FSET(encrypt_update, eu_return_value, rv);
3067 if (copyout(STRUCT_BUF(encrypt_update), arg,
3068 STRUCT_SIZE(encrypt_update)) != 0) {
3069 return (EFAULT);
3071 return (0);
3074 /* ARGSUSED */
3075 static int
3076 encrypt_final(dev_t dev, caddr_t arg, int mode, int *rval)
3078 return (common_final(dev, arg, mode, crypto_encrypt_final));
3081 /* ARGSUSED */
3082 static int
3083 decrypt_final(dev_t dev, caddr_t arg, int mode, int *rval)
3085 return (common_final(dev, arg, mode, crypto_decrypt_final));
3089 * ASSUMPTION: crypto_encrypt_final, crypto_decrypt_final, crypto_sign_final,
3090 * and crypto_digest_final structures are identical except for field names.
3092 static int
3093 common_final(dev_t dev, caddr_t arg, int mode,
3094 int (*final)(crypto_context_t, crypto_data_t *, crypto_call_req_t *))
3096 STRUCT_DECL(crypto_encrypt_final, encrypt_final);
3097 crypto_session_id_t session_id;
3098 crypto_minor_t *cm;
3099 crypto_session_data_t *sp = NULL;
3100 crypto_ctx_t **ctxpp;
3101 crypto_data_t encr;
3102 size_t encrlen, need = 0;
3103 char *encrbuf;
3104 int error = 0;
3105 int rv;
3106 boolean_t rctl_chk = B_FALSE;
3108 STRUCT_INIT(encrypt_final, mode);
3110 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3111 cmn_err(CE_WARN, "common_final: failed holding minor");
3112 return (ENXIO);
3115 if (copyin(arg, STRUCT_BUF(encrypt_final),
3116 STRUCT_SIZE(encrypt_final)) != 0) {
3117 crypto_release_minor(cm);
3118 return (EFAULT);
3121 encr.cd_format = CRYPTO_DATA_RAW;
3122 encr.cd_raw.iov_base = NULL;
3124 encrlen = STRUCT_FGET(encrypt_final, ef_encrlen);
3127 * Don't allocate output buffer unless both buffer pointer and
3128 * buffer length are not NULL or 0 (length).
3130 encrbuf = STRUCT_FGETP(encrypt_final, ef_encrbuf);
3131 if (encrbuf == NULL || encrlen == 0) {
3132 encrlen = 0;
3135 if (encrlen > crypto_max_buffer_len) {
3136 cmn_err(CE_NOTE, "common_final: buffer greater than %ld "
3137 "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
3138 rv = CRYPTO_ARGUMENTS_BAD;
3139 goto release_minor;
3142 session_id = STRUCT_FGET(encrypt_final, ef_session);
3144 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
3145 goto release_minor;
3148 if ((rv = CRYPTO_BUFFER_CHECK(sp, encrlen, rctl_chk)) !=
3149 CRYPTO_SUCCESS) {
3150 goto release_minor;
3152 need = encrlen;
3153 encr.cd_raw.iov_base = kmem_alloc(encrlen, KM_SLEEP);
3154 encr.cd_raw.iov_len = encrlen;
3156 encr.cd_offset = 0;
3157 encr.cd_length = encrlen;
3159 ASSERT(final == crypto_encrypt_final ||
3160 final == crypto_decrypt_final || final == crypto_sign_final ||
3161 final == crypto_digest_final || final == crypto_mac_final);
3163 if (final == crypto_encrypt_final) {
3164 ctxpp = &sp->sd_encr_ctx;
3165 } else if (final == crypto_decrypt_final) {
3166 ctxpp = &sp->sd_decr_ctx;
3167 } else if (final == crypto_sign_final) {
3168 ctxpp = &sp->sd_sign_ctx;
3169 } else if (final == crypto_mac_final) {
3170 ctxpp = &sp->sd_mac_ctx;
3171 } else {
3172 ctxpp = &sp->sd_digest_ctx;
3175 rv = (final)(*ctxpp, &encr, NULL);
3176 if (KCF_CONTEXT_DONE(rv))
3177 *ctxpp = NULL;
3179 if (rv == CRYPTO_SUCCESS) {
3180 ASSERT(encr.cd_length <= encrlen);
3181 if (encr.cd_length != 0 && copyout(encr.cd_raw.iov_base,
3182 encrbuf, encr.cd_length) != 0) {
3183 error = EFAULT;
3184 goto release_minor;
3186 STRUCT_FSET(encrypt_final, ef_encrlen,
3187 (ulong_t)encr.cd_length);
3190 if (rv == CRYPTO_BUFFER_TOO_SMALL) {
3192 * The providers return CRYPTO_BUFFER_TOO_SMALL even for case 1
3193 * of section 11.2 of the pkcs11 spec. We catch it here and
3194 * provide the correct pkcs11 return value.
3196 if (STRUCT_FGETP(encrypt_final, ef_encrbuf) == NULL)
3197 rv = CRYPTO_SUCCESS;
3198 STRUCT_FSET(encrypt_final, ef_encrlen,
3199 (ulong_t)encr.cd_length);
3202 release_minor:
3203 CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
3204 CRYPTO_SESSION_RELE(sp);
3205 crypto_release_minor(cm);
3207 if (encr.cd_raw.iov_base != NULL)
3208 kmem_free(encr.cd_raw.iov_base, encrlen);
3210 if (error != 0)
3211 return (error);
3213 STRUCT_FSET(encrypt_final, ef_return_value, rv);
3214 if (copyout(STRUCT_BUF(encrypt_final), arg,
3215 STRUCT_SIZE(encrypt_final)) != 0) {
3216 return (EFAULT);
3218 return (0);
3221 /* ARGSUSED */
3222 static int
3223 digest_init(dev_t dev, caddr_t arg, int mode, int *rval)
3225 STRUCT_DECL(crypto_digest_init, digest_init);
3226 kcf_provider_desc_t *real_provider = NULL;
3227 crypto_session_id_t session_id;
3228 crypto_mechanism_t mech;
3229 crypto_minor_t *cm;
3230 crypto_session_data_t *sp = NULL;
3231 crypto_context_t cc;
3232 size_t rctl_bytes = 0;
3233 boolean_t rctl_chk = B_FALSE;
3234 int error = 0;
3235 int rv;
3237 STRUCT_INIT(digest_init, mode);
3239 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3240 cmn_err(CE_WARN, "digest_init: failed holding minor");
3241 return (ENXIO);
3244 if (copyin(arg, STRUCT_BUF(digest_init),
3245 STRUCT_SIZE(digest_init)) != 0) {
3246 crypto_release_minor(cm);
3247 return (EFAULT);
3250 mech.cm_param = NULL;
3252 session_id = STRUCT_FGET(digest_init, di_session);
3254 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
3255 goto out;
3258 if (!copyin_mech(mode, sp, STRUCT_FADDR(digest_init, di_mech), &mech,
3259 &rctl_bytes, &rctl_chk, &rv, &error)) {
3260 goto out;
3263 if ((rv = kcf_get_hardware_provider(mech.cm_type, NULL,
3264 CRYPTO_MECH_INVALID, NULL, sp->sd_provider, &real_provider,
3265 CRYPTO_FG_DIGEST)) != CRYPTO_SUCCESS) {
3266 goto out;
3269 rv = crypto_digest_init_prov(real_provider,
3270 sp->sd_provider_session->ps_session, &mech, &cc, NULL);
3273 * Check if a context already exists. If so, it means it is being
3274 * abandoned. So, cancel it to avoid leaking it.
3276 if (sp->sd_digest_ctx != NULL)
3277 CRYPTO_CANCEL_CTX(&sp->sd_digest_ctx);
3278 sp->sd_digest_ctx = (rv == CRYPTO_SUCCESS) ? cc : NULL;
3279 out:
3280 CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, rctl_chk);
3281 CRYPTO_SESSION_RELE(sp);
3282 crypto_release_minor(cm);
3284 if (real_provider != NULL)
3285 KCF_PROV_REFRELE(real_provider);
3287 if (mech.cm_param != NULL)
3288 kmem_free(mech.cm_param, mech.cm_param_len);
3290 if (error != 0)
3291 return (error);
3293 STRUCT_FSET(digest_init, di_return_value, rv);
3294 if (copyout(STRUCT_BUF(digest_init), arg,
3295 STRUCT_SIZE(digest_init)) != 0) {
3296 return (EFAULT);
3298 return (0);
3301 /* ARGSUSED */
3302 static int
3303 digest_update(dev_t dev, caddr_t arg, int mode, int *rval)
3305 STRUCT_DECL(crypto_digest_update, digest_update);
3306 crypto_session_id_t session_id;
3307 crypto_minor_t *cm;
3308 crypto_session_data_t *sp = NULL;
3309 crypto_data_t data;
3310 size_t datalen, need = 0;
3311 int error = 0;
3312 int rv;
3313 boolean_t rctl_chk = B_FALSE;
3315 STRUCT_INIT(digest_update, mode);
3317 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3318 cmn_err(CE_WARN, "digest_update: failed holding minor");
3319 return (ENXIO);
3322 if (copyin(arg, STRUCT_BUF(digest_update),
3323 STRUCT_SIZE(digest_update)) != 0) {
3324 crypto_release_minor(cm);
3325 return (EFAULT);
3328 data.cd_format = CRYPTO_DATA_RAW;
3329 data.cd_raw.iov_base = NULL;
3331 datalen = STRUCT_FGET(digest_update, du_datalen);
3332 if (datalen > crypto_max_buffer_len) {
3333 cmn_err(CE_NOTE, "digest_update: buffer greater than %ld "
3334 "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
3335 rv = CRYPTO_ARGUMENTS_BAD;
3336 goto release_minor;
3339 session_id = STRUCT_FGET(digest_update, du_session);
3341 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
3342 goto release_minor;
3345 if ((rv = CRYPTO_BUFFER_CHECK(sp, datalen, rctl_chk)) !=
3346 CRYPTO_SUCCESS) {
3347 goto release_minor;
3350 need = datalen;
3351 data.cd_raw.iov_base = kmem_alloc(datalen, KM_SLEEP);
3352 data.cd_raw.iov_len = datalen;
3354 if (datalen != 0 && copyin(STRUCT_FGETP(digest_update, du_databuf),
3355 data.cd_raw.iov_base, datalen) != 0) {
3356 error = EFAULT;
3357 goto release_minor;
3360 data.cd_offset = 0;
3361 data.cd_length = datalen;
3363 rv = crypto_digest_update(sp->sd_digest_ctx, &data, NULL);
3364 if (rv != CRYPTO_SUCCESS)
3365 CRYPTO_CANCEL_CTX(&sp->sd_digest_ctx);
3367 release_minor:
3368 CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
3369 CRYPTO_SESSION_RELE(sp);
3370 crypto_release_minor(cm);
3372 if (data.cd_raw.iov_base != NULL)
3373 kmem_free(data.cd_raw.iov_base, datalen);
3375 if (error != 0)
3376 return (error);
3378 STRUCT_FSET(digest_update, du_return_value, rv);
3379 if (copyout(STRUCT_BUF(digest_update), arg,
3380 STRUCT_SIZE(digest_update)) != 0) {
3381 return (EFAULT);
3383 return (0);
3386 /* ARGSUSED */
3387 static int
3388 digest_key(dev_t dev, caddr_t arg, int mode, int *rval)
3390 STRUCT_DECL(crypto_digest_key, digest_key);
3391 crypto_session_id_t session_id;
3392 crypto_key_t key;
3393 crypto_minor_t *cm;
3394 crypto_session_data_t *sp = NULL;
3395 size_t rctl_bytes = 0;
3396 boolean_t key_rctl_chk = B_FALSE;
3397 int error = 0;
3398 int rv;
3400 STRUCT_INIT(digest_key, mode);
3402 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3403 cmn_err(CE_WARN, "digest_key: failed holding minor");
3404 return (ENXIO);
3407 if (copyin(arg, STRUCT_BUF(digest_key), STRUCT_SIZE(digest_key)) != 0) {
3408 crypto_release_minor(cm);
3409 return (EFAULT);
3412 bzero(&key, sizeof (crypto_key_t));
3414 session_id = STRUCT_FGET(digest_key, dk_session);
3416 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
3417 goto out;
3420 if (!copyin_key(mode, sp, STRUCT_FADDR(digest_key, dk_key), &key,
3421 &rctl_bytes, &key_rctl_chk, &rv, &error)) {
3422 goto out;
3425 rv = crypto_digest_key_prov(sp->sd_digest_ctx, &key, NULL);
3426 if (rv != CRYPTO_SUCCESS)
3427 CRYPTO_CANCEL_CTX(&sp->sd_digest_ctx);
3428 out:
3429 CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, key_rctl_chk);
3430 CRYPTO_SESSION_RELE(sp);
3431 crypto_release_minor(cm);
3433 free_crypto_key(&key);
3435 if (error != 0)
3436 return (error);
3438 STRUCT_FSET(digest_key, dk_return_value, rv);
3439 if (copyout(STRUCT_BUF(digest_key), arg,
3440 STRUCT_SIZE(digest_key)) != 0) {
3441 return (EFAULT);
3443 return (0);
3446 /* ARGSUSED */
3447 static int
3448 digest_final(dev_t dev, caddr_t arg, int mode, int *rval)
3450 return (common_final(dev, arg, mode, crypto_digest_final));
3453 /* ARGSUSED */
3454 static int
3455 digest(dev_t dev, caddr_t arg, int mode, int *rval)
3457 return (common_digest(dev, arg, mode, crypto_digest_single));
3460 static int
3461 mac_init(dev_t dev, caddr_t arg, int mode, int *rval)
3463 _NOTE(ARGUNUSED(rval))
3464 return (sign_verify_init(dev, arg, mode, crypto_mac_init_prov));
3467 static int
3468 mac_update(dev_t dev, caddr_t arg, int mode, int *rval)
3470 _NOTE(ARGUNUSED(rval))
3471 return (sign_verify_update(dev, arg, mode, crypto_mac_update));
3474 static int
3475 mac_final(dev_t dev, caddr_t arg, int mode, int *rval)
3477 _NOTE(ARGUNUSED(rval))
3478 return (common_final(dev, arg, mode, crypto_mac_final));
3481 /* ARGSUSED */
3482 static int
3483 mac(dev_t dev, caddr_t arg, int mode, int *rval)
3485 _NOTE(ARGUNUSED(rval))
3486 return (common_digest(dev, arg, mode, crypto_mac_single));
3490 * ASSUMPTION: crypto_digest, crypto_sign, crypto_sign_recover,
3491 * and crypto_verify_recover are identical except for field names.
3493 static int
3494 common_digest(dev_t dev, caddr_t arg, int mode,
3495 int (*single)(crypto_context_t, crypto_data_t *, crypto_data_t *,
3496 crypto_call_req_t *))
3498 STRUCT_DECL(crypto_digest, crypto_digest);
3499 crypto_session_id_t session_id;
3500 crypto_minor_t *cm;
3501 crypto_session_data_t *sp = NULL;
3502 crypto_data_t data, digest;
3503 crypto_ctx_t **ctxpp;
3504 size_t datalen, digestlen, need = 0;
3505 char *digestbuf;
3506 int error = 0;
3507 int rv;
3508 boolean_t rctl_chk = B_FALSE;
3510 STRUCT_INIT(crypto_digest, mode);
3512 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3513 cmn_err(CE_WARN, "common_digest: failed holding minor");
3514 return (ENXIO);
3517 if (copyin(arg, STRUCT_BUF(crypto_digest),
3518 STRUCT_SIZE(crypto_digest)) != 0) {
3519 crypto_release_minor(cm);
3520 return (EFAULT);
3523 data.cd_raw.iov_base = NULL;
3524 digest.cd_raw.iov_base = NULL;
3525 data.cd_miscdata = NULL;
3526 digest.cd_miscdata = NULL;
3528 datalen = STRUCT_FGET(crypto_digest, cd_datalen);
3529 digestlen = STRUCT_FGET(crypto_digest, cd_digestlen);
3532 * Don't allocate output buffer unless both buffer pointer and
3533 * buffer length are not NULL or 0 (length).
3535 digestbuf = STRUCT_FGETP(crypto_digest, cd_digestbuf);
3536 if (digestbuf == NULL || digestlen == 0) {
3537 digestlen = 0;
3540 if (datalen > crypto_max_buffer_len ||
3541 digestlen > crypto_max_buffer_len) {
3542 cmn_err(CE_NOTE, "common_digest: buffer greater than %ld "
3543 "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
3544 rv = CRYPTO_ARGUMENTS_BAD;
3545 goto release_minor;
3548 session_id = STRUCT_FGET(crypto_digest, cd_session);
3550 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
3551 goto release_minor;
3554 need = datalen + digestlen;
3555 if ((rv = CRYPTO_BUFFER_CHECK(sp, need, rctl_chk)) !=
3556 CRYPTO_SUCCESS) {
3557 need = 0;
3558 goto release_minor;
3561 INIT_RAW_CRYPTO_DATA(data, datalen);
3563 if (datalen != 0 && copyin(STRUCT_FGETP(crypto_digest, cd_databuf),
3564 data.cd_raw.iov_base, datalen) != 0) {
3565 error = EFAULT;
3566 goto release_minor;
3569 INIT_RAW_CRYPTO_DATA(digest, digestlen);
3571 ASSERT(single == crypto_digest_single ||
3572 single == crypto_sign_single ||
3573 single == crypto_verify_recover_single ||
3574 single == crypto_sign_recover_single ||
3575 single == crypto_mac_single);
3577 if (single == crypto_digest_single) {
3578 ctxpp = &sp->sd_digest_ctx;
3579 } else if (single == crypto_sign_single) {
3580 ctxpp = &sp->sd_sign_ctx;
3581 } else if (single == crypto_verify_recover_single) {
3582 ctxpp = &sp->sd_verify_recover_ctx;
3583 } else if (single == crypto_mac_single) {
3584 ctxpp = &sp->sd_mac_ctx;
3585 } else {
3586 ctxpp = &sp->sd_sign_recover_ctx;
3588 rv = (single)(*ctxpp, &data, &digest, NULL);
3589 if (KCF_CONTEXT_DONE(rv))
3590 *ctxpp = NULL;
3592 if (rv == CRYPTO_SUCCESS) {
3593 ASSERT(digest.cd_length <= digestlen);
3594 if (digest.cd_length != 0 && copyout(digest.cd_raw.iov_base,
3595 digestbuf, digest.cd_length) != 0) {
3596 error = EFAULT;
3597 goto release_minor;
3599 STRUCT_FSET(crypto_digest, cd_digestlen,
3600 (ulong_t)digest.cd_length);
3603 if (rv == CRYPTO_BUFFER_TOO_SMALL) {
3605 * The providers return CRYPTO_BUFFER_TOO_SMALL even for case 1
3606 * of section 11.2 of the pkcs11 spec. We catch it here and
3607 * provide the correct pkcs11 return value.
3609 if (STRUCT_FGETP(crypto_digest, cd_digestbuf) == NULL)
3610 rv = CRYPTO_SUCCESS;
3611 STRUCT_FSET(crypto_digest, cd_digestlen,
3612 (ulong_t)digest.cd_length);
3615 release_minor:
3616 CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
3617 CRYPTO_SESSION_RELE(sp);
3618 crypto_release_minor(cm);
3620 if (data.cd_raw.iov_base != NULL)
3621 kmem_free(data.cd_raw.iov_base, datalen);
3623 if (digest.cd_raw.iov_base != NULL)
3624 kmem_free(digest.cd_raw.iov_base, digestlen);
3626 if (error != 0)
3627 return (error);
3629 STRUCT_FSET(crypto_digest, cd_return_value, rv);
3630 if (copyout(STRUCT_BUF(crypto_digest), arg,
3631 STRUCT_SIZE(crypto_digest)) != 0) {
3632 return (EFAULT);
3634 return (0);
3638 * A helper function that does what the name suggests.
3639 * Returns 0 on success and non-zero otherwise.
3640 * On failure, out_pin is set to 0.
3643 get_pin_and_session_ptr(char *in_pin, char **out_pin, size_t pin_len,
3644 crypto_minor_t *cm, crypto_session_id_t sid, crypto_session_data_t **sp,
3645 int *rv, int *error)
3647 char *tmp_pin = NULL;
3648 int tmp_error = 0, tmp_rv = 0;
3650 if (pin_len > KCF_MAX_PIN_LEN) {
3651 tmp_rv = CRYPTO_PIN_LEN_RANGE;
3652 goto out;
3654 tmp_pin = kmem_alloc(pin_len, KM_SLEEP);
3656 if (pin_len != 0 && copyin(in_pin, tmp_pin, pin_len) != 0) {
3657 tmp_error = EFAULT;
3658 goto out;
3661 (void) get_session_ptr(sid, cm, sp, &tmp_error, &tmp_rv);
3662 out:
3663 *out_pin = tmp_pin;
3664 *rv = tmp_rv;
3665 *error = tmp_error;
3666 return (tmp_rv | tmp_error);
3669 /* ARGSUSED */
3670 static int
3671 set_pin(dev_t dev, caddr_t arg, int mode, int *rval)
3673 STRUCT_DECL(crypto_set_pin, set_pin);
3674 kcf_provider_desc_t *real_provider;
3675 kcf_req_params_t params;
3676 crypto_minor_t *cm;
3677 crypto_session_data_t *sp;
3678 char *old_pin = NULL;
3679 char *new_pin = NULL;
3680 size_t old_pin_len;
3681 size_t new_pin_len;
3682 int error = 0;
3683 int rv;
3685 STRUCT_INIT(set_pin, mode);
3687 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3688 cmn_err(CE_WARN, "set_pin: failed holding minor");
3689 return (ENXIO);
3692 if (copyin(arg, STRUCT_BUF(set_pin),
3693 STRUCT_SIZE(set_pin)) != 0) {
3694 crypto_release_minor(cm);
3695 return (EFAULT);
3698 old_pin_len = STRUCT_FGET(set_pin, sp_old_len);
3700 if (get_pin_and_session_ptr(STRUCT_FGETP(set_pin, sp_old_pin),
3701 &old_pin, old_pin_len, cm, STRUCT_FGET(set_pin, sp_session),
3702 &sp, &rv, &error) != 0)
3703 goto release_minor;
3705 new_pin_len = STRUCT_FGET(set_pin, sp_new_len);
3706 if (new_pin_len > KCF_MAX_PIN_LEN) {
3707 rv = CRYPTO_PIN_LEN_RANGE;
3708 goto out;
3710 new_pin = kmem_alloc(new_pin_len, KM_SLEEP);
3712 if (new_pin_len != 0 && copyin(STRUCT_FGETP(set_pin, sp_new_pin),
3713 new_pin, new_pin_len) != 0) {
3714 error = EFAULT;
3715 goto out;
3718 if ((rv = kcf_get_hardware_provider_nomech(
3719 CRYPTO_OPS_OFFSET(provider_ops), CRYPTO_PROVIDER_OFFSET(set_pin),
3720 sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
3721 goto out;
3724 KCF_WRAP_PROVMGMT_OPS_PARAMS(&params, KCF_OP_MGMT_SETPIN,
3725 sp->sd_provider_session->ps_session, old_pin, old_pin_len,
3726 new_pin, new_pin_len, NULL, NULL, real_provider);
3728 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
3729 KCF_PROV_REFRELE(real_provider);
3731 out:
3732 CRYPTO_SESSION_RELE(sp);
3734 release_minor:
3735 crypto_release_minor(cm);
3737 if (old_pin != NULL) {
3738 bzero(old_pin, old_pin_len);
3739 kmem_free(old_pin, old_pin_len);
3742 if (new_pin != NULL) {
3743 bzero(new_pin, new_pin_len);
3744 kmem_free(new_pin, new_pin_len);
3747 if (error != 0)
3748 return (error);
3750 STRUCT_FSET(set_pin, sp_return_value, rv);
3751 if (copyout(STRUCT_BUF(set_pin), arg, STRUCT_SIZE(set_pin)) != 0) {
3752 return (EFAULT);
3754 return (0);
3757 /* ARGSUSED */
3758 static int
3759 login(dev_t dev, caddr_t arg, int mode, int *rval)
3761 STRUCT_DECL(crypto_login, login);
3762 kcf_provider_desc_t *real_provider;
3763 kcf_req_params_t params;
3764 crypto_minor_t *cm;
3765 crypto_session_data_t *sp;
3766 size_t pin_len;
3767 char *pin;
3768 uint_t user_type;
3769 int error = 0;
3770 int rv;
3772 STRUCT_INIT(login, mode);
3774 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3775 cmn_err(CE_WARN, "login: failed holding minor");
3776 return (ENXIO);
3779 if (copyin(arg, STRUCT_BUF(login), STRUCT_SIZE(login)) != 0) {
3780 crypto_release_minor(cm);
3781 return (EFAULT);
3784 user_type = STRUCT_FGET(login, co_user_type);
3786 pin_len = STRUCT_FGET(login, co_pin_len);
3788 if (get_pin_and_session_ptr(STRUCT_FGETP(login, co_pin),
3789 &pin, pin_len, cm, STRUCT_FGET(login, co_session),
3790 &sp, &rv, &error) != 0) {
3791 if (rv == CRYPTO_PIN_LEN_RANGE)
3792 rv = CRYPTO_PIN_INCORRECT;
3793 goto release_minor;
3796 if ((rv = kcf_get_hardware_provider_nomech(
3797 CRYPTO_OPS_OFFSET(session_ops),
3798 CRYPTO_SESSION_OFFSET(session_login), sp->sd_provider,
3799 &real_provider)) != CRYPTO_SUCCESS) {
3800 goto out;
3803 KCF_WRAP_SESSION_OPS_PARAMS(&params, KCF_OP_SESSION_LOGIN, NULL,
3804 sp->sd_provider_session->ps_session, user_type, pin, pin_len,
3805 real_provider);
3807 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
3808 KCF_PROV_REFRELE(real_provider);
3810 out:
3811 CRYPTO_SESSION_RELE(sp);
3813 release_minor:
3814 crypto_release_minor(cm);
3816 if (pin != NULL) {
3817 bzero(pin, pin_len);
3818 kmem_free(pin, pin_len);
3821 if (error != 0)
3822 return (error);
3824 STRUCT_FSET(login, co_return_value, rv);
3825 if (copyout(STRUCT_BUF(login), arg, STRUCT_SIZE(login)) != 0) {
3826 return (EFAULT);
3828 return (0);
3831 /* ARGSUSED */
3832 static int
3833 logout(dev_t dev, caddr_t arg, int mode, int *rval)
3835 crypto_logout_t logout;
3836 kcf_provider_desc_t *real_provider;
3837 kcf_req_params_t params;
3838 crypto_minor_t *cm;
3839 crypto_session_data_t *sp;
3840 int error = 0;
3841 int rv;
3843 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3844 cmn_err(CE_WARN, "logout: failed holding minor");
3845 return (ENXIO);
3848 if (copyin(arg, &logout, sizeof (logout)) != 0) {
3849 crypto_release_minor(cm);
3850 return (EFAULT);
3853 if (!get_session_ptr(logout.cl_session, cm, &sp, &error, &rv)) {
3854 goto release_minor;
3857 if ((rv = kcf_get_hardware_provider_nomech(
3858 CRYPTO_OPS_OFFSET(session_ops),
3859 CRYPTO_SESSION_OFFSET(session_logout), sp->sd_provider,
3860 &real_provider)) != CRYPTO_SUCCESS) {
3861 goto out;
3864 KCF_WRAP_SESSION_OPS_PARAMS(&params, KCF_OP_SESSION_LOGOUT, NULL,
3865 sp->sd_provider_session->ps_session, 0, NULL, 0, real_provider);
3866 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
3867 KCF_PROV_REFRELE(real_provider);
3869 out:
3870 CRYPTO_SESSION_RELE(sp);
3872 release_minor:
3873 crypto_release_minor(cm);
3875 if (error != 0)
3876 return (error);
3878 logout.cl_return_value = rv;
3879 if (copyout(&logout, arg, sizeof (logout)) != 0) {
3880 return (EFAULT);
3882 return (0);
3885 /* ARGSUSED */
3886 static int
3887 sign_init(dev_t dev, caddr_t arg, int mode, int *rval)
3889 return (sign_verify_init(dev, arg, mode, crypto_sign_init_prov));
3892 /* ARGSUSED */
3893 static int
3894 sign_recover_init(dev_t dev, caddr_t arg, int mode, int *rval)
3896 return (sign_verify_init(dev, arg, mode,
3897 crypto_sign_recover_init_prov));
3900 /* ARGSUSED */
3901 static int
3902 verify_init(dev_t dev, caddr_t arg, int mode, int *rval)
3904 return (sign_verify_init(dev, arg, mode, crypto_verify_init_prov));
3907 /* ARGSUSED */
3908 static int
3909 verify_recover_init(dev_t dev, caddr_t arg, int mode, int *rval)
3911 return (sign_verify_init(dev, arg, mode,
3912 crypto_verify_recover_init_prov));
3916 * ASSUMPTION: crypto_sign_init, crypto_verify_init, crypto_sign_recover_init,
3917 * and crypto_verify_recover_init structures are identical
3918 * except for field names.
3920 static int
3921 sign_verify_init(dev_t dev, caddr_t arg, int mode,
3922 int (*init)(crypto_provider_t, crypto_session_id_t,
3923 crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
3924 crypto_context_t *, crypto_call_req_t *))
3926 STRUCT_DECL(crypto_sign_init, sign_init);
3927 kcf_provider_desc_t *real_provider = NULL;
3928 crypto_session_id_t session_id;
3929 crypto_mechanism_t mech;
3930 crypto_key_t key;
3931 crypto_minor_t *cm;
3932 crypto_session_data_t *sp = NULL;
3933 crypto_context_t cc;
3934 crypto_ctx_t **ctxpp;
3935 size_t mech_rctl_bytes = 0;
3936 boolean_t mech_rctl_chk = B_FALSE;
3937 size_t key_rctl_bytes = 0;
3938 boolean_t key_rctl_chk = B_FALSE;
3939 int error = 0;
3940 int rv;
3941 boolean_t allocated_by_crypto_module = B_FALSE;
3942 crypto_func_group_t fg;
3944 STRUCT_INIT(sign_init, mode);
3946 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
3947 cmn_err(CE_WARN, "sign_verify_init: failed holding minor");
3948 return (ENXIO);
3951 if (copyin(arg, STRUCT_BUF(sign_init), STRUCT_SIZE(sign_init)) != 0) {
3952 crypto_release_minor(cm);
3953 return (EFAULT);
3956 mech.cm_param = NULL;
3957 bzero(&key, sizeof (key));
3959 session_id = STRUCT_FGET(sign_init, si_session);
3961 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
3962 goto out;
3965 bcopy(STRUCT_FADDR(sign_init, si_mech), &mech.cm_type,
3966 sizeof (crypto_mech_type_t));
3968 ASSERT(init == crypto_sign_init_prov ||
3969 init == crypto_verify_init_prov ||
3970 init == crypto_sign_recover_init_prov ||
3971 init == crypto_verify_recover_init_prov ||
3972 init == crypto_mac_init_prov);
3974 if (init == crypto_sign_init_prov) {
3975 fg = CRYPTO_FG_SIGN;
3976 ctxpp = &sp->sd_sign_ctx;
3977 } else if (init == crypto_verify_init_prov) {
3978 fg = CRYPTO_FG_VERIFY;
3979 ctxpp = &sp->sd_verify_ctx;
3980 } else if (init == crypto_sign_recover_init_prov) {
3981 fg = CRYPTO_FG_SIGN_RECOVER;
3982 ctxpp = &sp->sd_sign_recover_ctx;
3983 } else if (init == crypto_mac_init_prov) {
3984 fg = CRYPTO_FG_MAC;
3985 ctxpp = &sp->sd_mac_ctx;
3986 } else {
3987 fg = CRYPTO_FG_VERIFY_RECOVER;
3988 ctxpp = &sp->sd_verify_recover_ctx;
3991 /* We need the key length for provider selection so copy it in now. */
3992 if (!copyin_key(mode, sp, STRUCT_FADDR(sign_init, si_key), &key,
3993 &key_rctl_bytes, &key_rctl_chk, &rv, &error)) {
3994 goto out;
3997 if ((rv = kcf_get_hardware_provider(mech.cm_type, &key,
3998 CRYPTO_MECH_INVALID, NULL, sp->sd_provider, &real_provider,
3999 fg)) != CRYPTO_SUCCESS) {
4000 goto out;
4003 rv = crypto_provider_copyin_mech_param(real_provider,
4004 STRUCT_FADDR(sign_init, si_mech), &mech, mode, &error);
4006 if (rv == CRYPTO_NOT_SUPPORTED) {
4007 allocated_by_crypto_module = B_TRUE;
4008 if (!copyin_mech(mode, sp, STRUCT_FADDR(sign_init, si_mech),
4009 &mech, &mech_rctl_bytes, &mech_rctl_chk, &rv, &error)) {
4010 goto out;
4012 } else {
4013 if (rv != CRYPTO_SUCCESS)
4014 goto out;
4017 rv = (init)(real_provider, sp->sd_provider_session->ps_session,
4018 &mech, &key, NULL, &cc, NULL);
4021 * Check if a context already exists. If so, it means it is being
4022 * abandoned. So, cancel it to avoid leaking it.
4024 if (*ctxpp != NULL)
4025 CRYPTO_CANCEL_CTX(ctxpp);
4026 *ctxpp = (rv == CRYPTO_SUCCESS) ? cc : NULL;
4028 out:
4029 CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
4030 CRYPTO_DECREMENT_RCTL_SESSION(sp, key_rctl_bytes, key_rctl_chk);
4031 CRYPTO_SESSION_RELE(sp);
4032 crypto_release_minor(cm);
4034 if (real_provider != NULL) {
4035 crypto_free_mech(real_provider,
4036 allocated_by_crypto_module, &mech);
4037 KCF_PROV_REFRELE(real_provider);
4040 free_crypto_key(&key);
4042 if (error != 0)
4043 return (error);
4045 STRUCT_FSET(sign_init, si_return_value, rv);
4046 if (copyout(STRUCT_BUF(sign_init), arg, STRUCT_SIZE(sign_init)) != 0) {
4047 return (EFAULT);
4049 return (0);
4052 /* ARGSUSED */
4053 static int
4054 sign(dev_t dev, caddr_t arg, int mode, int *rval)
4056 return (common_digest(dev, arg, mode, crypto_sign_single));
4059 /* ARGSUSED */
4060 static int
4061 sign_recover(dev_t dev, caddr_t arg, int mode, int *rval)
4063 return (common_digest(dev, arg, mode, crypto_sign_recover_single));
4066 /* ARGSUSED */
4067 static int
4068 verify(dev_t dev, caddr_t arg, int mode, int *rval)
4070 STRUCT_DECL(crypto_verify, verify);
4071 crypto_session_id_t session_id;
4072 crypto_minor_t *cm;
4073 crypto_session_data_t *sp = NULL;
4074 crypto_data_t data, sign;
4075 size_t datalen, signlen, need = 0;
4076 int error = 0;
4077 int rv;
4078 boolean_t rctl_chk = B_FALSE;
4080 STRUCT_INIT(verify, mode);
4082 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4083 cmn_err(CE_WARN, "verify: failed holding minor");
4084 return (ENXIO);
4087 if (copyin(arg, STRUCT_BUF(verify), STRUCT_SIZE(verify)) != 0) {
4088 crypto_release_minor(cm);
4089 return (EFAULT);
4092 data.cd_raw.iov_base = NULL;
4093 sign.cd_raw.iov_base = NULL;
4095 datalen = STRUCT_FGET(verify, cv_datalen);
4096 signlen = STRUCT_FGET(verify, cv_signlen);
4097 if (datalen > crypto_max_buffer_len ||
4098 signlen > crypto_max_buffer_len) {
4099 cmn_err(CE_NOTE, "verify: buffer greater than %ld bytes, "
4100 "pid = %d", crypto_max_buffer_len, curproc->p_pid);
4101 rv = CRYPTO_ARGUMENTS_BAD;
4102 goto release_minor;
4105 session_id = STRUCT_FGET(verify, cv_session);
4107 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4108 goto release_minor;
4111 need = datalen + signlen;
4112 if ((rv = CRYPTO_BUFFER_CHECK(sp, need, rctl_chk)) !=
4113 CRYPTO_SUCCESS) {
4114 need = 0;
4115 goto release_minor;
4118 INIT_RAW_CRYPTO_DATA(data, datalen);
4119 INIT_RAW_CRYPTO_DATA(sign, signlen);
4121 if (datalen != 0 && copyin(STRUCT_FGETP(verify, cv_databuf),
4122 data.cd_raw.iov_base, datalen) != 0) {
4123 error = EFAULT;
4124 goto release_minor;
4127 if (signlen != 0 && copyin(STRUCT_FGETP(verify, cv_signbuf),
4128 sign.cd_raw.iov_base, signlen) != 0) {
4129 error = EFAULT;
4130 goto release_minor;
4133 rv = crypto_verify_single(sp->sd_verify_ctx, &data, &sign, NULL);
4134 if (KCF_CONTEXT_DONE(rv))
4135 sp->sd_verify_ctx = NULL;
4137 release_minor:
4138 CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
4139 CRYPTO_SESSION_RELE(sp);
4140 crypto_release_minor(cm);
4142 if (data.cd_raw.iov_base != NULL)
4143 kmem_free(data.cd_raw.iov_base, datalen);
4145 if (sign.cd_raw.iov_base != NULL)
4146 kmem_free(sign.cd_raw.iov_base, signlen);
4148 if (error != 0)
4149 return (error);
4151 STRUCT_FSET(verify, cv_return_value, rv);
4152 if (copyout(STRUCT_BUF(verify), arg, STRUCT_SIZE(verify)) != 0) {
4153 return (EFAULT);
4155 return (0);
4158 /* ARGSUSED */
4159 static int
4160 verify_recover(dev_t dev, caddr_t arg, int mode, int *rval)
4162 return (common_digest(dev, arg, mode, crypto_verify_recover_single));
4165 /* ARGSUSED */
4166 static int
4167 sign_update(dev_t dev, caddr_t arg, int mode, int *rval)
4169 return (sign_verify_update(dev, arg, mode, crypto_sign_update));
4172 /* ARGSUSED */
4173 static int
4174 verify_update(dev_t dev, caddr_t arg, int mode, int *rval)
4176 return (sign_verify_update(dev, arg, mode, crypto_verify_update));
4180 * ASSUMPTION: crypto_sign_update and crypto_verify_update structures
4181 * are identical except for field names.
4183 static int
4184 sign_verify_update(dev_t dev, caddr_t arg, int mode,
4185 int (*update)(crypto_context_t, crypto_data_t *, crypto_call_req_t *))
4187 STRUCT_DECL(crypto_sign_update, sign_update);
4188 crypto_session_id_t session_id;
4189 crypto_minor_t *cm;
4190 crypto_session_data_t *sp = NULL;
4191 crypto_ctx_t **ctxpp;
4192 crypto_data_t data;
4193 size_t datalen, need = 0;
4194 int error = 0;
4195 int rv;
4196 boolean_t rctl_chk = B_FALSE;
4198 STRUCT_INIT(sign_update, mode);
4200 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4201 cmn_err(CE_WARN, "sign_verify_update: failed holding minor");
4202 return (ENXIO);
4205 if (copyin(arg, STRUCT_BUF(sign_update),
4206 STRUCT_SIZE(sign_update)) != 0) {
4207 crypto_release_minor(cm);
4208 return (EFAULT);
4211 data.cd_raw.iov_base = NULL;
4212 data.cd_miscdata = NULL;
4214 datalen = STRUCT_FGET(sign_update, su_datalen);
4215 if (datalen > crypto_max_buffer_len) {
4216 cmn_err(CE_NOTE, "sign_verify_update: buffer greater than %ld "
4217 "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
4218 rv = CRYPTO_ARGUMENTS_BAD;
4219 goto release_minor;
4222 session_id = STRUCT_FGET(sign_update, su_session);
4224 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4225 goto release_minor;
4228 if ((rv = CRYPTO_BUFFER_CHECK(sp, datalen, rctl_chk)) !=
4229 CRYPTO_SUCCESS) {
4230 goto release_minor;
4232 need = datalen;
4234 INIT_RAW_CRYPTO_DATA(data, datalen);
4236 if (datalen != 0 && copyin(STRUCT_FGETP(sign_update, su_databuf),
4237 data.cd_raw.iov_base, datalen) != 0) {
4238 error = EFAULT;
4239 goto release_minor;
4242 ASSERT(update == crypto_sign_update ||
4243 update == crypto_verify_update ||
4244 update == crypto_mac_update);
4246 if (update == crypto_sign_update)
4247 ctxpp = &sp->sd_sign_ctx;
4248 else if (update == crypto_verify_update)
4249 ctxpp = &sp->sd_verify_ctx;
4250 else
4251 ctxpp = &sp->sd_mac_ctx;
4253 rv = (update)(*ctxpp, &data, NULL);
4254 if (rv != CRYPTO_SUCCESS)
4255 CRYPTO_CANCEL_CTX(ctxpp);
4257 release_minor:
4258 CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
4259 CRYPTO_SESSION_RELE(sp);
4260 crypto_release_minor(cm);
4262 if (data.cd_raw.iov_base != NULL)
4263 kmem_free(data.cd_raw.iov_base, datalen);
4265 if (error != 0)
4266 return (error);
4268 STRUCT_FSET(sign_update, su_return_value, rv);
4269 if (copyout(STRUCT_BUF(sign_update), arg,
4270 STRUCT_SIZE(sign_update)) != 0) {
4271 return (EFAULT);
4273 return (0);
4276 /* ARGSUSED */
4277 static int
4278 sign_final(dev_t dev, caddr_t arg, int mode, int *rval)
4280 return (common_final(dev, arg, mode, crypto_sign_final));
4284 * Can't use the common final because it does a copyout of
4285 * the final part.
4287 /* ARGSUSED */
4288 static int
4289 verify_final(dev_t dev, caddr_t arg, int mode, int *rval)
4291 STRUCT_DECL(crypto_verify_final, verify_final);
4292 crypto_session_id_t session_id;
4293 crypto_minor_t *cm;
4294 crypto_session_data_t *sp = NULL;
4295 crypto_data_t sign;
4296 size_t signlen, need = 0;
4297 int error = 0;
4298 int rv;
4299 boolean_t rctl_chk = B_FALSE;
4301 STRUCT_INIT(verify_final, mode);
4303 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4304 cmn_err(CE_WARN, "verify_final: failed holding minor");
4305 return (ENXIO);
4308 if (copyin(arg, STRUCT_BUF(verify_final),
4309 STRUCT_SIZE(verify_final)) != 0) {
4310 crypto_release_minor(cm);
4311 return (EFAULT);
4314 sign.cd_raw.iov_base = NULL;
4316 signlen = STRUCT_FGET(verify_final, vf_signlen);
4317 if (signlen > crypto_max_buffer_len) {
4318 cmn_err(CE_NOTE, "verify_final: buffer greater than %ld "
4319 "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
4320 rv = CRYPTO_ARGUMENTS_BAD;
4321 goto release_minor;
4324 session_id = STRUCT_FGET(verify_final, vf_session);
4326 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4327 goto release_minor;
4330 if ((rv = CRYPTO_BUFFER_CHECK(sp, signlen, rctl_chk)) !=
4331 CRYPTO_SUCCESS) {
4332 goto release_minor;
4334 need = signlen;
4336 INIT_RAW_CRYPTO_DATA(sign, signlen);
4338 if (signlen != 0 && copyin(STRUCT_FGETP(verify_final, vf_signbuf),
4339 sign.cd_raw.iov_base, signlen) != 0) {
4340 error = EFAULT;
4341 goto release_minor;
4344 rv = crypto_verify_final(sp->sd_verify_ctx, &sign, NULL);
4345 if (KCF_CONTEXT_DONE(rv))
4346 sp->sd_verify_ctx = NULL;
4348 release_minor:
4349 CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
4350 CRYPTO_SESSION_RELE(sp);
4351 crypto_release_minor(cm);
4353 if (sign.cd_raw.iov_base != NULL)
4354 kmem_free(sign.cd_raw.iov_base, signlen);
4356 if (error != 0)
4357 return (error);
4359 STRUCT_FSET(verify_final, vf_return_value, rv);
4360 if (copyout(STRUCT_BUF(verify_final), arg,
4361 STRUCT_SIZE(verify_final)) != 0) {
4362 return (EFAULT);
4364 return (0);
4367 /* ARGSUSED */
4368 static int
4369 seed_random(dev_t dev, caddr_t arg, int mode, int *rval)
4371 STRUCT_DECL(crypto_seed_random, seed_random);
4372 kcf_provider_desc_t *real_provider = NULL;
4373 kcf_req_params_t params;
4374 crypto_session_id_t session_id;
4375 crypto_minor_t *cm;
4376 crypto_session_data_t *sp = NULL;
4377 uchar_t *seed_buffer = NULL;
4378 size_t seed_len;
4379 size_t need = 0;
4380 int error = 0;
4381 int rv;
4382 boolean_t rctl_chk = B_FALSE;
4384 STRUCT_INIT(seed_random, mode);
4386 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4387 cmn_err(CE_WARN, "seed_random: failed holding minor");
4388 return (ENXIO);
4391 if (copyin(arg, STRUCT_BUF(seed_random),
4392 STRUCT_SIZE(seed_random)) != 0) {
4393 crypto_release_minor(cm);
4394 return (EFAULT);
4397 seed_len = STRUCT_FGET(seed_random, sr_seedlen);
4398 if (seed_len > crypto_max_buffer_len) {
4399 cmn_err(CE_NOTE, "seed_random: buffer greater than %ld "
4400 "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
4401 rv = CRYPTO_ARGUMENTS_BAD;
4402 goto release_minor;
4405 session_id = STRUCT_FGET(seed_random, sr_session);
4407 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4408 goto release_minor;
4411 if ((rv = CRYPTO_BUFFER_CHECK(sp, seed_len, rctl_chk)) !=
4412 CRYPTO_SUCCESS) {
4413 goto release_minor;
4415 need = seed_len;
4416 seed_buffer = kmem_alloc(seed_len, KM_SLEEP);
4418 if (seed_len != 0 && copyin(STRUCT_FGETP(seed_random, sr_seedbuf),
4419 seed_buffer, seed_len) != 0) {
4420 error = EFAULT;
4421 goto release_minor;
4424 if ((rv = kcf_get_hardware_provider_nomech(
4425 CRYPTO_OPS_OFFSET(random_ops), CRYPTO_RANDOM_OFFSET(seed_random),
4426 sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4427 goto release_minor;
4430 KCF_WRAP_RANDOM_OPS_PARAMS(&params, KCF_OP_RANDOM_SEED,
4431 sp->sd_provider_session->ps_session, seed_buffer, seed_len, 0,
4432 CRYPTO_SEED_NOW);
4434 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4436 release_minor:
4437 CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
4438 CRYPTO_SESSION_RELE(sp);
4439 crypto_release_minor(cm);
4441 if (real_provider != NULL)
4442 KCF_PROV_REFRELE(real_provider);
4444 if (seed_buffer != NULL)
4445 kmem_free(seed_buffer, seed_len);
4447 if (error != 0)
4448 return (error);
4450 STRUCT_FSET(seed_random, sr_return_value, rv);
4451 if (copyout(STRUCT_BUF(seed_random), arg,
4452 STRUCT_SIZE(seed_random)) != 0) {
4453 return (EFAULT);
4455 return (0);
4458 /* ARGSUSED */
4459 static int
4460 generate_random(dev_t dev, caddr_t arg, int mode, int *rval)
4462 STRUCT_DECL(crypto_generate_random, generate_random);
4463 kcf_provider_desc_t *real_provider = NULL;
4464 kcf_req_params_t params;
4465 crypto_session_id_t session_id;
4466 crypto_minor_t *cm;
4467 crypto_session_data_t *sp = NULL;
4468 uchar_t *buffer = NULL;
4469 size_t len;
4470 size_t need = 0;
4471 int error = 0;
4472 int rv;
4473 boolean_t rctl_chk = B_FALSE;
4475 STRUCT_INIT(generate_random, mode);
4477 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4478 cmn_err(CE_WARN, "generate_random: failed holding minor");
4479 return (ENXIO);
4482 if (copyin(arg, STRUCT_BUF(generate_random),
4483 STRUCT_SIZE(generate_random)) != 0) {
4484 crypto_release_minor(cm);
4485 return (EFAULT);
4488 len = STRUCT_FGET(generate_random, gr_buflen);
4489 if (len > crypto_max_buffer_len) {
4490 cmn_err(CE_NOTE, "generate_random: buffer greater than %ld "
4491 "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
4492 rv = CRYPTO_ARGUMENTS_BAD;
4493 goto release_minor;
4496 session_id = STRUCT_FGET(generate_random, gr_session);
4498 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4499 goto release_minor;
4502 if ((rv = CRYPTO_BUFFER_CHECK(sp, len, rctl_chk)) !=
4503 CRYPTO_SUCCESS) {
4504 goto release_minor;
4506 need = len;
4507 buffer = kmem_alloc(len, KM_SLEEP);
4509 if ((rv = kcf_get_hardware_provider_nomech(
4510 CRYPTO_OPS_OFFSET(random_ops),
4511 CRYPTO_RANDOM_OFFSET(generate_random), sp->sd_provider,
4512 &real_provider)) != CRYPTO_SUCCESS) {
4513 goto release_minor;
4516 KCF_WRAP_RANDOM_OPS_PARAMS(&params, KCF_OP_RANDOM_GENERATE,
4517 sp->sd_provider_session->ps_session, buffer, len, 0, 0);
4519 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4521 if (rv == CRYPTO_SUCCESS) {
4522 if (len != 0 && copyout(buffer,
4523 STRUCT_FGETP(generate_random, gr_buf), len) != 0) {
4524 error = EFAULT;
4528 release_minor:
4529 CRYPTO_DECREMENT_RCTL_SESSION(sp, need, rctl_chk);
4530 CRYPTO_SESSION_RELE(sp);
4531 crypto_release_minor(cm);
4533 if (real_provider != NULL)
4534 KCF_PROV_REFRELE(real_provider);
4536 if (buffer != NULL) {
4537 /* random numbers are often used to create keys */
4538 bzero(buffer, len);
4539 kmem_free(buffer, len);
4542 if (error != 0)
4543 return (error);
4545 STRUCT_FSET(generate_random, gr_return_value, rv);
4546 if (copyout(STRUCT_BUF(generate_random), arg,
4547 STRUCT_SIZE(generate_random)) != 0) {
4548 return (EFAULT);
4550 return (0);
4554 * Copyout a kernel array of attributes to user space.
4555 * u_attrs is the corresponding user space array containing
4556 * user space pointers necessary for the copyout.
4558 /* ARGSUSED */
4559 static int
4560 copyout_attributes(int mode, caddr_t out, uint_t count,
4561 crypto_object_attribute_t *k_attrs, caddr_t u_attrs)
4563 STRUCT_DECL(crypto_object_attribute, oa);
4564 caddr_t p, valuep;
4565 size_t value_len;
4566 size_t len;
4567 int i;
4568 int error = 0;
4570 if (count == 0)
4571 return (0);
4573 STRUCT_INIT(oa, mode);
4575 len = count * STRUCT_SIZE(oa);
4577 ASSERT(u_attrs != NULL);
4578 p = u_attrs;
4579 for (i = 0; i < count; i++) {
4580 /* can this bcopy be eliminated? */
4581 bcopy(p, STRUCT_BUF(oa), STRUCT_SIZE(oa));
4582 value_len = k_attrs[i].oa_value_len;
4583 STRUCT_FSET(oa, oa_type, k_attrs[i].oa_type);
4584 STRUCT_FSET(oa, oa_value_len, (ssize_t)value_len);
4585 valuep = STRUCT_FGETP(oa, oa_value);
4586 if ((valuep != NULL) && (value_len != (size_t)-1)) {
4587 if (copyout(k_attrs[i].oa_value,
4588 valuep, value_len) != 0) {
4589 error = EFAULT;
4590 goto out;
4593 bcopy(STRUCT_BUF(oa), p, STRUCT_SIZE(oa));
4594 p += STRUCT_SIZE(oa);
4596 if (copyout(u_attrs, out, len)) {
4597 error = EFAULT;
4599 out:
4600 return (error);
4604 /* ARGSUSED */
4605 static int
4606 object_create(dev_t dev, caddr_t arg, int mode, int *rval)
4608 STRUCT_DECL(crypto_object_create, object_create);
4609 kcf_provider_desc_t *real_provider = NULL;
4610 kcf_req_params_t params;
4611 crypto_object_attribute_t *k_attrs = NULL;
4612 crypto_session_id_t session_id;
4613 crypto_minor_t *cm;
4614 crypto_session_data_t *sp = NULL;
4615 crypto_object_id_t object_handle;
4616 caddr_t oc_attributes;
4617 size_t k_attrs_size;
4618 size_t rctl_bytes = 0;
4619 boolean_t rctl_chk = B_FALSE;
4620 int error = 0;
4621 int rv;
4622 uint_t count;
4624 STRUCT_INIT(object_create, mode);
4626 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4627 cmn_err(CE_WARN, "object_create: failed holding minor");
4628 return (ENXIO);
4631 if (copyin(arg, STRUCT_BUF(object_create),
4632 STRUCT_SIZE(object_create)) != 0) {
4633 crypto_release_minor(cm);
4634 return (EFAULT);
4637 count = STRUCT_FGET(object_create, oc_count);
4638 oc_attributes = STRUCT_FGETP(object_create, oc_attributes);
4640 session_id = STRUCT_FGET(object_create, oc_session);
4641 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4642 goto release_minor;
4644 if (!copyin_attributes(mode, sp, count, oc_attributes, &k_attrs,
4645 &k_attrs_size, NULL, &rv, &error, &rctl_bytes,
4646 &rctl_chk, B_TRUE)) {
4647 goto release_minor;
4650 if ((rv = kcf_get_hardware_provider_nomech(
4651 CRYPTO_OPS_OFFSET(object_ops),
4652 CRYPTO_OBJECT_OFFSET(object_create), sp->sd_provider,
4653 &real_provider)) != CRYPTO_SUCCESS) {
4654 goto release_minor;
4657 KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_CREATE,
4658 sp->sd_provider_session->ps_session, 0, k_attrs, count,
4659 &object_handle, 0, NULL, NULL, 0, NULL);
4661 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4663 if (rv == CRYPTO_SUCCESS)
4664 STRUCT_FSET(object_create, oc_handle, object_handle);
4666 release_minor:
4667 CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, rctl_chk);
4669 if (k_attrs != NULL)
4670 kmem_free(k_attrs, k_attrs_size);
4672 if (error != 0)
4673 goto out;
4675 STRUCT_FSET(object_create, oc_return_value, rv);
4676 if (copyout(STRUCT_BUF(object_create), arg,
4677 STRUCT_SIZE(object_create)) != 0) {
4678 if (rv == CRYPTO_SUCCESS) {
4679 KCF_WRAP_OBJECT_OPS_PARAMS(&params,
4680 KCF_OP_OBJECT_DESTROY,
4681 sp->sd_provider_session->ps_session, object_handle,
4682 NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
4684 (void) kcf_submit_request(real_provider, NULL,
4685 NULL, &params, B_FALSE);
4687 error = EFAULT;
4690 out:
4691 CRYPTO_SESSION_RELE(sp);
4692 crypto_release_minor(cm);
4693 if (real_provider != NULL)
4694 KCF_PROV_REFRELE(real_provider);
4695 return (error);
4698 /* ARGSUSED */
4699 static int
4700 object_copy(dev_t dev, caddr_t arg, int mode, int *rval)
4702 STRUCT_DECL(crypto_object_copy, object_copy);
4703 kcf_provider_desc_t *real_provider = NULL;
4704 kcf_req_params_t params;
4705 crypto_object_attribute_t *k_attrs = NULL;
4706 crypto_session_id_t session_id;
4707 crypto_minor_t *cm;
4708 crypto_session_data_t *sp = NULL;
4709 crypto_object_id_t handle, new_handle;
4710 caddr_t oc_new_attributes;
4711 size_t k_attrs_size;
4712 size_t rctl_bytes = 0;
4713 boolean_t rctl_chk = B_FALSE;
4714 int error = 0;
4715 int rv;
4716 uint_t count;
4718 STRUCT_INIT(object_copy, mode);
4720 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4721 cmn_err(CE_WARN, "object_copy: failed holding minor");
4722 return (ENXIO);
4725 if (copyin(arg, STRUCT_BUF(object_copy),
4726 STRUCT_SIZE(object_copy)) != 0) {
4727 crypto_release_minor(cm);
4728 return (EFAULT);
4731 count = STRUCT_FGET(object_copy, oc_count);
4732 oc_new_attributes = STRUCT_FGETP(object_copy, oc_new_attributes);
4734 session_id = STRUCT_FGET(object_copy, oc_session);
4736 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4737 goto release_minor;
4739 if (!copyin_attributes(mode, sp, count, oc_new_attributes, &k_attrs,
4740 &k_attrs_size, NULL, &rv, &error, &rctl_bytes,
4741 &rctl_chk, B_TRUE)) {
4742 goto release_minor;
4745 if ((rv = kcf_get_hardware_provider_nomech(
4746 CRYPTO_OPS_OFFSET(object_ops),
4747 CRYPTO_OBJECT_OFFSET(object_copy), sp->sd_provider,
4748 &real_provider)) != CRYPTO_SUCCESS) {
4749 goto release_minor;
4752 handle = STRUCT_FGET(object_copy, oc_handle);
4753 KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_COPY,
4754 sp->sd_provider_session->ps_session, handle, k_attrs, count,
4755 &new_handle, 0, NULL, NULL, 0, NULL);
4757 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4759 if (rv == CRYPTO_SUCCESS)
4760 STRUCT_FSET(object_copy, oc_new_handle, new_handle);
4762 release_minor:
4763 CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, rctl_chk);
4765 if (k_attrs != NULL)
4766 kmem_free(k_attrs, k_attrs_size);
4768 if (error != 0)
4769 goto out;
4771 STRUCT_FSET(object_copy, oc_return_value, rv);
4772 if (copyout(STRUCT_BUF(object_copy), arg,
4773 STRUCT_SIZE(object_copy)) != 0) {
4774 if (rv == CRYPTO_SUCCESS) {
4775 KCF_WRAP_OBJECT_OPS_PARAMS(&params,
4776 KCF_OP_OBJECT_DESTROY,
4777 sp->sd_provider_session->ps_session, new_handle,
4778 NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
4780 (void) kcf_submit_request(real_provider, NULL,
4781 NULL, &params, B_FALSE);
4783 error = EFAULT;
4786 out:
4787 CRYPTO_SESSION_RELE(sp);
4788 crypto_release_minor(cm);
4789 if (real_provider != NULL)
4790 KCF_PROV_REFRELE(real_provider);
4791 return (error);
4794 /* ARGSUSED */
4795 static int
4796 object_destroy(dev_t dev, caddr_t arg, int mode, int *rval)
4798 STRUCT_DECL(crypto_object_destroy, object_destroy);
4799 kcf_provider_desc_t *real_provider;
4800 kcf_req_params_t params;
4801 crypto_session_id_t session_id;
4802 crypto_minor_t *cm;
4803 crypto_session_data_t *sp;
4804 crypto_object_id_t handle;
4805 int error = 0;
4806 int rv;
4808 STRUCT_INIT(object_destroy, mode);
4810 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4811 cmn_err(CE_WARN, "object_destroy: failed holding minor");
4812 return (ENXIO);
4815 if (copyin(arg, STRUCT_BUF(object_destroy),
4816 STRUCT_SIZE(object_destroy)) != 0) {
4817 crypto_release_minor(cm);
4818 return (EFAULT);
4821 session_id = STRUCT_FGET(object_destroy, od_session);
4823 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4824 goto release_minor;
4827 if ((rv = kcf_get_hardware_provider_nomech(
4828 CRYPTO_OPS_OFFSET(object_ops),
4829 CRYPTO_OBJECT_OFFSET(object_destroy), sp->sd_provider,
4830 &real_provider)) != CRYPTO_SUCCESS) {
4831 goto out;
4834 handle = STRUCT_FGET(object_destroy, od_handle);
4835 KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_DESTROY,
4836 sp->sd_provider_session->ps_session, handle, NULL, 0, NULL, 0,
4837 NULL, NULL, 0, NULL);
4839 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4840 KCF_PROV_REFRELE(real_provider);
4842 out:
4843 CRYPTO_SESSION_RELE(sp);
4845 release_minor:
4846 crypto_release_minor(cm);
4848 if (error != 0)
4849 return (error);
4851 STRUCT_FSET(object_destroy, od_return_value, rv);
4853 if (copyout(STRUCT_BUF(object_destroy), arg,
4854 STRUCT_SIZE(object_destroy)) != 0) {
4855 return (EFAULT);
4857 return (0);
4860 /* ARGSUSED */
4861 static int
4862 object_get_attribute_value(dev_t dev, caddr_t arg, int mode, int *rval)
4864 STRUCT_DECL(crypto_object_get_attribute_value, get_attribute_value);
4865 #ifdef _LP64
4866 STRUCT_DECL(crypto_object_attribute, oa);
4867 #else
4868 /* LINTED E_FUNC_SET_NOT_USED */
4869 STRUCT_DECL(crypto_object_attribute, oa);
4870 #endif
4871 kcf_provider_desc_t *real_provider;
4872 kcf_req_params_t params;
4873 crypto_object_attribute_t *k_attrs = NULL;
4874 crypto_session_id_t session_id;
4875 crypto_minor_t *cm;
4876 crypto_session_data_t *sp = NULL;
4877 crypto_object_id_t handle;
4878 caddr_t og_attributes;
4879 caddr_t u_attrs = NULL;
4880 size_t k_attrs_size;
4881 size_t rctl_bytes = 0;
4882 boolean_t rctl_chk = B_FALSE;
4883 int error = 0;
4884 int rv;
4885 uint_t count;
4887 STRUCT_INIT(get_attribute_value, mode);
4888 STRUCT_INIT(oa, mode);
4890 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4891 cmn_err(CE_WARN,
4892 "object_get_attribute_value: failed holding minor");
4893 return (ENXIO);
4896 if (copyin(arg, STRUCT_BUF(get_attribute_value),
4897 STRUCT_SIZE(get_attribute_value)) != 0) {
4898 crypto_release_minor(cm);
4899 return (EFAULT);
4902 count = STRUCT_FGET(get_attribute_value, og_count);
4903 og_attributes = STRUCT_FGETP(get_attribute_value, og_attributes);
4905 session_id = STRUCT_FGET(get_attribute_value, og_session);
4907 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4908 goto release_minor;
4910 if (!copyin_attributes(mode, sp, count, og_attributes, &k_attrs,
4911 &k_attrs_size, &u_attrs, &rv, &error, &rctl_bytes,
4912 &rctl_chk, B_FALSE)) {
4913 goto release_minor;
4916 if ((rv = kcf_get_hardware_provider_nomech(
4917 CRYPTO_OPS_OFFSET(object_ops),
4918 CRYPTO_OBJECT_OFFSET(object_get_attribute_value),
4919 sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
4920 goto out;
4923 handle = STRUCT_FGET(get_attribute_value, og_handle);
4924 KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_GET_ATTRIBUTE_VALUE,
4925 sp->sd_provider_session->ps_session, handle, k_attrs, count, NULL,
4926 0, NULL, NULL, 0, NULL);
4928 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
4929 KCF_PROV_REFRELE(real_provider);
4931 out:
4932 if (rv == CRYPTO_SUCCESS || rv == CRYPTO_ATTRIBUTE_SENSITIVE ||
4933 rv == CRYPTO_ATTRIBUTE_TYPE_INVALID ||
4934 rv == CRYPTO_BUFFER_TOO_SMALL) {
4935 error = copyout_attributes(mode,
4936 STRUCT_FGETP(get_attribute_value, og_attributes),
4937 count, k_attrs, u_attrs);
4940 release_minor:
4941 CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, rctl_chk);
4942 CRYPTO_SESSION_RELE(sp);
4943 crypto_release_minor(cm);
4945 if (k_attrs != NULL)
4946 kmem_free(k_attrs, k_attrs_size);
4948 if (u_attrs != NULL)
4949 kmem_free(u_attrs, count * STRUCT_SIZE(oa));
4951 if (error != 0)
4952 return (error);
4954 STRUCT_FSET(get_attribute_value, og_return_value, rv);
4955 if (copyout(STRUCT_BUF(get_attribute_value), arg,
4956 STRUCT_SIZE(get_attribute_value)) != 0) {
4957 return (EFAULT);
4959 return (0);
4962 /* ARGSUSED */
4963 static int
4964 object_get_size(dev_t dev, caddr_t arg, int mode, int *rval)
4966 STRUCT_DECL(crypto_object_get_size, object_get_size);
4967 kcf_provider_desc_t *real_provider;
4968 kcf_req_params_t params;
4969 crypto_session_id_t session_id;
4970 crypto_minor_t *cm;
4971 crypto_session_data_t *sp = NULL;
4972 crypto_object_id_t handle;
4973 size_t size;
4974 int error = 0;
4975 int rv;
4977 STRUCT_INIT(object_get_size, mode);
4979 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
4980 cmn_err(CE_WARN, "object_get_size: failed holding minor");
4981 return (ENXIO);
4984 if (copyin(arg, STRUCT_BUF(object_get_size),
4985 STRUCT_SIZE(object_get_size)) != 0) {
4986 crypto_release_minor(cm);
4987 return (EFAULT);
4990 session_id = STRUCT_FGET(object_get_size, gs_session);
4992 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
4993 goto release_minor;
4996 if ((rv = kcf_get_hardware_provider_nomech(
4997 CRYPTO_OPS_OFFSET(object_ops),
4998 CRYPTO_OBJECT_OFFSET(object_get_size),
4999 sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
5000 goto release_minor;
5003 handle = STRUCT_FGET(object_get_size, gs_handle);
5004 KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_GET_SIZE,
5005 sp->sd_provider_session->ps_session, handle, NULL, 0, NULL, &size,
5006 NULL, NULL, 0, NULL);
5008 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5009 KCF_PROV_REFRELE(real_provider);
5011 if (rv == CRYPTO_SUCCESS) {
5012 STRUCT_FSET(object_get_size, gs_size, (ulong_t)size);
5015 release_minor:
5016 crypto_release_minor(cm);
5017 CRYPTO_SESSION_RELE(sp);
5019 if (error != 0)
5020 return (error);
5022 STRUCT_FSET(object_get_size, gs_return_value, rv);
5023 if (copyout(STRUCT_BUF(object_get_size), arg,
5024 STRUCT_SIZE(object_get_size)) != 0) {
5025 return (EFAULT);
5027 return (0);
5030 /* ARGSUSED */
5031 static int
5032 object_set_attribute_value(dev_t dev, caddr_t arg, int mode, int *rval)
5034 STRUCT_DECL(crypto_object_set_attribute_value, set_attribute_value);
5035 kcf_provider_desc_t *real_provider;
5036 kcf_req_params_t params;
5037 crypto_object_attribute_t *k_attrs = NULL;
5038 crypto_session_id_t session_id;
5039 crypto_minor_t *cm;
5040 crypto_session_data_t *sp = NULL;
5041 crypto_object_id_t object_handle;
5042 caddr_t sa_attributes;
5043 size_t k_attrs_size;
5044 size_t rctl_bytes = 0;
5045 boolean_t rctl_chk = B_FALSE;
5046 int error = 0;
5047 int rv;
5048 uint_t count;
5050 STRUCT_INIT(set_attribute_value, mode);
5052 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5053 cmn_err(CE_WARN,
5054 "object_set_attribute_value: failed holding minor");
5055 return (ENXIO);
5058 if (copyin(arg, STRUCT_BUF(set_attribute_value),
5059 STRUCT_SIZE(set_attribute_value)) != 0) {
5060 crypto_release_minor(cm);
5061 return (EFAULT);
5064 count = STRUCT_FGET(set_attribute_value, sa_count);
5065 sa_attributes = STRUCT_FGETP(set_attribute_value, sa_attributes);
5067 session_id = STRUCT_FGET(set_attribute_value, sa_session);
5069 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5070 goto release_minor;
5072 if (!copyin_attributes(mode, sp, count, sa_attributes, &k_attrs,
5073 &k_attrs_size, NULL, &rv, &error, &rctl_bytes,
5074 &rctl_chk, B_TRUE)) {
5075 goto release_minor;
5078 if ((rv = kcf_get_hardware_provider_nomech(
5079 CRYPTO_OPS_OFFSET(object_ops),
5080 CRYPTO_OBJECT_OFFSET(object_set_attribute_value),
5081 sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
5082 goto release_minor;
5085 object_handle = STRUCT_FGET(set_attribute_value, sa_handle);
5086 KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_SET_ATTRIBUTE_VALUE,
5087 sp->sd_provider_session->ps_session, object_handle, k_attrs, count,
5088 NULL, 0, NULL, NULL, 0, NULL);
5090 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5091 KCF_PROV_REFRELE(real_provider);
5093 release_minor:
5094 CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, rctl_chk);
5095 CRYPTO_SESSION_RELE(sp);
5096 crypto_release_minor(cm);
5098 if (k_attrs != NULL)
5099 kmem_free(k_attrs, k_attrs_size);
5101 if (error != 0)
5102 return (error);
5104 STRUCT_FSET(set_attribute_value, sa_return_value, rv);
5105 if (copyout(STRUCT_BUF(set_attribute_value), arg,
5106 STRUCT_SIZE(set_attribute_value)) != 0) {
5107 return (EFAULT);
5109 return (0);
5112 /* ARGSUSED */
5113 static int
5114 object_find_init(dev_t dev, caddr_t arg, int mode, int *rval)
5116 STRUCT_DECL(crypto_object_find_init, find_init);
5117 kcf_provider_desc_t *real_provider = NULL;
5118 kcf_req_params_t params;
5119 crypto_object_attribute_t *k_attrs = NULL;
5120 crypto_session_id_t session_id;
5121 crypto_minor_t *cm;
5122 crypto_session_data_t *sp = NULL;
5123 caddr_t attributes;
5124 size_t k_attrs_size;
5125 size_t rctl_bytes = 0;
5126 boolean_t rctl_chk = B_FALSE;
5127 int error = 0;
5128 int rv;
5129 uint_t count;
5130 void *cookie;
5132 STRUCT_INIT(find_init, mode);
5134 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5135 cmn_err(CE_WARN, "object_find_init: failed holding minor");
5136 return (ENXIO);
5139 if (copyin(arg, STRUCT_BUF(find_init), STRUCT_SIZE(find_init)) != 0) {
5140 crypto_release_minor(cm);
5141 return (EFAULT);
5144 count = STRUCT_FGET(find_init, fi_count);
5145 attributes = STRUCT_FGETP(find_init, fi_attributes);
5147 session_id = STRUCT_FGET(find_init, fi_session);
5149 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5150 goto release_minor;
5152 if (!copyin_attributes(mode, sp, count, attributes, &k_attrs,
5153 &k_attrs_size, NULL, &rv, &error, &rctl_bytes,
5154 &rctl_chk, B_TRUE)) {
5155 goto release_minor;
5158 if ((rv = kcf_get_hardware_provider_nomech(
5159 CRYPTO_OPS_OFFSET(object_ops),
5160 CRYPTO_OBJECT_OFFSET(object_find_init),
5161 sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
5162 goto release_minor;
5165 /* check for an active find */
5166 if (sp->sd_find_init_cookie != NULL) {
5167 rv = CRYPTO_OPERATION_IS_ACTIVE;
5168 goto release_minor;
5171 KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_FIND_INIT,
5172 sp->sd_provider_session->ps_session, 0, k_attrs, count, NULL, 0,
5173 &cookie, NULL, 0, NULL);
5175 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5177 if (rv == CRYPTO_SUCCESS) {
5179 * The cookie is allocated by a provider at the start of an
5180 * object search. It is freed when the search is terminated
5181 * by a final operation, or when the session is closed.
5182 * It contains state information about which object handles
5183 * have been returned to the caller.
5185 sp->sd_find_init_cookie = cookie;
5188 release_minor:
5189 CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, rctl_chk);
5190 CRYPTO_SESSION_RELE(sp);
5191 crypto_release_minor(cm);
5193 if (real_provider != NULL)
5194 KCF_PROV_REFRELE(real_provider);
5196 if (k_attrs != NULL)
5197 kmem_free(k_attrs, k_attrs_size);
5199 if (error != 0)
5200 return (error);
5202 STRUCT_FSET(find_init, fi_return_value, rv);
5203 if (copyout(STRUCT_BUF(find_init), arg, STRUCT_SIZE(find_init)) != 0) {
5204 return (EFAULT);
5206 return (0);
5209 /* ARGSUSED */
5210 static int
5211 object_find_update(dev_t dev, caddr_t arg, int mode, int *rval)
5213 STRUCT_DECL(crypto_object_find_update, find_update);
5214 kcf_provider_desc_t *real_provider;
5215 kcf_req_params_t params;
5216 crypto_minor_t *cm;
5217 crypto_session_data_t *sp = NULL;
5218 crypto_object_id_t *buffer = NULL;
5219 crypto_session_id_t session_id;
5220 size_t len, rctl_bytes = 0;
5221 uint_t count, max_count;
5222 int rv, error = 0;
5223 boolean_t rctl_chk = B_FALSE;
5225 STRUCT_INIT(find_update, mode);
5227 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5228 cmn_err(CE_WARN, "object_find_update: failed holding minor");
5229 return (ENXIO);
5232 if (copyin(arg, STRUCT_BUF(find_update),
5233 STRUCT_SIZE(find_update)) != 0) {
5234 crypto_release_minor(cm);
5235 return (EFAULT);
5238 max_count = STRUCT_FGET(find_update, fu_max_count);
5239 if (max_count > CRYPTO_MAX_FIND_COUNT) {
5240 cmn_err(CE_NOTE, "object_find_update: count greater than %d, "
5241 "pid = %d", CRYPTO_MAX_FIND_COUNT, curproc->p_pid);
5242 rv = CRYPTO_ARGUMENTS_BAD;
5243 goto release_minor;
5245 len = max_count * sizeof (crypto_object_id_t);
5246 session_id = STRUCT_FGET(find_update, fu_session);
5248 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5249 goto release_minor;
5251 if ((rv = CRYPTO_BUFFER_CHECK(sp, len, rctl_chk)) !=
5252 CRYPTO_SUCCESS) {
5253 goto release_minor;
5255 rctl_bytes = len;
5256 buffer = kmem_alloc(len, KM_SLEEP);
5258 if ((rv = kcf_get_hardware_provider_nomech(
5259 CRYPTO_OPS_OFFSET(object_ops),
5260 CRYPTO_OBJECT_OFFSET(object_find), sp->sd_provider,
5261 &real_provider)) != CRYPTO_SUCCESS) {
5262 goto release_minor;
5265 KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_FIND,
5266 sp->sd_provider_session->ps_session, 0, NULL, 0, buffer, 0,
5267 NULL, sp->sd_find_init_cookie, max_count, &count);
5269 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5270 KCF_PROV_REFRELE(real_provider);
5272 if (rv == CRYPTO_SUCCESS) {
5273 if (count > max_count) {
5274 /* bad bad provider */
5275 rv = CRYPTO_FAILED;
5276 goto release_minor;
5278 if (count != 0) {
5279 /* copyout handles */
5280 if (copyout(buffer,
5281 STRUCT_FGETP(find_update, fu_handles),
5282 count * sizeof (crypto_object_id_t)) != 0) {
5283 error = EFAULT;
5286 STRUCT_FSET(find_update, fu_count, count);
5289 release_minor:
5290 CRYPTO_DECREMENT_RCTL_SESSION(sp, rctl_bytes, rctl_chk);
5291 CRYPTO_SESSION_RELE(sp);
5292 crypto_release_minor(cm);
5294 if (buffer != NULL)
5295 kmem_free(buffer, len);
5297 if (error != 0)
5298 return (error);
5300 STRUCT_FSET(find_update, fu_return_value, rv);
5301 if (copyout(STRUCT_BUF(find_update), arg,
5302 STRUCT_SIZE(find_update)) != 0) {
5303 return (EFAULT);
5306 return (0);
5310 * Free provider-allocated storage used for find object searches.
5312 static int
5313 crypto_free_find_ctx(crypto_session_data_t *sp)
5315 kcf_provider_desc_t *real_provider;
5316 kcf_req_params_t params;
5317 int rv;
5319 if ((rv = kcf_get_hardware_provider_nomech(
5320 CRYPTO_OPS_OFFSET(object_ops),
5321 CRYPTO_OBJECT_OFFSET(object_find_final),
5322 sp->sd_provider, &real_provider)) != CRYPTO_SUCCESS) {
5323 return (rv);
5326 KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_FIND_FINAL,
5327 sp->sd_provider_session->ps_session, 0, NULL, 0, NULL, 0,
5328 NULL, sp->sd_find_init_cookie, 0, NULL);
5330 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5331 KCF_PROV_REFRELE(real_provider);
5332 return (rv);
5335 /* ARGSUSED */
5336 static int
5337 object_find_final(dev_t dev, caddr_t arg, int mode, int *rval)
5339 STRUCT_DECL(crypto_object_find_final, object_find_final);
5340 crypto_session_id_t session_id;
5341 crypto_minor_t *cm;
5342 crypto_session_data_t *sp;
5343 int error = 0;
5344 int rv;
5346 STRUCT_INIT(object_find_final, mode);
5348 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5349 cmn_err(CE_WARN, "object_find_final: failed holding minor");
5350 return (ENXIO);
5353 if (copyin(arg, STRUCT_BUF(object_find_final),
5354 STRUCT_SIZE(object_find_final)) != 0) {
5355 crypto_release_minor(cm);
5356 return (EFAULT);
5359 session_id = STRUCT_FGET(object_find_final, ff_session);
5361 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5362 goto release_minor;
5365 if ((rv = crypto_free_find_ctx(sp)) == CRYPTO_SUCCESS) {
5366 sp->sd_find_init_cookie = NULL;
5369 CRYPTO_SESSION_RELE(sp);
5371 release_minor:
5372 crypto_release_minor(cm);
5374 if (error != 0)
5375 return (error);
5377 STRUCT_FSET(object_find_final, ff_return_value, rv);
5379 if (copyout(STRUCT_BUF(object_find_final), arg,
5380 STRUCT_SIZE(object_find_final)) != 0) {
5381 return (EFAULT);
5383 return (0);
5386 /* ARGSUSED */
5387 static int
5388 object_generate_key(dev_t dev, caddr_t arg, int mode, int *rval)
5390 STRUCT_DECL(crypto_object_generate_key, generate_key);
5391 kcf_provider_desc_t *real_provider = NULL;
5392 kcf_req_params_t params;
5393 crypto_mechanism_t mech;
5394 crypto_object_attribute_t *k_attrs = NULL;
5395 crypto_session_id_t session_id;
5396 crypto_minor_t *cm;
5397 crypto_session_data_t *sp = NULL;
5398 crypto_object_id_t key_handle;
5399 caddr_t attributes;
5400 size_t k_attrs_size;
5401 size_t mech_rctl_bytes = 0, key_rctl_bytes = 0;
5402 boolean_t mech_rctl_chk = B_FALSE;
5403 boolean_t key_rctl_chk = B_FALSE;
5404 uint_t count;
5405 int error = 0;
5406 int rv;
5407 boolean_t allocated_by_crypto_module = B_FALSE;
5409 STRUCT_INIT(generate_key, mode);
5411 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5412 cmn_err(CE_WARN, "object_generate_key: failed holding minor");
5413 return (ENXIO);
5416 if (copyin(arg, STRUCT_BUF(generate_key),
5417 STRUCT_SIZE(generate_key)) != 0) {
5418 crypto_release_minor(cm);
5419 return (EFAULT);
5422 session_id = STRUCT_FGET(generate_key, gk_session);
5424 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5425 goto release_minor;
5428 bcopy(STRUCT_FADDR(generate_key, gk_mechanism), &mech.cm_type,
5429 sizeof (crypto_mech_type_t));
5431 if ((rv = kcf_get_hardware_provider(mech.cm_type, NULL,
5432 CRYPTO_MECH_INVALID, NULL, sp->sd_provider,
5433 &real_provider, CRYPTO_FG_GENERATE)) != CRYPTO_SUCCESS) {
5434 goto release_minor;
5437 rv = crypto_provider_copyin_mech_param(real_provider,
5438 STRUCT_FADDR(generate_key, gk_mechanism), &mech, mode, &error);
5440 if (rv == CRYPTO_NOT_SUPPORTED) {
5441 allocated_by_crypto_module = B_TRUE;
5442 if (!copyin_mech(mode, sp,
5443 STRUCT_FADDR(generate_key, gk_mechanism),
5444 &mech, &mech_rctl_bytes, &mech_rctl_chk, &rv, &error)) {
5445 goto release_minor;
5447 } else {
5448 if (rv != CRYPTO_SUCCESS)
5449 goto release_minor;
5452 count = STRUCT_FGET(generate_key, gk_count);
5453 attributes = STRUCT_FGETP(generate_key, gk_attributes);
5454 if (!copyin_attributes(mode, sp, count, attributes, &k_attrs,
5455 &k_attrs_size, NULL, &rv, &error, &key_rctl_bytes,
5456 &key_rctl_chk, B_TRUE)) {
5457 goto release_minor;
5460 KCF_WRAP_KEY_OPS_PARAMS(&params, KCF_OP_KEY_GENERATE,
5461 sp->sd_provider_session->ps_session, &mech, k_attrs, count,
5462 &key_handle, NULL, 0, NULL, NULL, NULL, 0);
5464 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5466 if (rv == CRYPTO_SUCCESS)
5467 STRUCT_FSET(generate_key, gk_handle, key_handle);
5469 release_minor:
5470 CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
5471 CRYPTO_DECREMENT_RCTL_SESSION(sp, key_rctl_bytes, key_rctl_chk);
5473 if (k_attrs != NULL)
5474 kmem_free(k_attrs, k_attrs_size);
5476 if (error != 0)
5477 goto out;
5479 STRUCT_FSET(generate_key, gk_return_value, rv);
5480 if (copyout(STRUCT_BUF(generate_key), arg,
5481 STRUCT_SIZE(generate_key)) != 0) {
5482 if (rv == CRYPTO_SUCCESS) {
5483 KCF_WRAP_OBJECT_OPS_PARAMS(&params,
5484 KCF_OP_OBJECT_DESTROY,
5485 sp->sd_provider_session->ps_session, key_handle,
5486 NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
5488 (void) kcf_submit_request(real_provider, NULL,
5489 NULL, &params, B_FALSE);
5491 error = EFAULT;
5494 out:
5495 CRYPTO_SESSION_RELE(sp);
5496 crypto_release_minor(cm);
5498 if (real_provider != NULL) {
5499 crypto_free_mech(real_provider,
5500 allocated_by_crypto_module, &mech);
5501 KCF_PROV_REFRELE(real_provider);
5503 return (error);
5506 /* ARGSUSED */
5507 static int
5508 nostore_generate_key(dev_t dev, caddr_t arg, int mode, int *rval)
5510 STRUCT_DECL(crypto_nostore_generate_key, generate_key);
5511 #ifdef _LP64
5512 STRUCT_DECL(crypto_object_attribute, oa);
5513 #else
5514 /* LINTED E_FUNC_SET_NOT_USED */
5515 STRUCT_DECL(crypto_object_attribute, oa);
5516 #endif
5517 kcf_provider_desc_t *real_provider = NULL;
5518 kcf_req_params_t params;
5519 crypto_mechanism_t mech;
5520 crypto_object_attribute_t *k_in_attrs = NULL;
5521 crypto_object_attribute_t *k_out_attrs = NULL;
5522 crypto_session_id_t session_id;
5523 crypto_minor_t *cm;
5524 crypto_session_data_t *sp = NULL;
5525 caddr_t in_attributes;
5526 caddr_t out_attributes;
5527 size_t k_in_attrs_size;
5528 size_t k_out_attrs_size;
5529 size_t mech_rctl_bytes = 0;
5530 boolean_t mech_rctl_chk = B_FALSE;
5531 size_t in_key_rctl_bytes = 0, out_key_rctl_bytes = 0;
5532 boolean_t in_key_rctl_chk = B_FALSE;
5533 boolean_t out_key_rctl_chk = B_FALSE;
5534 uint_t in_count;
5535 uint_t out_count;
5536 int error = 0;
5537 int rv;
5538 boolean_t allocated_by_crypto_module = B_FALSE;
5539 caddr_t u_attrs = NULL;
5541 STRUCT_INIT(generate_key, mode);
5542 STRUCT_INIT(oa, mode);
5544 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5545 cmn_err(CE_WARN, "nostore_generate_key: failed holding minor");
5546 return (ENXIO);
5549 if (copyin(arg, STRUCT_BUF(generate_key),
5550 STRUCT_SIZE(generate_key)) != 0) {
5551 crypto_release_minor(cm);
5552 return (EFAULT);
5555 session_id = STRUCT_FGET(generate_key, ngk_session);
5557 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5558 goto release_minor;
5561 bcopy(STRUCT_FADDR(generate_key, ngk_mechanism), &mech.cm_type,
5562 sizeof (crypto_mech_type_t));
5564 if ((rv = kcf_get_hardware_provider(mech.cm_type, NULL,
5565 CRYPTO_MECH_INVALID, NULL, sp->sd_provider,
5566 &real_provider, CRYPTO_FG_GENERATE)) != CRYPTO_SUCCESS) {
5567 goto release_minor;
5570 rv = crypto_provider_copyin_mech_param(real_provider,
5571 STRUCT_FADDR(generate_key, ngk_mechanism), &mech, mode, &error);
5573 if (rv == CRYPTO_NOT_SUPPORTED) {
5574 allocated_by_crypto_module = B_TRUE;
5575 if (!copyin_mech(mode, sp, STRUCT_FADDR(generate_key,
5576 ngk_mechanism), &mech, &mech_rctl_bytes,
5577 &mech_rctl_chk, &rv, &error)) {
5578 goto release_minor;
5580 } else {
5581 if (rv != CRYPTO_SUCCESS)
5582 goto release_minor;
5585 in_count = STRUCT_FGET(generate_key, ngk_in_count);
5586 in_attributes = STRUCT_FGETP(generate_key, ngk_in_attributes);
5587 if (!copyin_attributes(mode, sp, in_count, in_attributes, &k_in_attrs,
5588 &k_in_attrs_size, NULL, &rv, &error, &in_key_rctl_bytes,
5589 &in_key_rctl_chk, B_TRUE)) {
5590 goto release_minor;
5593 out_count = STRUCT_FGET(generate_key, ngk_out_count);
5594 out_attributes = STRUCT_FGETP(generate_key, ngk_out_attributes);
5595 if (!copyin_attributes(mode, sp, out_count, out_attributes,
5596 &k_out_attrs,
5597 &k_out_attrs_size, &u_attrs, &rv, &error, &out_key_rctl_bytes,
5598 &out_key_rctl_chk, B_FALSE)) {
5599 goto release_minor;
5602 KCF_WRAP_NOSTORE_KEY_OPS_PARAMS(&params, KCF_OP_KEY_GENERATE,
5603 sp->sd_provider_session->ps_session, &mech, k_in_attrs, in_count,
5604 NULL, 0, NULL, k_out_attrs, out_count, NULL, 0);
5606 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5608 if (rv == CRYPTO_SUCCESS) {
5609 error = copyout_attributes(mode, out_attributes,
5610 out_count, k_out_attrs, u_attrs);
5612 release_minor:
5613 CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
5614 CRYPTO_DECREMENT_RCTL_SESSION(sp, in_key_rctl_bytes, in_key_rctl_chk);
5615 CRYPTO_DECREMENT_RCTL_SESSION(sp, out_key_rctl_bytes,
5616 out_key_rctl_chk);
5618 if (k_in_attrs != NULL)
5619 kmem_free(k_in_attrs, k_in_attrs_size);
5620 if (k_out_attrs != NULL) {
5621 bzero(k_out_attrs, k_out_attrs_size);
5622 kmem_free(k_out_attrs, k_out_attrs_size);
5625 if (u_attrs != NULL)
5626 kmem_free(u_attrs, out_count * STRUCT_SIZE(oa));
5628 if (error != 0)
5629 goto out;
5631 STRUCT_FSET(generate_key, ngk_return_value, rv);
5632 if (copyout(STRUCT_BUF(generate_key), arg,
5633 STRUCT_SIZE(generate_key)) != 0) {
5634 error = EFAULT;
5636 out:
5637 CRYPTO_SESSION_RELE(sp);
5638 crypto_release_minor(cm);
5640 if (real_provider != NULL) {
5641 crypto_free_mech(real_provider,
5642 allocated_by_crypto_module, &mech);
5643 KCF_PROV_REFRELE(real_provider);
5645 return (error);
5648 /* ARGSUSED */
5649 static int
5650 object_generate_key_pair(dev_t dev, caddr_t arg, int mode, int *rval)
5652 STRUCT_DECL(crypto_object_generate_key_pair, generate_key_pair);
5653 kcf_provider_desc_t *real_provider = NULL;
5654 kcf_req_params_t params;
5655 crypto_mechanism_t mech;
5656 crypto_object_attribute_t *k_pub_attrs = NULL;
5657 crypto_object_attribute_t *k_pri_attrs = NULL;
5658 crypto_session_id_t session_id;
5659 crypto_minor_t *cm;
5660 crypto_session_data_t *sp = NULL;
5661 crypto_object_id_t pub_handle;
5662 crypto_object_id_t pri_handle;
5663 caddr_t pri_attributes;
5664 caddr_t pub_attributes;
5665 size_t k_pub_attrs_size, k_pri_attrs_size;
5666 size_t mech_rctl_bytes = 0;
5667 boolean_t mech_rctl_chk = B_FALSE;
5668 size_t pub_rctl_bytes = 0;
5669 boolean_t pub_rctl_chk = B_FALSE;
5670 size_t pri_rctl_bytes = 0;
5671 boolean_t pri_rctl_chk = B_FALSE;
5672 uint_t pub_count;
5673 uint_t pri_count;
5674 int error = 0;
5675 int rv;
5676 boolean_t allocated_by_crypto_module = B_FALSE;
5678 STRUCT_INIT(generate_key_pair, mode);
5680 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5681 cmn_err(CE_WARN,
5682 "object_generate_key_pair: failed holding minor");
5683 return (ENXIO);
5686 if (copyin(arg, STRUCT_BUF(generate_key_pair),
5687 STRUCT_SIZE(generate_key_pair)) != 0) {
5688 crypto_release_minor(cm);
5689 return (EFAULT);
5692 session_id = STRUCT_FGET(generate_key_pair, kp_session);
5694 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5695 goto release_minor;
5698 bcopy(STRUCT_FADDR(generate_key_pair, kp_mechanism), &mech.cm_type,
5699 sizeof (crypto_mech_type_t));
5701 if ((rv = kcf_get_hardware_provider(mech.cm_type, NULL,
5702 CRYPTO_MECH_INVALID, NULL, sp->sd_provider,
5703 &real_provider, CRYPTO_FG_GENERATE_KEY_PAIR)) != CRYPTO_SUCCESS) {
5704 goto release_minor;
5707 rv = crypto_provider_copyin_mech_param(real_provider,
5708 STRUCT_FADDR(generate_key_pair, kp_mechanism), &mech, mode, &error);
5710 if (rv == CRYPTO_NOT_SUPPORTED) {
5711 allocated_by_crypto_module = B_TRUE;
5712 if (!copyin_mech(mode, sp, STRUCT_FADDR(generate_key_pair,
5713 kp_mechanism), &mech, &mech_rctl_bytes,
5714 &mech_rctl_chk, &rv, &error)) {
5715 goto release_minor;
5717 } else {
5718 if (rv != CRYPTO_SUCCESS)
5719 goto release_minor;
5722 pub_count = STRUCT_FGET(generate_key_pair, kp_public_count);
5723 pri_count = STRUCT_FGET(generate_key_pair, kp_private_count);
5725 pub_attributes = STRUCT_FGETP(generate_key_pair, kp_public_attributes);
5726 if (!copyin_attributes(mode, sp, pub_count, pub_attributes,
5727 &k_pub_attrs, &k_pub_attrs_size, NULL, &rv, &error, &pub_rctl_bytes,
5728 &pub_rctl_chk, B_TRUE)) {
5729 goto release_minor;
5732 pri_attributes = STRUCT_FGETP(generate_key_pair, kp_private_attributes);
5733 if (!copyin_attributes(mode, sp, pri_count, pri_attributes,
5734 &k_pri_attrs, &k_pri_attrs_size, NULL, &rv, &error,
5735 &pri_rctl_bytes, &pri_rctl_chk, B_TRUE)) {
5736 goto release_minor;
5739 KCF_WRAP_KEY_OPS_PARAMS(&params, KCF_OP_KEY_GENERATE_PAIR,
5740 sp->sd_provider_session->ps_session, &mech, k_pub_attrs,
5741 pub_count, &pub_handle, k_pri_attrs, pri_count, &pri_handle,
5742 NULL, NULL, 0);
5744 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5746 if (rv == CRYPTO_SUCCESS) {
5747 STRUCT_FSET(generate_key_pair, kp_public_handle, pub_handle);
5748 STRUCT_FSET(generate_key_pair, kp_private_handle, pri_handle);
5751 release_minor:
5752 CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
5753 CRYPTO_DECREMENT_RCTL_SESSION(sp, pub_rctl_bytes, pub_rctl_chk);
5754 CRYPTO_DECREMENT_RCTL_SESSION(sp, pri_rctl_bytes, pri_rctl_chk);
5756 if (k_pub_attrs != NULL)
5757 kmem_free(k_pub_attrs, k_pub_attrs_size);
5759 if (k_pri_attrs != NULL)
5760 kmem_free(k_pri_attrs, k_pri_attrs_size);
5762 if (error != 0)
5763 goto out;
5765 STRUCT_FSET(generate_key_pair, kp_return_value, rv);
5766 if (copyout(STRUCT_BUF(generate_key_pair), arg,
5767 STRUCT_SIZE(generate_key_pair)) != 0) {
5768 if (rv == CRYPTO_SUCCESS) {
5769 KCF_WRAP_OBJECT_OPS_PARAMS(&params,
5770 KCF_OP_OBJECT_DESTROY,
5771 sp->sd_provider_session->ps_session, pub_handle,
5772 NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
5774 (void) kcf_submit_request(real_provider, NULL,
5775 NULL, &params, B_FALSE);
5777 KCF_WRAP_OBJECT_OPS_PARAMS(&params,
5778 KCF_OP_OBJECT_DESTROY,
5779 sp->sd_provider_session->ps_session, pri_handle,
5780 NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
5782 (void) kcf_submit_request(real_provider, NULL,
5783 NULL, &params, B_FALSE);
5785 error = EFAULT;
5788 out:
5789 CRYPTO_SESSION_RELE(sp);
5790 crypto_release_minor(cm);
5792 if (real_provider != NULL) {
5793 crypto_free_mech(real_provider,
5794 allocated_by_crypto_module, &mech);
5795 KCF_PROV_REFRELE(real_provider);
5797 return (error);
5800 /* ARGSUSED */
5801 static int
5802 nostore_generate_key_pair(dev_t dev, caddr_t arg, int mode, int *rval)
5804 STRUCT_DECL(crypto_nostore_generate_key_pair, generate_key_pair);
5805 #ifdef _LP64
5806 STRUCT_DECL(crypto_object_attribute, oa);
5807 #else
5808 /* LINTED E_FUNC_SET_NOT_USED */
5809 STRUCT_DECL(crypto_object_attribute, oa);
5810 #endif
5811 kcf_provider_desc_t *real_provider = NULL;
5812 kcf_req_params_t params;
5813 crypto_mechanism_t mech;
5814 crypto_object_attribute_t *k_in_pub_attrs = NULL;
5815 crypto_object_attribute_t *k_in_pri_attrs = NULL;
5816 crypto_object_attribute_t *k_out_pub_attrs = NULL;
5817 crypto_object_attribute_t *k_out_pri_attrs = NULL;
5818 crypto_session_id_t session_id;
5819 crypto_minor_t *cm;
5820 crypto_session_data_t *sp = NULL;
5821 caddr_t in_pri_attributes;
5822 caddr_t in_pub_attributes;
5823 caddr_t out_pri_attributes;
5824 caddr_t out_pub_attributes;
5825 size_t k_in_pub_attrs_size, k_in_pri_attrs_size;
5826 size_t k_out_pub_attrs_size, k_out_pri_attrs_size;
5827 size_t mech_rctl_bytes = 0;
5828 boolean_t mech_rctl_chk = B_FALSE;
5829 size_t in_pub_rctl_bytes = 0;
5830 boolean_t in_pub_rctl_chk = B_FALSE;
5831 size_t in_pri_rctl_bytes = 0;
5832 boolean_t in_pri_rctl_chk = B_FALSE;
5833 size_t out_pub_rctl_bytes = 0;
5834 boolean_t out_pub_rctl_chk = B_FALSE;
5835 size_t out_pri_rctl_bytes = 0;
5836 boolean_t out_pri_rctl_chk = B_FALSE;
5837 uint_t in_pub_count;
5838 uint_t in_pri_count;
5839 uint_t out_pub_count;
5840 uint_t out_pri_count;
5841 int error = 0;
5842 int rv;
5843 boolean_t allocated_by_crypto_module = B_FALSE;
5844 caddr_t u_pub_attrs = NULL;
5845 caddr_t u_pri_attrs = NULL;
5847 STRUCT_INIT(generate_key_pair, mode);
5848 STRUCT_INIT(oa, mode);
5850 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
5851 cmn_err(CE_WARN,
5852 "nostore_generate_key_pair: failed holding minor");
5853 return (ENXIO);
5856 if (copyin(arg, STRUCT_BUF(generate_key_pair),
5857 STRUCT_SIZE(generate_key_pair)) != 0) {
5858 crypto_release_minor(cm);
5859 return (EFAULT);
5862 session_id = STRUCT_FGET(generate_key_pair, nkp_session);
5864 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
5865 goto release_minor;
5868 bcopy(STRUCT_FADDR(generate_key_pair, nkp_mechanism), &mech.cm_type,
5869 sizeof (crypto_mech_type_t));
5871 if ((rv = kcf_get_hardware_provider(mech.cm_type, NULL,
5872 CRYPTO_MECH_INVALID, NULL, sp->sd_provider,
5873 &real_provider, CRYPTO_FG_GENERATE_KEY_PAIR)) != CRYPTO_SUCCESS) {
5874 goto release_minor;
5877 rv = crypto_provider_copyin_mech_param(real_provider,
5878 STRUCT_FADDR(generate_key_pair, nkp_mechanism), &mech, mode,
5879 &error);
5881 if (rv == CRYPTO_NOT_SUPPORTED) {
5882 allocated_by_crypto_module = B_TRUE;
5883 if (!copyin_mech(mode, sp, STRUCT_FADDR(generate_key_pair,
5884 nkp_mechanism), &mech, &mech_rctl_bytes,
5885 &mech_rctl_chk, &rv, &error)) {
5886 goto release_minor;
5888 } else {
5889 if (rv != CRYPTO_SUCCESS)
5890 goto release_minor;
5893 in_pub_count = STRUCT_FGET(generate_key_pair, nkp_in_public_count);
5894 in_pri_count = STRUCT_FGET(generate_key_pair, nkp_in_private_count);
5896 in_pub_attributes = STRUCT_FGETP(generate_key_pair,
5897 nkp_in_public_attributes);
5898 if (!copyin_attributes(mode, sp, in_pub_count, in_pub_attributes,
5899 &k_in_pub_attrs, &k_in_pub_attrs_size, NULL, &rv, &error,
5900 &in_pub_rctl_bytes, &in_pub_rctl_chk, B_TRUE)) {
5901 goto release_minor;
5904 in_pri_attributes = STRUCT_FGETP(generate_key_pair,
5905 nkp_in_private_attributes);
5906 if (!copyin_attributes(mode, sp, in_pri_count, in_pri_attributes,
5907 &k_in_pri_attrs, &k_in_pri_attrs_size, NULL, &rv, &error,
5908 &in_pri_rctl_bytes, &in_pri_rctl_chk, B_TRUE)) {
5909 goto release_minor;
5912 out_pub_count = STRUCT_FGET(generate_key_pair, nkp_out_public_count);
5913 out_pri_count = STRUCT_FGET(generate_key_pair, nkp_out_private_count);
5915 out_pub_attributes = STRUCT_FGETP(generate_key_pair,
5916 nkp_out_public_attributes);
5917 if (!copyin_attributes(mode, sp, out_pub_count, out_pub_attributes,
5918 &k_out_pub_attrs, &k_out_pub_attrs_size, &u_pub_attrs, &rv, &error,
5919 &out_pub_rctl_bytes, &out_pub_rctl_chk, B_FALSE)) {
5920 goto release_minor;
5923 out_pri_attributes = STRUCT_FGETP(generate_key_pair,
5924 nkp_out_private_attributes);
5925 if (!copyin_attributes(mode, sp, out_pri_count, out_pri_attributes,
5926 &k_out_pri_attrs, &k_out_pri_attrs_size, &u_pri_attrs, &rv, &error,
5927 &out_pri_rctl_bytes, &out_pri_rctl_chk, B_FALSE)) {
5928 goto release_minor;
5931 KCF_WRAP_NOSTORE_KEY_OPS_PARAMS(&params, KCF_OP_KEY_GENERATE_PAIR,
5932 sp->sd_provider_session->ps_session, &mech, k_in_pub_attrs,
5933 in_pub_count, k_in_pri_attrs, in_pri_count, NULL, k_out_pub_attrs,
5934 out_pub_count, k_out_pri_attrs, out_pri_count);
5936 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
5938 if (rv == CRYPTO_SUCCESS) {
5939 error = copyout_attributes(mode, out_pub_attributes,
5940 out_pub_count, k_out_pub_attrs, u_pub_attrs);
5941 if (error != CRYPTO_SUCCESS)
5942 goto release_minor;
5943 error = copyout_attributes(mode, out_pri_attributes,
5944 out_pri_count, k_out_pri_attrs, u_pri_attrs);
5947 release_minor:
5948 CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
5949 CRYPTO_DECREMENT_RCTL_SESSION(sp, in_pub_rctl_bytes, in_pub_rctl_chk);
5950 CRYPTO_DECREMENT_RCTL_SESSION(sp, in_pri_rctl_bytes, in_pri_rctl_chk);
5951 CRYPTO_DECREMENT_RCTL_SESSION(sp, out_pub_rctl_bytes,
5952 out_pub_rctl_chk);
5953 CRYPTO_DECREMENT_RCTL_SESSION(sp, out_pri_rctl_bytes,
5954 out_pri_rctl_chk);
5956 if (k_in_pub_attrs != NULL)
5957 kmem_free(k_in_pub_attrs, k_in_pub_attrs_size);
5959 if (k_in_pri_attrs != NULL)
5960 kmem_free(k_in_pri_attrs, k_in_pri_attrs_size);
5962 if (k_out_pub_attrs != NULL)
5963 kmem_free(k_out_pub_attrs, k_out_pub_attrs_size);
5965 if (k_out_pri_attrs != NULL) {
5966 bzero(k_out_pri_attrs, k_out_pri_attrs_size);
5967 kmem_free(k_out_pri_attrs, k_out_pri_attrs_size);
5970 if (u_pub_attrs != NULL)
5971 kmem_free(u_pub_attrs, out_pub_count * STRUCT_SIZE(oa));
5973 if (u_pri_attrs != NULL)
5974 kmem_free(u_pri_attrs, out_pri_count * STRUCT_SIZE(oa));
5976 if (error != 0)
5977 goto out;
5979 STRUCT_FSET(generate_key_pair, nkp_return_value, rv);
5980 if (copyout(STRUCT_BUF(generate_key_pair), arg,
5981 STRUCT_SIZE(generate_key_pair)) != 0) {
5982 error = EFAULT;
5984 out:
5985 CRYPTO_SESSION_RELE(sp);
5986 crypto_release_minor(cm);
5988 if (real_provider != NULL) {
5989 crypto_free_mech(real_provider,
5990 allocated_by_crypto_module, &mech);
5991 KCF_PROV_REFRELE(real_provider);
5993 return (error);
5996 /* ARGSUSED */
5997 static int
5998 object_wrap_key(dev_t dev, caddr_t arg, int mode, int *rval)
6000 STRUCT_DECL(crypto_object_wrap_key, wrap_key);
6001 kcf_provider_desc_t *real_provider = NULL;
6002 kcf_req_params_t params;
6003 crypto_mechanism_t mech;
6004 crypto_key_t key;
6005 crypto_session_id_t session_id;
6006 crypto_minor_t *cm;
6007 crypto_session_data_t *sp = NULL;
6008 crypto_object_id_t handle;
6009 size_t mech_rctl_bytes = 0, key_rctl_bytes = 0;
6010 boolean_t mech_rctl_chk = B_FALSE;
6011 boolean_t key_rctl_chk = B_FALSE;
6012 size_t wrapped_key_rctl_bytes = 0;
6013 boolean_t wrapped_key_rctl_chk = B_FALSE;
6014 size_t wrapped_key_len, new_wrapped_key_len;
6015 uchar_t *wrapped_key = NULL;
6016 char *wrapped_key_buffer;
6017 int error = 0;
6018 int rv;
6019 boolean_t allocated_by_crypto_module = B_FALSE;
6021 STRUCT_INIT(wrap_key, mode);
6023 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
6024 cmn_err(CE_WARN, "object_wrap_key: failed holding minor");
6025 return (ENXIO);
6028 if (copyin(arg, STRUCT_BUF(wrap_key), STRUCT_SIZE(wrap_key)) != 0) {
6029 crypto_release_minor(cm);
6030 return (EFAULT);
6033 bzero(&key, sizeof (crypto_key_t));
6035 session_id = STRUCT_FGET(wrap_key, wk_session);
6037 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
6038 goto out;
6041 bcopy(STRUCT_FADDR(wrap_key, wk_mechanism), &mech.cm_type,
6042 sizeof (crypto_mech_type_t));
6044 /* We need the key length for provider selection so copy it in now. */
6045 if (!copyin_key(mode, sp, STRUCT_FADDR(wrap_key, wk_wrapping_key), &key,
6046 &key_rctl_bytes, &key_rctl_chk, &rv, &error)) {
6047 goto out;
6050 wrapped_key_len = STRUCT_FGET(wrap_key, wk_wrapped_key_len);
6052 if ((rv = kcf_get_hardware_provider(mech.cm_type, &key,
6053 CRYPTO_MECH_INVALID, NULL, sp->sd_provider,
6054 &real_provider, CRYPTO_FG_WRAP)) != CRYPTO_SUCCESS) {
6055 goto out;
6058 rv = crypto_provider_copyin_mech_param(real_provider,
6059 STRUCT_FADDR(wrap_key, wk_mechanism), &mech, mode, &error);
6061 if (rv == CRYPTO_NOT_SUPPORTED) {
6062 allocated_by_crypto_module = B_TRUE;
6063 if (!copyin_mech(mode, sp, STRUCT_FADDR(wrap_key, wk_mechanism),
6064 &mech, &mech_rctl_bytes, &mech_rctl_chk, &rv, &error)) {
6065 goto out;
6067 } else {
6068 if (rv != CRYPTO_SUCCESS)
6069 goto out;
6073 * Don't allocate output buffer unless both buffer pointer and
6074 * buffer length are not NULL or 0 (length).
6076 wrapped_key_buffer = STRUCT_FGETP(wrap_key, wk_wrapped_key);
6077 if (wrapped_key_buffer == NULL || wrapped_key_len == 0) {
6078 wrapped_key_len = 0;
6081 if (wrapped_key_len > crypto_max_buffer_len) {
6082 cmn_err(CE_NOTE, "object_wrap_key: buffer greater than %ld "
6083 "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
6084 rv = CRYPTO_ARGUMENTS_BAD;
6085 goto out;
6088 if ((rv = CRYPTO_BUFFER_CHECK(sp, wrapped_key_len,
6089 wrapped_key_rctl_chk)) != CRYPTO_SUCCESS) {
6090 goto out;
6093 /* new_wrapped_key_len can be modified by the provider */
6094 wrapped_key_rctl_bytes = new_wrapped_key_len = wrapped_key_len;
6095 wrapped_key = kmem_alloc(wrapped_key_len, KM_SLEEP);
6097 handle = STRUCT_FGET(wrap_key, wk_object_handle);
6098 KCF_WRAP_KEY_OPS_PARAMS(&params, KCF_OP_KEY_WRAP,
6099 sp->sd_provider_session->ps_session, &mech, NULL, 0, &handle,
6100 NULL, 0, NULL, &key, wrapped_key, &new_wrapped_key_len);
6102 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
6104 if (rv == CRYPTO_SUCCESS) {
6105 if (wrapped_key_len != 0 && copyout(wrapped_key,
6106 wrapped_key_buffer, new_wrapped_key_len) != 0) {
6107 error = EFAULT;
6109 STRUCT_FSET(wrap_key, wk_wrapped_key_len,
6110 (ulong_t)new_wrapped_key_len);
6113 if (rv == CRYPTO_BUFFER_TOO_SMALL) {
6115 * The providers return CRYPTO_BUFFER_TOO_SMALL even for case 1
6116 * of section 11.2 of the pkcs11 spec. We catch it here and
6117 * provide the correct pkcs11 return value.
6119 if (STRUCT_FGETP(wrap_key, wk_wrapped_key) == NULL)
6120 rv = CRYPTO_SUCCESS;
6121 STRUCT_FSET(wrap_key, wk_wrapped_key_len,
6122 (ulong_t)new_wrapped_key_len);
6125 out:
6126 CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
6127 CRYPTO_DECREMENT_RCTL_SESSION(sp, key_rctl_bytes, key_rctl_chk);
6128 CRYPTO_DECREMENT_RCTL_SESSION(sp, wrapped_key_rctl_bytes,
6129 wrapped_key_rctl_chk);
6130 CRYPTO_SESSION_RELE(sp);
6132 crypto_release_minor(cm);
6134 if (real_provider != NULL) {
6135 crypto_free_mech(real_provider,
6136 allocated_by_crypto_module, &mech);
6137 KCF_PROV_REFRELE(real_provider);
6140 if (wrapped_key != NULL)
6141 kmem_free(wrapped_key, wrapped_key_len);
6143 free_crypto_key(&key);
6145 if (error != 0)
6146 return (error);
6148 STRUCT_FSET(wrap_key, wk_return_value, rv);
6149 if (copyout(STRUCT_BUF(wrap_key), arg, STRUCT_SIZE(wrap_key)) != 0) {
6150 return (EFAULT);
6152 return (0);
6155 /* ARGSUSED */
6156 static int
6157 object_unwrap_key(dev_t dev, caddr_t arg, int mode, int *rval)
6159 STRUCT_DECL(crypto_object_unwrap_key, unwrap_key);
6160 kcf_provider_desc_t *real_provider = NULL;
6161 kcf_req_params_t params;
6162 crypto_mechanism_t mech;
6163 crypto_key_t unwrapping_key;
6164 crypto_session_id_t session_id;
6165 crypto_minor_t *cm;
6166 crypto_session_data_t *sp = NULL;
6167 crypto_object_id_t handle;
6168 crypto_object_attribute_t *k_attrs = NULL;
6169 size_t k_attrs_size;
6170 size_t mech_rctl_bytes = 0, unwrapping_key_rctl_bytes = 0;
6171 boolean_t mech_rctl_chk = B_FALSE;
6172 boolean_t unwrapping_key_rctl_chk = B_FALSE;
6173 size_t wrapped_key_rctl_bytes = 0, k_attrs_rctl_bytes = 0;
6174 boolean_t wrapped_key_rctl_chk = B_FALSE;
6175 boolean_t k_attrs_rctl_chk = B_FALSE;
6176 size_t wrapped_key_len;
6177 uchar_t *wrapped_key = NULL;
6178 int error = 0;
6179 int rv;
6180 uint_t count;
6181 caddr_t uk_attributes;
6182 boolean_t allocated_by_crypto_module = B_FALSE;
6184 STRUCT_INIT(unwrap_key, mode);
6186 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
6187 cmn_err(CE_WARN, "object_unwrap_key: failed holding minor");
6188 return (ENXIO);
6191 if (copyin(arg, STRUCT_BUF(unwrap_key), STRUCT_SIZE(unwrap_key)) != 0) {
6192 crypto_release_minor(cm);
6193 return (EFAULT);
6196 bzero(&unwrapping_key, sizeof (unwrapping_key));
6198 session_id = STRUCT_FGET(unwrap_key, uk_session);
6200 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
6201 goto release_minor;
6204 bcopy(STRUCT_FADDR(unwrap_key, uk_mechanism), &mech.cm_type,
6205 sizeof (crypto_mech_type_t));
6207 /* We need the key length for provider selection so copy it in now. */
6208 if (!copyin_key(mode, sp, STRUCT_FADDR(unwrap_key, uk_unwrapping_key),
6209 &unwrapping_key, &unwrapping_key_rctl_bytes,
6210 &unwrapping_key_rctl_chk, &rv, &error)) {
6211 goto release_minor;
6214 if ((rv = kcf_get_hardware_provider(mech.cm_type, &unwrapping_key,
6215 CRYPTO_MECH_INVALID, NULL, sp->sd_provider,
6216 &real_provider, CRYPTO_FG_UNWRAP)) != CRYPTO_SUCCESS) {
6217 goto release_minor;
6220 rv = crypto_provider_copyin_mech_param(real_provider,
6221 STRUCT_FADDR(unwrap_key, uk_mechanism), &mech, mode, &error);
6223 if (rv == CRYPTO_NOT_SUPPORTED) {
6224 allocated_by_crypto_module = B_TRUE;
6225 if (!copyin_mech(mode, sp,
6226 STRUCT_FADDR(unwrap_key, uk_mechanism),
6227 &mech, &mech_rctl_bytes, &mech_rctl_chk, &rv, &error)) {
6228 goto release_minor;
6230 } else {
6231 if (rv != CRYPTO_SUCCESS)
6232 goto release_minor;
6235 count = STRUCT_FGET(unwrap_key, uk_count);
6236 uk_attributes = STRUCT_FGETP(unwrap_key, uk_attributes);
6237 if (!copyin_attributes(mode, sp, count, uk_attributes, &k_attrs,
6238 &k_attrs_size, NULL, &rv, &error, &k_attrs_rctl_bytes,
6239 &k_attrs_rctl_chk, B_TRUE)) {
6240 goto release_minor;
6243 wrapped_key_len = STRUCT_FGET(unwrap_key, uk_wrapped_key_len);
6244 if (wrapped_key_len > crypto_max_buffer_len) {
6245 cmn_err(CE_NOTE, "object_unwrap_key: buffer greater than %ld "
6246 "bytes, pid = %d", crypto_max_buffer_len, curproc->p_pid);
6247 rv = CRYPTO_ARGUMENTS_BAD;
6248 goto release_minor;
6251 if ((rv = CRYPTO_BUFFER_CHECK(sp, wrapped_key_len,
6252 wrapped_key_rctl_chk)) != CRYPTO_SUCCESS) {
6253 goto release_minor;
6255 wrapped_key_rctl_bytes = wrapped_key_len;
6256 wrapped_key = kmem_alloc(wrapped_key_len, KM_SLEEP);
6258 if (wrapped_key_len != 0 && copyin(STRUCT_FGETP(unwrap_key,
6259 uk_wrapped_key), wrapped_key, wrapped_key_len) != 0) {
6260 error = EFAULT;
6261 goto release_minor;
6264 /* wrapped_key_len is not modified by the unwrap operation */
6265 KCF_WRAP_KEY_OPS_PARAMS(&params, KCF_OP_KEY_UNWRAP,
6266 sp->sd_provider_session->ps_session, &mech, k_attrs, count, &handle,
6267 NULL, 0, NULL, &unwrapping_key, wrapped_key, &wrapped_key_len);
6269 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
6271 if (rv == CRYPTO_SUCCESS)
6272 STRUCT_FSET(unwrap_key, uk_object_handle, handle);
6274 release_minor:
6275 CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
6276 CRYPTO_DECREMENT_RCTL_SESSION(sp, unwrapping_key_rctl_bytes,
6277 unwrapping_key_rctl_chk);
6278 CRYPTO_DECREMENT_RCTL_SESSION(sp, wrapped_key_rctl_bytes,
6279 wrapped_key_rctl_chk);
6280 CRYPTO_DECREMENT_RCTL_SESSION(sp, k_attrs_rctl_bytes,
6281 k_attrs_rctl_chk);
6283 if (k_attrs != NULL)
6284 kmem_free(k_attrs, k_attrs_size);
6286 if (wrapped_key != NULL)
6287 kmem_free(wrapped_key, wrapped_key_len);
6289 free_crypto_key(&unwrapping_key);
6291 if (error != 0)
6292 goto out;
6294 STRUCT_FSET(unwrap_key, uk_return_value, rv);
6295 if (copyout(STRUCT_BUF(unwrap_key), arg,
6296 STRUCT_SIZE(unwrap_key)) != 0) {
6297 if (rv == CRYPTO_SUCCESS) {
6298 KCF_WRAP_OBJECT_OPS_PARAMS(&params,
6299 KCF_OP_OBJECT_DESTROY,
6300 sp->sd_provider_session->ps_session, handle,
6301 NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
6303 (void) kcf_submit_request(real_provider, NULL,
6304 NULL, &params, B_FALSE);
6306 error = EFAULT;
6309 out:
6310 CRYPTO_SESSION_RELE(sp);
6311 crypto_release_minor(cm);
6313 if (real_provider != NULL) {
6314 crypto_free_mech(real_provider,
6315 allocated_by_crypto_module, &mech);
6316 KCF_PROV_REFRELE(real_provider);
6319 return (error);
6322 /* ARGSUSED */
6323 static int
6324 object_derive_key(dev_t dev, caddr_t arg, int mode, int *rval)
6326 STRUCT_DECL(crypto_derive_key, derive_key);
6327 kcf_provider_desc_t *real_provider = NULL;
6328 kcf_req_params_t params;
6329 crypto_object_attribute_t *k_attrs = NULL;
6330 crypto_mechanism_t mech;
6331 crypto_key_t base_key;
6332 crypto_session_id_t session_id;
6333 crypto_minor_t *cm;
6334 crypto_session_data_t *sp = NULL;
6335 crypto_object_id_t handle;
6336 size_t k_attrs_size;
6337 size_t key_rctl_bytes = 0, mech_rctl_bytes = 0;
6338 boolean_t mech_rctl_chk = B_FALSE;
6339 boolean_t key_rctl_chk = B_FALSE;
6340 size_t attributes_rctl_bytes = 0;
6341 boolean_t attributes_rctl_chk = B_FALSE;
6342 caddr_t attributes;
6343 uint_t count;
6344 int error = 0;
6345 int rv;
6346 boolean_t allocated_by_crypto_module = B_FALSE;
6347 boolean_t please_destroy_object = B_FALSE;
6349 STRUCT_INIT(derive_key, mode);
6351 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
6352 cmn_err(CE_WARN, "object_derive_key: failed holding minor");
6353 return (ENXIO);
6356 if (copyin(arg, STRUCT_BUF(derive_key), STRUCT_SIZE(derive_key)) != 0) {
6357 crypto_release_minor(cm);
6358 return (EFAULT);
6361 bzero(&base_key, sizeof (base_key));
6363 session_id = STRUCT_FGET(derive_key, dk_session);
6365 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
6366 goto release_minor;
6369 bcopy(STRUCT_FADDR(derive_key, dk_mechanism), &mech.cm_type,
6370 sizeof (crypto_mech_type_t));
6372 /* We need the key length for provider selection so copy it in now. */
6373 if (!copyin_key(mode, sp, STRUCT_FADDR(derive_key, dk_base_key),
6374 &base_key, &key_rctl_bytes, &key_rctl_chk, &rv, &error)) {
6375 goto release_minor;
6378 if ((rv = kcf_get_hardware_provider(mech.cm_type, &base_key,
6379 CRYPTO_MECH_INVALID, NULL, sp->sd_provider,
6380 &real_provider, CRYPTO_FG_DERIVE)) != CRYPTO_SUCCESS) {
6381 goto release_minor;
6384 rv = crypto_provider_copyin_mech_param(real_provider,
6385 STRUCT_FADDR(derive_key, dk_mechanism), &mech, mode, &error);
6387 if (rv == CRYPTO_NOT_SUPPORTED) {
6388 allocated_by_crypto_module = B_TRUE;
6389 if (!copyin_mech(mode, sp,
6390 STRUCT_FADDR(derive_key, dk_mechanism),
6391 &mech, &mech_rctl_bytes, &mech_rctl_chk, &rv, &error)) {
6392 goto release_minor;
6394 } else {
6395 if (rv != CRYPTO_SUCCESS)
6396 goto release_minor;
6399 count = STRUCT_FGET(derive_key, dk_count);
6401 attributes = STRUCT_FGETP(derive_key, dk_attributes);
6402 if (!copyin_attributes(mode, sp, count, attributes, &k_attrs,
6403 &k_attrs_size, NULL, &rv, &error,
6404 &attributes_rctl_bytes, &attributes_rctl_chk, B_TRUE)) {
6405 goto release_minor;
6408 KCF_WRAP_KEY_OPS_PARAMS(&params, KCF_OP_KEY_DERIVE,
6409 sp->sd_provider_session->ps_session, &mech, k_attrs, count,
6410 &handle, NULL, 0, NULL, &base_key, NULL, NULL);
6412 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
6414 if (rv == CRYPTO_SUCCESS) {
6415 STRUCT_FSET(derive_key, dk_object_handle, handle);
6417 rv = crypto_provider_copyout_mech_param(real_provider,
6418 &mech, STRUCT_FADDR(derive_key, dk_mechanism),
6419 mode, &error);
6421 if (rv == CRYPTO_NOT_SUPPORTED) {
6422 rv = CRYPTO_SUCCESS;
6423 goto release_minor;
6426 if (rv != CRYPTO_SUCCESS)
6427 please_destroy_object = B_TRUE;
6430 release_minor:
6431 CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
6432 CRYPTO_DECREMENT_RCTL_SESSION(sp, key_rctl_bytes, key_rctl_chk);
6433 CRYPTO_DECREMENT_RCTL_SESSION(sp, attributes_rctl_bytes,
6434 attributes_rctl_chk);
6436 if (k_attrs != NULL)
6437 kmem_free(k_attrs, k_attrs_size);
6439 free_crypto_key(&base_key);
6441 if (error != 0)
6442 goto out;
6444 STRUCT_FSET(derive_key, dk_return_value, rv);
6445 if (copyout(STRUCT_BUF(derive_key), arg,
6446 STRUCT_SIZE(derive_key)) != 0) {
6447 if (rv == CRYPTO_SUCCESS) {
6448 please_destroy_object = B_TRUE;
6449 error = EFAULT;
6452 out:
6453 if (please_destroy_object) {
6454 KCF_WRAP_OBJECT_OPS_PARAMS(&params, KCF_OP_OBJECT_DESTROY,
6455 sp->sd_provider_session->ps_session, handle,
6456 NULL, 0, NULL, 0, NULL, NULL, 0, NULL);
6458 (void) kcf_submit_request(real_provider, NULL,
6459 NULL, &params, B_FALSE);
6462 CRYPTO_SESSION_RELE(sp);
6463 crypto_release_minor(cm);
6465 if (real_provider != NULL) {
6466 crypto_free_mech(real_provider,
6467 allocated_by_crypto_module, &mech);
6468 KCF_PROV_REFRELE(real_provider);
6470 return (error);
6473 /* ARGSUSED */
6474 static int
6475 nostore_derive_key(dev_t dev, caddr_t arg, int mode, int *rval)
6477 STRUCT_DECL(crypto_nostore_derive_key, derive_key);
6478 #ifdef _LP64
6479 STRUCT_DECL(crypto_object_attribute, oa);
6480 #else
6481 /* LINTED E_FUNC_SET_NOT_USED */
6482 STRUCT_DECL(crypto_object_attribute, oa);
6483 #endif
6484 kcf_provider_desc_t *real_provider = NULL;
6485 kcf_req_params_t params;
6486 crypto_object_attribute_t *k_in_attrs = NULL;
6487 crypto_object_attribute_t *k_out_attrs = NULL;
6488 crypto_mechanism_t mech;
6489 crypto_key_t base_key;
6490 crypto_session_id_t session_id;
6491 crypto_minor_t *cm;
6492 crypto_session_data_t *sp = NULL;
6493 size_t k_in_attrs_size, k_out_attrs_size;
6494 size_t key_rctl_bytes = 0, mech_rctl_bytes = 0;
6495 boolean_t mech_rctl_chk = B_FALSE;
6496 boolean_t key_rctl_chk = B_FALSE;
6497 size_t in_attributes_rctl_bytes = 0;
6498 size_t out_attributes_rctl_bytes = 0;
6499 boolean_t in_attributes_rctl_chk = B_FALSE;
6500 boolean_t out_attributes_rctl_chk = B_FALSE;
6501 caddr_t in_attributes, out_attributes;
6502 uint_t in_count, out_count;
6503 int error = 0;
6504 int rv;
6505 boolean_t allocated_by_crypto_module = B_FALSE;
6506 caddr_t u_attrs = NULL;
6508 STRUCT_INIT(derive_key, mode);
6509 STRUCT_INIT(oa, mode);
6511 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
6512 cmn_err(CE_WARN, "nostore_derive_key: failed holding minor");
6513 return (ENXIO);
6516 if (copyin(arg, STRUCT_BUF(derive_key), STRUCT_SIZE(derive_key)) != 0) {
6517 crypto_release_minor(cm);
6518 return (EFAULT);
6521 bzero(&base_key, sizeof (base_key));
6523 session_id = STRUCT_FGET(derive_key, ndk_session);
6525 if (!get_session_ptr(session_id, cm, &sp, &error, &rv)) {
6526 goto release_minor;
6529 bcopy(STRUCT_FADDR(derive_key, ndk_mechanism), &mech.cm_type,
6530 sizeof (crypto_mech_type_t));
6532 /* We need the key length for provider selection so copy it in now. */
6533 if (!copyin_key(mode, sp, STRUCT_FADDR(derive_key, ndk_base_key),
6534 &base_key, &key_rctl_bytes, &key_rctl_chk, &rv, &error)) {
6535 goto release_minor;
6538 if ((rv = kcf_get_hardware_provider(mech.cm_type, &base_key,
6539 CRYPTO_MECH_INVALID, NULL, sp->sd_provider,
6540 &real_provider, CRYPTO_FG_DERIVE)) != CRYPTO_SUCCESS) {
6541 goto release_minor;
6544 rv = crypto_provider_copyin_mech_param(real_provider,
6545 STRUCT_FADDR(derive_key, ndk_mechanism), &mech, mode, &error);
6547 if (rv == CRYPTO_NOT_SUPPORTED) {
6548 allocated_by_crypto_module = B_TRUE;
6549 if (!copyin_mech(mode, sp,
6550 STRUCT_FADDR(derive_key, ndk_mechanism),
6551 &mech, &mech_rctl_bytes, &mech_rctl_chk, &rv, &error)) {
6552 goto release_minor;
6554 } else {
6555 if (rv != CRYPTO_SUCCESS)
6556 goto release_minor;
6559 in_count = STRUCT_FGET(derive_key, ndk_in_count);
6560 out_count = STRUCT_FGET(derive_key, ndk_out_count);
6562 in_attributes = STRUCT_FGETP(derive_key, ndk_in_attributes);
6563 if (!copyin_attributes(mode, sp, in_count, in_attributes, &k_in_attrs,
6564 &k_in_attrs_size, NULL, &rv, &error, &in_attributes_rctl_bytes,
6565 &in_attributes_rctl_chk, B_TRUE)) {
6566 goto release_minor;
6569 out_attributes = STRUCT_FGETP(derive_key, ndk_out_attributes);
6570 if (!copyin_attributes(mode, sp, out_count, out_attributes,
6571 &k_out_attrs, &k_out_attrs_size, &u_attrs, &rv, &error,
6572 &out_attributes_rctl_bytes,
6573 &out_attributes_rctl_chk, B_FALSE)) {
6574 goto release_minor;
6577 KCF_WRAP_NOSTORE_KEY_OPS_PARAMS(&params, KCF_OP_KEY_DERIVE,
6578 sp->sd_provider_session->ps_session, &mech, k_in_attrs, in_count,
6579 NULL, 0, &base_key, k_out_attrs, out_count, NULL, 0);
6581 rv = kcf_submit_request(real_provider, NULL, NULL, &params, B_FALSE);
6583 if (rv == CRYPTO_SUCCESS) {
6584 rv = crypto_provider_copyout_mech_param(real_provider,
6585 &mech, STRUCT_FADDR(derive_key, ndk_mechanism),
6586 mode, &error);
6588 if (rv == CRYPTO_NOT_SUPPORTED) {
6589 rv = CRYPTO_SUCCESS;
6591 /* copyout the derived secret */
6592 if (copyout_attributes(mode, out_attributes, out_count,
6593 k_out_attrs, u_attrs) != 0)
6594 error = EFAULT;
6597 release_minor:
6598 CRYPTO_DECREMENT_RCTL_SESSION(sp, mech_rctl_bytes, mech_rctl_chk);
6599 CRYPTO_DECREMENT_RCTL_SESSION(sp, key_rctl_bytes, key_rctl_chk);
6600 CRYPTO_DECREMENT_RCTL_SESSION(sp, in_attributes_rctl_bytes,
6601 in_attributes_rctl_chk);
6602 CRYPTO_DECREMENT_RCTL_SESSION(sp, out_attributes_rctl_bytes,
6603 out_attributes_rctl_chk);
6605 if (k_in_attrs != NULL)
6606 kmem_free(k_in_attrs, k_in_attrs_size);
6607 if (k_out_attrs != NULL) {
6608 bzero(k_out_attrs, k_out_attrs_size);
6609 kmem_free(k_out_attrs, k_out_attrs_size);
6612 if (u_attrs != NULL)
6613 kmem_free(u_attrs, out_count * STRUCT_SIZE(oa));
6615 free_crypto_key(&base_key);
6617 if (error != 0)
6618 goto out;
6620 STRUCT_FSET(derive_key, ndk_return_value, rv);
6621 if (copyout(STRUCT_BUF(derive_key), arg,
6622 STRUCT_SIZE(derive_key)) != 0) {
6623 error = EFAULT;
6625 out:
6626 CRYPTO_SESSION_RELE(sp);
6627 crypto_release_minor(cm);
6629 if (real_provider != NULL) {
6630 crypto_free_mech(real_provider,
6631 allocated_by_crypto_module, &mech);
6632 KCF_PROV_REFRELE(real_provider);
6634 return (error);
6637 static int
6638 get_provider_by_mech(dev_t dev, caddr_t arg, int mode, int *rval)
6640 _NOTE(ARGUNUSED(mode, rval))
6641 kcf_mech_entry_t *me;
6642 kcf_provider_desc_t *pd;
6643 crypto_key_t key;
6644 crypto_by_mech_t mech;
6645 crypto_provider_session_t *ps;
6646 crypto_minor_t *cm;
6647 int rv, error;
6649 if ((cm = crypto_hold_minor(getminor(dev))) == NULL) {
6650 cmn_err(CE_WARN, "get_provider_by_mech: failed holding minor");
6651 return (ENXIO);
6654 bzero(&key, sizeof (key));
6655 key.ck_format = CRYPTO_KEY_RAW;
6657 if (copyin(arg, &mech, sizeof (mech)) != 0) {
6658 crypto_release_minor(cm);
6659 return (EFAULT);
6662 key.ck_length = mech.mech_keylen;
6663 /* pd is returned held */
6664 if ((pd = kcf_get_mech_provider(mech.mech_type, &key, &me, &error,
6665 NULL, mech.mech_fg, 0)) == NULL) {
6666 rv = error;
6667 goto release_minor;
6670 /* don't want to allow direct access to software providers */
6671 if (pd->pd_prov_type == CRYPTO_SW_PROVIDER) {
6672 rv = CRYPTO_MECHANISM_INVALID;
6673 KCF_PROV_REFRELE(pd);
6674 cmn_err(CE_WARN, "software mech_type given");
6675 goto release_minor;
6678 mutex_enter(&cm->cm_lock);
6679 if ((rv = crypto_create_provider_session(cm, pd, pd->pd_sid, &ps, NULL))
6680 == CRYPTO_SUCCESS)
6681 rv = crypto_create_session_ptr(cm, pd, ps, &mech.session_id);
6683 mutex_exit(&cm->cm_lock);
6684 release_minor:
6685 crypto_release_minor(cm);
6686 mech.rv = rv;
6687 if (copyout(&mech, arg, sizeof (mech)) != 0)
6688 return (EFAULT);
6690 return (rv);
6693 /* ARGSUSED */
6694 static int
6695 crypto_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *c,
6696 int *rval)
6698 #define ARG ((caddr_t)arg)
6700 switch (cmd) {
6701 case CRYPTO_GET_FUNCTION_LIST:
6702 return (get_function_list(dev, ARG, mode, rval));
6704 case CRYPTO_GET_MECHANISM_NUMBER:
6705 return (get_mechanism_number(dev, ARG, mode, rval));
6707 case CRYPTO_GET_MECHANISM_LIST:
6708 return (get_mechanism_list(dev, ARG, mode, rval));
6710 case CRYPTO_GET_ALL_MECHANISM_INFO:
6711 return (get_all_mechanism_info(dev, ARG, mode, rval));
6713 case CRYPTO_GET_PROVIDER_LIST:
6714 return (get_provider_list(dev, ARG, mode, rval));
6716 case CRYPTO_GET_PROVIDER_BY_MECH:
6717 return (get_provider_by_mech(dev, ARG, mode, rval));
6719 case CRYPTO_GET_PROVIDER_INFO:
6720 return (get_provider_info(dev, ARG, mode, rval));
6722 case CRYPTO_GET_PROVIDER_MECHANISMS:
6723 return (get_provider_mechanisms(dev, ARG, mode, rval));
6725 case CRYPTO_GET_PROVIDER_MECHANISM_INFO:
6726 return (get_provider_mechanism_info(dev, ARG, mode, rval));
6728 case CRYPTO_OPEN_SESSION:
6729 return (open_session(dev, ARG, mode, rval));
6731 case CRYPTO_CLOSE_SESSION:
6732 return (close_session(dev, ARG, mode, rval));
6734 case CRYPTO_ENCRYPT_INIT:
6735 return (encrypt_init(dev, ARG, mode, rval));
6737 case CRYPTO_DECRYPT_INIT:
6738 return (decrypt_init(dev, ARG, mode, rval));
6740 case CRYPTO_ENCRYPT:
6741 return (encrypt(dev, ARG, mode, rval));
6743 case CRYPTO_DECRYPT:
6744 return (decrypt(dev, ARG, mode, rval));
6746 case CRYPTO_ENCRYPT_UPDATE:
6747 return (encrypt_update(dev, ARG, mode, rval));
6749 case CRYPTO_DECRYPT_UPDATE:
6750 return (decrypt_update(dev, ARG, mode, rval));
6752 case CRYPTO_ENCRYPT_FINAL:
6753 return (encrypt_final(dev, ARG, mode, rval));
6755 case CRYPTO_DECRYPT_FINAL:
6756 return (decrypt_final(dev, ARG, mode, rval));
6758 case CRYPTO_DIGEST_INIT:
6759 return (digest_init(dev, ARG, mode, rval));
6761 case CRYPTO_DIGEST:
6762 return (digest(dev, ARG, mode, rval));
6764 case CRYPTO_DIGEST_UPDATE:
6765 return (digest_update(dev, ARG, mode, rval));
6767 case CRYPTO_DIGEST_KEY:
6768 return (digest_key(dev, ARG, mode, rval));
6770 case CRYPTO_DIGEST_FINAL:
6771 return (digest_final(dev, ARG, mode, rval));
6773 case CRYPTO_SIGN_INIT:
6774 return (sign_init(dev, ARG, mode, rval));
6776 case CRYPTO_SIGN:
6777 return (sign(dev, ARG, mode, rval));
6779 case CRYPTO_SIGN_UPDATE:
6780 return (sign_update(dev, ARG, mode, rval));
6782 case CRYPTO_SIGN_FINAL:
6783 return (sign_final(dev, ARG, mode, rval));
6785 case CRYPTO_SIGN_RECOVER_INIT:
6786 return (sign_recover_init(dev, ARG, mode, rval));
6788 case CRYPTO_SIGN_RECOVER:
6789 return (sign_recover(dev, ARG, mode, rval));
6791 case CRYPTO_VERIFY_INIT:
6792 return (verify_init(dev, ARG, mode, rval));
6794 case CRYPTO_VERIFY:
6795 return (verify(dev, ARG, mode, rval));
6797 case CRYPTO_VERIFY_UPDATE:
6798 return (verify_update(dev, ARG, mode, rval));
6800 case CRYPTO_VERIFY_FINAL:
6801 return (verify_final(dev, ARG, mode, rval));
6803 case CRYPTO_VERIFY_RECOVER_INIT:
6804 return (verify_recover_init(dev, ARG, mode, rval));
6806 case CRYPTO_VERIFY_RECOVER:
6807 return (verify_recover(dev, ARG, mode, rval));
6809 case CRYPTO_MAC_INIT:
6810 return (mac_init(dev, ARG, mode, rval));
6812 case CRYPTO_MAC:
6813 return (mac(dev, ARG, mode, rval));
6815 case CRYPTO_MAC_UPDATE:
6816 return (mac_update(dev, ARG, mode, rval));
6818 case CRYPTO_MAC_FINAL:
6819 return (mac_final(dev, ARG, mode, rval));
6821 case CRYPTO_SET_PIN:
6822 return (set_pin(dev, ARG, mode, rval));
6824 case CRYPTO_LOGIN:
6825 return (login(dev, ARG, mode, rval));
6827 case CRYPTO_LOGOUT:
6828 return (logout(dev, ARG, mode, rval));
6830 case CRYPTO_SEED_RANDOM:
6831 return (seed_random(dev, ARG, mode, rval));
6833 case CRYPTO_GENERATE_RANDOM:
6834 return (generate_random(dev, ARG, mode, rval));
6836 case CRYPTO_OBJECT_CREATE:
6837 return (object_create(dev, ARG, mode, rval));
6839 case CRYPTO_OBJECT_COPY:
6840 return (object_copy(dev, ARG, mode, rval));
6842 case CRYPTO_OBJECT_DESTROY:
6843 return (object_destroy(dev, ARG, mode, rval));
6845 case CRYPTO_OBJECT_GET_ATTRIBUTE_VALUE:
6846 return (object_get_attribute_value(dev, ARG, mode, rval));
6848 case CRYPTO_OBJECT_GET_SIZE:
6849 return (object_get_size(dev, ARG, mode, rval));
6851 case CRYPTO_OBJECT_SET_ATTRIBUTE_VALUE:
6852 return (object_set_attribute_value(dev, ARG, mode, rval));
6854 case CRYPTO_OBJECT_FIND_INIT:
6855 return (object_find_init(dev, ARG, mode, rval));
6857 case CRYPTO_OBJECT_FIND_UPDATE:
6858 return (object_find_update(dev, ARG, mode, rval));
6860 case CRYPTO_OBJECT_FIND_FINAL:
6861 return (object_find_final(dev, ARG, mode, rval));
6863 case CRYPTO_GENERATE_KEY:
6864 return (object_generate_key(dev, ARG, mode, rval));
6866 case CRYPTO_GENERATE_KEY_PAIR:
6867 return (object_generate_key_pair(dev, ARG, mode, rval));
6869 case CRYPTO_WRAP_KEY:
6870 return (object_wrap_key(dev, ARG, mode, rval));
6872 case CRYPTO_UNWRAP_KEY:
6873 return (object_unwrap_key(dev, ARG, mode, rval));
6875 case CRYPTO_DERIVE_KEY:
6876 return (object_derive_key(dev, ARG, mode, rval));
6878 case CRYPTO_NOSTORE_GENERATE_KEY:
6879 return (nostore_generate_key(dev, ARG, mode, rval));
6881 case CRYPTO_NOSTORE_GENERATE_KEY_PAIR:
6882 return (nostore_generate_key_pair(dev, ARG, mode, rval));
6884 case CRYPTO_NOSTORE_DERIVE_KEY:
6885 return (nostore_derive_key(dev, ARG, mode, rval));
6887 return (EINVAL);
6891 * Check for the project.max-crypto-memory resource control.
6893 static int
6894 crypto_buffer_check(size_t need)
6896 kproject_t *kpj;
6898 if (need == 0)
6899 return (CRYPTO_SUCCESS);
6901 mutex_enter(&curproc->p_lock);
6902 kpj = curproc->p_task->tk_proj;
6903 mutex_enter(&(kpj->kpj_data.kpd_crypto_lock));
6905 if (kpj->kpj_data.kpd_crypto_mem + need >
6906 kpj->kpj_data.kpd_crypto_mem_ctl) {
6907 if (rctl_test(rc_project_crypto_mem,
6908 kpj->kpj_rctls, curproc, need, 0) & RCT_DENY) {
6909 mutex_exit(&(kpj->kpj_data.kpd_crypto_lock));
6910 mutex_exit(&curproc->p_lock);
6911 return (CRYPTO_HOST_MEMORY);
6915 kpj->kpj_data.kpd_crypto_mem += need;
6916 mutex_exit(&(kpj->kpj_data.kpd_crypto_lock));
6918 curproc->p_crypto_mem += need;
6919 mutex_exit(&curproc->p_lock);
6921 return (CRYPTO_SUCCESS);