17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5c892ebf1Skrishna * Common Development and Distribution License (the "License").
6c892ebf1Skrishna * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22d3b2efc7SAnthony Scarpino * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
25*6ea3c060SGarrett D'Amore /*
26*6ea3c060SGarrett D'Amore * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
27*6ea3c060SGarrett D'Amore */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate * This file is part of the core Kernel Cryptographic Framework.
317c478bd9Sstevel@tonic-gate * It implements the SPI functions exported to cryptographic
327c478bd9Sstevel@tonic-gate * providers.
337c478bd9Sstevel@tonic-gate */
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gate #include <sys/ksynch.h>
367c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
377c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
387c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
397c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
407c478bd9Sstevel@tonic-gate #include <sys/crypto/common.h>
417c478bd9Sstevel@tonic-gate #include <sys/crypto/impl.h>
427c478bd9Sstevel@tonic-gate #include <sys/crypto/sched_impl.h>
437c478bd9Sstevel@tonic-gate #include <sys/crypto/spi.h>
4473556491SAnthony Scarpino #include <sys/crypto/ioctladmin.h>
457c478bd9Sstevel@tonic-gate #include <sys/taskq.h>
467c478bd9Sstevel@tonic-gate #include <sys/disp.h>
477c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
487c478bd9Sstevel@tonic-gate #include <sys/policy.h>
49c41e7ccaSkrishna #include <sys/cpuvar.h>
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate * minalloc and maxalloc values to be used for taskq_create().
537c478bd9Sstevel@tonic-gate */
54c41e7ccaSkrishna int crypto_taskq_threads = CRYPTO_TASKQ_THREADS;
557c478bd9Sstevel@tonic-gate int crypto_taskq_minalloc = CYRPTO_TASKQ_MIN;
567c478bd9Sstevel@tonic-gate int crypto_taskq_maxalloc = CRYPTO_TASKQ_MAX;
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate static void remove_provider(kcf_provider_desc_t *);
597c478bd9Sstevel@tonic-gate static void process_logical_providers(crypto_provider_info_t *,
607c478bd9Sstevel@tonic-gate kcf_provider_desc_t *);
617c478bd9Sstevel@tonic-gate static int init_prov_mechs(crypto_provider_info_t *, kcf_provider_desc_t *);
627c478bd9Sstevel@tonic-gate static int kcf_prov_kstat_update(kstat_t *, int);
63fe2f7468Skrishna static void delete_kstat(kcf_provider_desc_t *);
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate static kcf_prov_stats_t kcf_stats_ks_data_template = {
667c478bd9Sstevel@tonic-gate { "kcf_ops_total", KSTAT_DATA_UINT64 },
677c478bd9Sstevel@tonic-gate { "kcf_ops_passed", KSTAT_DATA_UINT64 },
687c478bd9Sstevel@tonic-gate { "kcf_ops_failed", KSTAT_DATA_UINT64 },
697c478bd9Sstevel@tonic-gate { "kcf_ops_returned_busy", KSTAT_DATA_UINT64 }
707c478bd9Sstevel@tonic-gate };
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate #define KCF_SPI_COPY_OPS(src, dst, ops) if ((src)->ops != NULL) \
737c478bd9Sstevel@tonic-gate *((dst)->ops) = *((src)->ops);
747c478bd9Sstevel@tonic-gate
75d3b2efc7SAnthony Scarpino extern int sys_shutdown;
76d3b2efc7SAnthony Scarpino
777c478bd9Sstevel@tonic-gate /*
78034448feSmcpowers * Copy an ops vector from src to dst. Used during provider registration
79034448feSmcpowers * to copy the ops vector from the provider info structure to the
80034448feSmcpowers * provider descriptor maintained by KCF.
81034448feSmcpowers * Copying the ops vector specified by the provider is needed since the
82034448feSmcpowers * framework does not require the provider info structure to be
83034448feSmcpowers * persistent.
84034448feSmcpowers */
85034448feSmcpowers static void
copy_ops_vector_v1(crypto_ops_t * src_ops,crypto_ops_t * dst_ops)86034448feSmcpowers copy_ops_vector_v1(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
87034448feSmcpowers {
88034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_control_ops);
89034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_digest_ops);
90034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_cipher_ops);
91034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mac_ops);
92034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_sign_ops);
93034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_verify_ops);
94034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_ops);
95034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_cipher_mac_ops);
96034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_random_ops);
97034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_session_ops);
98034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_object_ops);
99034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_key_ops);
100034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_provider_ops);
101034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_ctx_ops);
102034448feSmcpowers }
103034448feSmcpowers
104034448feSmcpowers static void
copy_ops_vector_v2(crypto_ops_t * src_ops,crypto_ops_t * dst_ops)105034448feSmcpowers copy_ops_vector_v2(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
106034448feSmcpowers {
107034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mech_ops);
108034448feSmcpowers }
109034448feSmcpowers
110034448feSmcpowers static void
copy_ops_vector_v3(crypto_ops_t * src_ops,crypto_ops_t * dst_ops)111034448feSmcpowers copy_ops_vector_v3(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
112034448feSmcpowers {
113034448feSmcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_nostore_key_ops);
114034448feSmcpowers }
115034448feSmcpowers
11673556491SAnthony Scarpino static void
copy_ops_vector_v4(crypto_ops_t * src_ops,crypto_ops_t * dst_ops)11773556491SAnthony Scarpino copy_ops_vector_v4(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
11873556491SAnthony Scarpino {
11973556491SAnthony Scarpino KCF_SPI_COPY_OPS(src_ops, dst_ops, co_fips140_ops);
12073556491SAnthony Scarpino }
12173556491SAnthony Scarpino
122034448feSmcpowers /*
1237c478bd9Sstevel@tonic-gate * This routine is used to add cryptographic providers to the KEF framework.
1247c478bd9Sstevel@tonic-gate * Providers pass a crypto_provider_info structure to crypto_register_provider()
1257c478bd9Sstevel@tonic-gate * and get back a handle. The crypto_provider_info structure contains a
1267c478bd9Sstevel@tonic-gate * list of mechanisms supported by the provider and an ops vector containing
1277c478bd9Sstevel@tonic-gate * provider entry points. Hardware providers call this routine in their attach
1287c478bd9Sstevel@tonic-gate * routines. Software providers call this routine in their _init() routine.
1297c478bd9Sstevel@tonic-gate */
1307c478bd9Sstevel@tonic-gate int
crypto_register_provider(crypto_provider_info_t * info,crypto_kcf_provider_handle_t * handle)1317c478bd9Sstevel@tonic-gate crypto_register_provider(crypto_provider_info_t *info,
1327c478bd9Sstevel@tonic-gate crypto_kcf_provider_handle_t *handle)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate struct modctl *mcp;
1357c478bd9Sstevel@tonic-gate char *name;
1367c478bd9Sstevel@tonic-gate char ks_name[KSTAT_STRLEN];
1377c478bd9Sstevel@tonic-gate kcf_provider_desc_t *prov_desc = NULL;
1387c478bd9Sstevel@tonic-gate int ret = CRYPTO_ARGUMENTS_BAD;
1397c478bd9Sstevel@tonic-gate
140d3b2efc7SAnthony Scarpino if (info->pi_interface_version > CRYPTO_SPI_VERSION_4) {
141d3b2efc7SAnthony Scarpino ret = CRYPTO_VERSION_MISMATCH;
142d3b2efc7SAnthony Scarpino goto errormsg;
143d3b2efc7SAnthony Scarpino }
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate /*
1467c478bd9Sstevel@tonic-gate * Check provider type, must be software, hardware, or logical.
1477c478bd9Sstevel@tonic-gate */
1487c478bd9Sstevel@tonic-gate if (info->pi_provider_type != CRYPTO_HW_PROVIDER &&
1497c478bd9Sstevel@tonic-gate info->pi_provider_type != CRYPTO_SW_PROVIDER &&
1507c478bd9Sstevel@tonic-gate info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER)
151d3b2efc7SAnthony Scarpino goto errormsg;
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate * Allocate and initialize a new provider descriptor. We also
1557c478bd9Sstevel@tonic-gate * hold it and release it when done.
1567c478bd9Sstevel@tonic-gate */
1577c478bd9Sstevel@tonic-gate prov_desc = kcf_alloc_provider_desc(info);
1587c478bd9Sstevel@tonic-gate KCF_PROV_REFHOLD(prov_desc);
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate prov_desc->pd_prov_type = info->pi_provider_type;
1617c478bd9Sstevel@tonic-gate
1627c478bd9Sstevel@tonic-gate /* provider-private handle, opaque to KCF */
1637c478bd9Sstevel@tonic-gate prov_desc->pd_prov_handle = info->pi_provider_handle;
1647c478bd9Sstevel@tonic-gate
1657c478bd9Sstevel@tonic-gate /* copy provider description string */
1667c478bd9Sstevel@tonic-gate if (info->pi_provider_description != NULL) {
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate * pi_provider_descriptor is a string that can contain
1697c478bd9Sstevel@tonic-gate * up to CRYPTO_PROVIDER_DESCR_MAX_LEN + 1 characters
1707c478bd9Sstevel@tonic-gate * INCLUDING the terminating null character. A bcopy()
1717c478bd9Sstevel@tonic-gate * is necessary here as pd_description should not have
1727c478bd9Sstevel@tonic-gate * a null character. See comments in kcf_alloc_provider_desc()
1737c478bd9Sstevel@tonic-gate * for details on pd_description field.
1747c478bd9Sstevel@tonic-gate */
1757c478bd9Sstevel@tonic-gate bcopy(info->pi_provider_description, prov_desc->pd_description,
1767c478bd9Sstevel@tonic-gate min(strlen(info->pi_provider_description),
1777c478bd9Sstevel@tonic-gate CRYPTO_PROVIDER_DESCR_MAX_LEN));
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
1817c478bd9Sstevel@tonic-gate if (info->pi_ops_vector == NULL) {
182034448feSmcpowers goto bail;
1837c478bd9Sstevel@tonic-gate }
184894b2776Smcpowers copy_ops_vector_v1(info->pi_ops_vector,
185894b2776Smcpowers prov_desc->pd_ops_vector);
186034448feSmcpowers if (info->pi_interface_version >= CRYPTO_SPI_VERSION_2) {
187894b2776Smcpowers copy_ops_vector_v2(info->pi_ops_vector,
188894b2776Smcpowers prov_desc->pd_ops_vector);
189894b2776Smcpowers prov_desc->pd_flags = info->pi_flags;
190894b2776Smcpowers }
19173556491SAnthony Scarpino if (info->pi_interface_version >= CRYPTO_SPI_VERSION_3) {
192034448feSmcpowers copy_ops_vector_v3(info->pi_ops_vector,
193034448feSmcpowers prov_desc->pd_ops_vector);
194034448feSmcpowers }
19573556491SAnthony Scarpino if (info->pi_interface_version == CRYPTO_SPI_VERSION_4) {
19673556491SAnthony Scarpino copy_ops_vector_v4(info->pi_ops_vector,
19773556491SAnthony Scarpino prov_desc->pd_ops_vector);
19873556491SAnthony Scarpino }
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate
201034448feSmcpowers /* object_ops and nostore_key_ops are mutually exclusive */
202034448feSmcpowers if (prov_desc->pd_ops_vector->co_object_ops &&
203034448feSmcpowers prov_desc->pd_ops_vector->co_nostore_key_ops) {
204034448feSmcpowers goto bail;
205034448feSmcpowers }
2067c478bd9Sstevel@tonic-gate /*
2077c478bd9Sstevel@tonic-gate * For software providers, copy the module name and module ID.
2087c478bd9Sstevel@tonic-gate * For hardware providers, copy the driver name and instance.
2097c478bd9Sstevel@tonic-gate */
2107c478bd9Sstevel@tonic-gate switch (info->pi_provider_type) {
2117c478bd9Sstevel@tonic-gate case CRYPTO_SW_PROVIDER:
2127c478bd9Sstevel@tonic-gate if (info->pi_provider_dev.pd_sw == NULL)
2137c478bd9Sstevel@tonic-gate goto bail;
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate if ((mcp = mod_getctl(info->pi_provider_dev.pd_sw)) == NULL)
2167c478bd9Sstevel@tonic-gate goto bail;
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate prov_desc->pd_module_id = mcp->mod_id;
2197c478bd9Sstevel@tonic-gate name = mcp->mod_modname;
2207c478bd9Sstevel@tonic-gate break;
2217c478bd9Sstevel@tonic-gate
2227c478bd9Sstevel@tonic-gate case CRYPTO_HW_PROVIDER:
2237c478bd9Sstevel@tonic-gate case CRYPTO_LOGICAL_PROVIDER:
2247c478bd9Sstevel@tonic-gate if (info->pi_provider_dev.pd_hw == NULL)
2257c478bd9Sstevel@tonic-gate goto bail;
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate prov_desc->pd_instance =
2287c478bd9Sstevel@tonic-gate ddi_get_instance(info->pi_provider_dev.pd_hw);
2297c478bd9Sstevel@tonic-gate name = (char *)ddi_driver_name(info->pi_provider_dev.pd_hw);
2307c478bd9Sstevel@tonic-gate break;
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate if (name == NULL)
2337c478bd9Sstevel@tonic-gate goto bail;
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate prov_desc->pd_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
2367c478bd9Sstevel@tonic-gate (void) strcpy(prov_desc->pd_name, name);
2377c478bd9Sstevel@tonic-gate
2387c478bd9Sstevel@tonic-gate if ((prov_desc->pd_mctlp = kcf_get_modctl(info)) == NULL)
2397c478bd9Sstevel@tonic-gate goto bail;
2407c478bd9Sstevel@tonic-gate
2417c478bd9Sstevel@tonic-gate /* process the mechanisms supported by the provider */
2427c478bd9Sstevel@tonic-gate if ((ret = init_prov_mechs(info, prov_desc)) != CRYPTO_SUCCESS)
2437c478bd9Sstevel@tonic-gate goto bail;
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate /*
2467c478bd9Sstevel@tonic-gate * Add provider to providers tables, also sets the descriptor
2477c478bd9Sstevel@tonic-gate * pd_prov_id field.
2487c478bd9Sstevel@tonic-gate */
2497c478bd9Sstevel@tonic-gate if ((ret = kcf_prov_tab_add_provider(prov_desc)) != CRYPTO_SUCCESS) {
2507c478bd9Sstevel@tonic-gate undo_register_provider(prov_desc, B_FALSE);
2517c478bd9Sstevel@tonic-gate goto bail;
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate
2547c478bd9Sstevel@tonic-gate /*
2557c478bd9Sstevel@tonic-gate * We create a taskq only for a hardware provider. The global
256c41e7ccaSkrishna * software queue is used for software providers. We handle ordering
257c41e7ccaSkrishna * of multi-part requests in the taskq routine. So, it is safe to
258c41e7ccaSkrishna * have multiple threads for the taskq. We pass TASKQ_PREPOPULATE flag
259c41e7ccaSkrishna * to keep some entries cached to improve performance.
2607c478bd9Sstevel@tonic-gate */
2617c478bd9Sstevel@tonic-gate if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
262ef56a3c5SKrishna Yenduri prov_desc->pd_taskq = taskq_create("kcf_taskq",
263c41e7ccaSkrishna crypto_taskq_threads, minclsyspri,
264c41e7ccaSkrishna crypto_taskq_minalloc, crypto_taskq_maxalloc,
265c41e7ccaSkrishna TASKQ_PREPOPULATE);
2667c478bd9Sstevel@tonic-gate else
267ef56a3c5SKrishna Yenduri prov_desc->pd_taskq = NULL;
2687c478bd9Sstevel@tonic-gate
2694df55fdeSJanie Lu /* no kernel session to logical providers and no pd_flags */
2707c478bd9Sstevel@tonic-gate if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate * Open a session for session-oriented providers. This session
2737c478bd9Sstevel@tonic-gate * is used for all kernel consumers. This is fine as a provider
2747c478bd9Sstevel@tonic-gate * is required to support multiple thread access to a session.
2757c478bd9Sstevel@tonic-gate * We can do this only after the taskq has been created as we
2767c478bd9Sstevel@tonic-gate * do a kcf_submit_request() to open the session.
2777c478bd9Sstevel@tonic-gate */
2787c478bd9Sstevel@tonic-gate if (KCF_PROV_SESSION_OPS(prov_desc) != NULL) {
2797c478bd9Sstevel@tonic-gate kcf_req_params_t params;
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate KCF_WRAP_SESSION_OPS_PARAMS(¶ms,
2827c478bd9Sstevel@tonic-gate KCF_OP_SESSION_OPEN, &prov_desc->pd_sid, 0,
2837c478bd9Sstevel@tonic-gate CRYPTO_USER, NULL, 0, prov_desc);
2847c478bd9Sstevel@tonic-gate ret = kcf_submit_request(prov_desc, NULL, NULL, ¶ms,
2857c478bd9Sstevel@tonic-gate B_FALSE);
2864df55fdeSJanie Lu if (ret != CRYPTO_SUCCESS)
2874df55fdeSJanie Lu goto undo_then_bail;
2884df55fdeSJanie Lu }
2897c478bd9Sstevel@tonic-gate
2904df55fdeSJanie Lu /*
2914df55fdeSJanie Lu * Get the value for the maximum input length allowed if
2924df55fdeSJanie Lu * CRYPTO_HASH_NO_UPDATE or CRYPTO_HASH_NO_UPDATE is specified.
2934df55fdeSJanie Lu */
2944df55fdeSJanie Lu if (prov_desc->pd_flags &
2954df55fdeSJanie Lu (CRYPTO_HASH_NO_UPDATE | CRYPTO_HMAC_NO_UPDATE)) {
2964df55fdeSJanie Lu kcf_req_params_t params;
2974df55fdeSJanie Lu crypto_provider_ext_info_t ext_info;
2984df55fdeSJanie Lu
2994df55fdeSJanie Lu if (KCF_PROV_PROVMGMT_OPS(prov_desc) == NULL)
3004df55fdeSJanie Lu goto undo_then_bail;
3014df55fdeSJanie Lu
3024df55fdeSJanie Lu bzero(&ext_info, sizeof (ext_info));
3034df55fdeSJanie Lu KCF_WRAP_PROVMGMT_OPS_PARAMS(¶ms,
3044df55fdeSJanie Lu KCF_OP_MGMT_EXTINFO,
3054df55fdeSJanie Lu 0, NULL, 0, NULL, 0, NULL, &ext_info, prov_desc);
3064df55fdeSJanie Lu ret = kcf_submit_request(prov_desc, NULL, NULL,
3074df55fdeSJanie Lu ¶ms, B_FALSE);
3084df55fdeSJanie Lu if (ret != CRYPTO_SUCCESS)
3094df55fdeSJanie Lu goto undo_then_bail;
3104df55fdeSJanie Lu
3114df55fdeSJanie Lu if (prov_desc->pd_flags & CRYPTO_HASH_NO_UPDATE) {
3124df55fdeSJanie Lu prov_desc->pd_hash_limit =
3134df55fdeSJanie Lu ext_info.ei_hash_max_input_len;
3144df55fdeSJanie Lu }
3154df55fdeSJanie Lu if (prov_desc->pd_flags & CRYPTO_HMAC_NO_UPDATE) {
3164df55fdeSJanie Lu prov_desc->pd_hmac_limit =
3174df55fdeSJanie Lu ext_info.ei_hmac_max_input_len;
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
3237c478bd9Sstevel@tonic-gate /*
3247c478bd9Sstevel@tonic-gate * Create the kstat for this provider. There is a kstat
3257c478bd9Sstevel@tonic-gate * installed for each successfully registered provider.
3267c478bd9Sstevel@tonic-gate * This kstat is deleted, when the provider unregisters.
3277c478bd9Sstevel@tonic-gate */
3287c478bd9Sstevel@tonic-gate if (prov_desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
3297c478bd9Sstevel@tonic-gate (void) snprintf(ks_name, KSTAT_STRLEN, "%s_%s",
3307c478bd9Sstevel@tonic-gate prov_desc->pd_name, "provider_stats");
3317c478bd9Sstevel@tonic-gate } else {
3327c478bd9Sstevel@tonic-gate (void) snprintf(ks_name, KSTAT_STRLEN, "%s_%d_%u_%s",
3337c478bd9Sstevel@tonic-gate prov_desc->pd_name, prov_desc->pd_instance,
3347c478bd9Sstevel@tonic-gate prov_desc->pd_prov_id, "provider_stats");
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate prov_desc->pd_kstat = kstat_create("kcf", 0, ks_name, "crypto",
3387c478bd9Sstevel@tonic-gate KSTAT_TYPE_NAMED, sizeof (kcf_prov_stats_t) /
3397c478bd9Sstevel@tonic-gate sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
3407c478bd9Sstevel@tonic-gate
3417c478bd9Sstevel@tonic-gate if (prov_desc->pd_kstat != NULL) {
3427c478bd9Sstevel@tonic-gate bcopy(&kcf_stats_ks_data_template,
3437c478bd9Sstevel@tonic-gate &prov_desc->pd_ks_data,
3447c478bd9Sstevel@tonic-gate sizeof (kcf_stats_ks_data_template));
3457c478bd9Sstevel@tonic-gate prov_desc->pd_kstat->ks_data = &prov_desc->pd_ks_data;
3467c478bd9Sstevel@tonic-gate KCF_PROV_REFHOLD(prov_desc);
3477c478bd9Sstevel@tonic-gate prov_desc->pd_kstat->ks_private = prov_desc;
3487c478bd9Sstevel@tonic-gate prov_desc->pd_kstat->ks_update = kcf_prov_kstat_update;
3497c478bd9Sstevel@tonic-gate kstat_install(prov_desc->pd_kstat);
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
3547c478bd9Sstevel@tonic-gate process_logical_providers(info, prov_desc);
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate mutex_enter(&prov_desc->pd_lock);
357fe2f7468Skrishna prov_desc->pd_state = KCF_PROV_READY;
3587c478bd9Sstevel@tonic-gate mutex_exit(&prov_desc->pd_lock);
359fe2f7468Skrishna kcf_do_notify(prov_desc, B_TRUE);
3607c478bd9Sstevel@tonic-gate
36173556491SAnthony Scarpino exit:
3627c478bd9Sstevel@tonic-gate *handle = prov_desc->pd_kcf_prov_handle;
3634df55fdeSJanie Lu KCF_PROV_REFRELE(prov_desc);
3644df55fdeSJanie Lu return (CRYPTO_SUCCESS);
3657c478bd9Sstevel@tonic-gate
3664df55fdeSJanie Lu undo_then_bail:
3674df55fdeSJanie Lu undo_register_provider(prov_desc, B_TRUE);
3684df55fdeSJanie Lu ret = CRYPTO_FAILED;
3697c478bd9Sstevel@tonic-gate bail:
3707c478bd9Sstevel@tonic-gate KCF_PROV_REFRELE(prov_desc);
371d3b2efc7SAnthony Scarpino
372d3b2efc7SAnthony Scarpino errormsg:
373d3b2efc7SAnthony Scarpino if (ret != CRYPTO_SUCCESS && sys_shutdown == 0) {
374d3b2efc7SAnthony Scarpino switch (ret) {
375d3b2efc7SAnthony Scarpino case CRYPTO_FAILED:
376d3b2efc7SAnthony Scarpino cmn_err(CE_WARN, "%s failed when registering with the "
377d3b2efc7SAnthony Scarpino "Cryptographic Framework.",
378d3b2efc7SAnthony Scarpino info->pi_provider_description);
379d3b2efc7SAnthony Scarpino break;
380d3b2efc7SAnthony Scarpino
381d3b2efc7SAnthony Scarpino case CRYPTO_MODVERIFICATION_FAILED:
382d3b2efc7SAnthony Scarpino cmn_err(CE_WARN, "%s failed module verification when "
383d3b2efc7SAnthony Scarpino "registering with the Cryptographic Framework.",
384d3b2efc7SAnthony Scarpino info->pi_provider_description);
385d3b2efc7SAnthony Scarpino break;
386d3b2efc7SAnthony Scarpino
387d3b2efc7SAnthony Scarpino case CRYPTO_ARGUMENTS_BAD:
388d3b2efc7SAnthony Scarpino cmn_err(CE_WARN, "%s provided bad arguments and was "
389d3b2efc7SAnthony Scarpino "not registered with the Cryptographic Framework.",
390d3b2efc7SAnthony Scarpino info->pi_provider_description);
391d3b2efc7SAnthony Scarpino break;
392d3b2efc7SAnthony Scarpino
393d3b2efc7SAnthony Scarpino case CRYPTO_VERSION_MISMATCH:
394d3b2efc7SAnthony Scarpino cmn_err(CE_WARN, "%s was not registered with the "
395d3b2efc7SAnthony Scarpino "Cryptographic Framework as there is a SPI version "
396d3b2efc7SAnthony Scarpino "mismatch (%d) error.",
397d3b2efc7SAnthony Scarpino info->pi_provider_description,
398d3b2efc7SAnthony Scarpino info->pi_interface_version);
399d3b2efc7SAnthony Scarpino break;
400d3b2efc7SAnthony Scarpino
401d3b2efc7SAnthony Scarpino case CRYPTO_FIPS140_ERROR:
402d3b2efc7SAnthony Scarpino cmn_err(CE_WARN, "%s was not registered with the "
403d3b2efc7SAnthony Scarpino "Cryptographic Framework as there was a FIPS 140 "
404d3b2efc7SAnthony Scarpino "validation error.", info->pi_provider_description);
405d3b2efc7SAnthony Scarpino break;
406d3b2efc7SAnthony Scarpino
407d3b2efc7SAnthony Scarpino default:
408d3b2efc7SAnthony Scarpino cmn_err(CE_WARN, "%s did not register with the "
409d3b2efc7SAnthony Scarpino "Cryptographic Framework. (0x%x)",
410d3b2efc7SAnthony Scarpino info->pi_provider_description, ret);
411d3b2efc7SAnthony Scarpino };
412d3b2efc7SAnthony Scarpino }
413d3b2efc7SAnthony Scarpino
4147c478bd9Sstevel@tonic-gate return (ret);
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate
417ef56a3c5SKrishna Yenduri /* Return the number of holds on a provider. */
418ef56a3c5SKrishna Yenduri int
kcf_get_refcnt(kcf_provider_desc_t * pd,boolean_t do_lock)419ef56a3c5SKrishna Yenduri kcf_get_refcnt(kcf_provider_desc_t *pd, boolean_t do_lock)
420ef56a3c5SKrishna Yenduri {
421ef56a3c5SKrishna Yenduri int i;
422ef56a3c5SKrishna Yenduri int refcnt = 0;
423ef56a3c5SKrishna Yenduri
424ef56a3c5SKrishna Yenduri if (do_lock)
425ef56a3c5SKrishna Yenduri for (i = 0; i < pd->pd_nbins; i++)
426ef56a3c5SKrishna Yenduri mutex_enter(&(pd->pd_percpu_bins[i].kp_lock));
427ef56a3c5SKrishna Yenduri
428ef56a3c5SKrishna Yenduri for (i = 0; i < pd->pd_nbins; i++)
429ef56a3c5SKrishna Yenduri refcnt += pd->pd_percpu_bins[i].kp_holdcnt;
430ef56a3c5SKrishna Yenduri
431ef56a3c5SKrishna Yenduri if (do_lock)
432ef56a3c5SKrishna Yenduri for (i = 0; i < pd->pd_nbins; i++)
433ef56a3c5SKrishna Yenduri mutex_exit(&(pd->pd_percpu_bins[i].kp_lock));
434ef56a3c5SKrishna Yenduri
435ef56a3c5SKrishna Yenduri return (refcnt);
436ef56a3c5SKrishna Yenduri }
437ef56a3c5SKrishna Yenduri
4387c478bd9Sstevel@tonic-gate /*
4397c478bd9Sstevel@tonic-gate * This routine is used to notify the framework when a provider is being
4407c478bd9Sstevel@tonic-gate * removed. Hardware providers call this routine in their detach routines.
4417c478bd9Sstevel@tonic-gate * Software providers call this routine in their _fini() routine.
4427c478bd9Sstevel@tonic-gate */
4437c478bd9Sstevel@tonic-gate int
crypto_unregister_provider(crypto_kcf_provider_handle_t handle)4447c478bd9Sstevel@tonic-gate crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate uint_t mech_idx;
4477c478bd9Sstevel@tonic-gate kcf_provider_desc_t *desc;
4487c478bd9Sstevel@tonic-gate kcf_prov_state_t saved_state;
449d3b2efc7SAnthony Scarpino int ret = CRYPTO_SUCCESS;
4507c478bd9Sstevel@tonic-gate
4517c478bd9Sstevel@tonic-gate /* lookup provider descriptor */
452d3b2efc7SAnthony Scarpino if ((desc = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) ==
453d3b2efc7SAnthony Scarpino NULL) {
454d3b2efc7SAnthony Scarpino ret = CRYPTO_UNKNOWN_PROVIDER;
455d3b2efc7SAnthony Scarpino goto errormsg;
456d3b2efc7SAnthony Scarpino }
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate mutex_enter(&desc->pd_lock);
4597c478bd9Sstevel@tonic-gate /*
4607c478bd9Sstevel@tonic-gate * Check if any other thread is disabling or removing
4617c478bd9Sstevel@tonic-gate * this provider. We return if this is the case.
4627c478bd9Sstevel@tonic-gate */
4637c478bd9Sstevel@tonic-gate if (desc->pd_state >= KCF_PROV_DISABLED) {
4647c478bd9Sstevel@tonic-gate mutex_exit(&desc->pd_lock);
4657c478bd9Sstevel@tonic-gate /* Release reference held by kcf_prov_tab_lookup(). */
4667c478bd9Sstevel@tonic-gate KCF_PROV_REFRELE(desc);
467d3b2efc7SAnthony Scarpino ret = CRYPTO_BUSY;
468d3b2efc7SAnthony Scarpino goto errormsg;
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate saved_state = desc->pd_state;
472ef56a3c5SKrishna Yenduri desc->pd_state = KCF_PROV_UNREGISTERING;
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate if (saved_state == KCF_PROV_BUSY) {
4757c478bd9Sstevel@tonic-gate /*
47668468c97Skrishna * The per-provider taskq threads may be waiting. We
47768468c97Skrishna * signal them so that they can start failing requests.
4787c478bd9Sstevel@tonic-gate */
47968468c97Skrishna cv_broadcast(&desc->pd_resume_cv);
4807c478bd9Sstevel@tonic-gate }
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate mutex_exit(&desc->pd_lock);
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate if (desc->pd_prov_type != CRYPTO_SW_PROVIDER) {
4857c478bd9Sstevel@tonic-gate remove_provider(desc);
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate if (desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
4897c478bd9Sstevel@tonic-gate /* remove the provider from the mechanisms tables */
4907c478bd9Sstevel@tonic-gate for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
4917c478bd9Sstevel@tonic-gate mech_idx++) {
4927c478bd9Sstevel@tonic-gate kcf_remove_mech_provider(
4937c478bd9Sstevel@tonic-gate desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate /* remove provider from providers table */
4987c478bd9Sstevel@tonic-gate if (kcf_prov_tab_rem_provider((crypto_provider_id_t)handle) !=
4997c478bd9Sstevel@tonic-gate CRYPTO_SUCCESS) {
5007c478bd9Sstevel@tonic-gate /* Release reference held by kcf_prov_tab_lookup(). */
5017c478bd9Sstevel@tonic-gate KCF_PROV_REFRELE(desc);
502d3b2efc7SAnthony Scarpino ret = CRYPTO_UNKNOWN_PROVIDER;
503d3b2efc7SAnthony Scarpino goto errormsg;
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate
506fe2f7468Skrishna delete_kstat(desc);
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
5097c478bd9Sstevel@tonic-gate /*
510ef56a3c5SKrishna Yenduri * Wait till the existing requests with the provider complete
511ef56a3c5SKrishna Yenduri * and all the holds are released. All the holds on a software
512ef56a3c5SKrishna Yenduri * provider are from kernel clients and the hold time
513ef56a3c5SKrishna Yenduri * is expected to be short. So, we won't be stuck here forever.
5147c478bd9Sstevel@tonic-gate */
515ef56a3c5SKrishna Yenduri while (kcf_get_refcnt(desc, B_TRUE) > 1) {
516ef56a3c5SKrishna Yenduri /* wait 1 second and try again. */
517ef56a3c5SKrishna Yenduri delay(1 * drv_usectohz(1000000));
518ef56a3c5SKrishna Yenduri }
5197c478bd9Sstevel@tonic-gate } else {
520ef56a3c5SKrishna Yenduri int i;
521ef56a3c5SKrishna Yenduri kcf_prov_cpu_t *mp;
522ef56a3c5SKrishna Yenduri
5237c478bd9Sstevel@tonic-gate /*
5247c478bd9Sstevel@tonic-gate * Wait until requests that have been sent to the provider
5257c478bd9Sstevel@tonic-gate * complete.
5267c478bd9Sstevel@tonic-gate */
527ef56a3c5SKrishna Yenduri for (i = 0; i < desc->pd_nbins; i++) {
528ef56a3c5SKrishna Yenduri mp = &(desc->pd_percpu_bins[i]);
529ef56a3c5SKrishna Yenduri
530ef56a3c5SKrishna Yenduri mutex_enter(&mp->kp_lock);
531ef56a3c5SKrishna Yenduri while (mp->kp_jobcnt > 0) {
532ef56a3c5SKrishna Yenduri cv_wait(&mp->kp_cv, &mp->kp_lock);
5337c478bd9Sstevel@tonic-gate }
534ef56a3c5SKrishna Yenduri mutex_exit(&mp->kp_lock);
535ef56a3c5SKrishna Yenduri }
536ef56a3c5SKrishna Yenduri }
537ef56a3c5SKrishna Yenduri
538ef56a3c5SKrishna Yenduri mutex_enter(&desc->pd_lock);
539ef56a3c5SKrishna Yenduri desc->pd_state = KCF_PROV_UNREGISTERED;
540ef56a3c5SKrishna Yenduri mutex_exit(&desc->pd_lock);
5417c478bd9Sstevel@tonic-gate
542fe2f7468Skrishna kcf_do_notify(desc, B_FALSE);
543c892ebf1Skrishna
5447623016fSKrishna Yenduri mutex_enter(&prov_tab_mutex);
545ef56a3c5SKrishna Yenduri /* Release reference held by kcf_prov_tab_lookup(). */
546ef56a3c5SKrishna Yenduri KCF_PROV_REFRELE(desc);
547ef56a3c5SKrishna Yenduri
548ef56a3c5SKrishna Yenduri if (kcf_get_refcnt(desc, B_TRUE) == 0) {
5497623016fSKrishna Yenduri /* kcf_free_provider_desc drops prov_tab_mutex */
5507c478bd9Sstevel@tonic-gate kcf_free_provider_desc(desc);
5517c478bd9Sstevel@tonic-gate } else {
552ef56a3c5SKrishna Yenduri ASSERT(desc->pd_prov_type != CRYPTO_SW_PROVIDER);
553ef56a3c5SKrishna Yenduri /*
554ef56a3c5SKrishna Yenduri * We could avoid this if /dev/crypto can proactively
555ef56a3c5SKrishna Yenduri * remove any holds on us from a dormant PKCS #11 app.
5567623016fSKrishna Yenduri * For now, we check the provider table for
5577623016fSKrishna Yenduri * KCF_PROV_UNREGISTERED entries when a provider is
5587623016fSKrishna Yenduri * added to the table or when a provider is removed from it
5597623016fSKrishna Yenduri * and free them when refcnt reaches zero.
560ef56a3c5SKrishna Yenduri */
561ef56a3c5SKrishna Yenduri kcf_need_provtab_walk = B_TRUE;
562ef56a3c5SKrishna Yenduri mutex_exit(&prov_tab_mutex);
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate
565d3b2efc7SAnthony Scarpino errormsg:
566d3b2efc7SAnthony Scarpino if (ret != CRYPTO_SUCCESS && sys_shutdown == 0) {
567d3b2efc7SAnthony Scarpino switch (ret) {
568d3b2efc7SAnthony Scarpino case CRYPTO_UNKNOWN_PROVIDER:
569d3b2efc7SAnthony Scarpino cmn_err(CE_WARN, "Unknown provider \"%s\" was "
570d3b2efc7SAnthony Scarpino "requested to unregister from the cryptographic "
571d3b2efc7SAnthony Scarpino "framework.", desc->pd_description);
572d3b2efc7SAnthony Scarpino break;
573d3b2efc7SAnthony Scarpino
574d3b2efc7SAnthony Scarpino case CRYPTO_BUSY:
575d3b2efc7SAnthony Scarpino cmn_err(CE_WARN, "%s could not be unregistered from "
576d3b2efc7SAnthony Scarpino "the Cryptographic Framework as it is busy.",
577d3b2efc7SAnthony Scarpino desc->pd_description);
578d3b2efc7SAnthony Scarpino break;
579d3b2efc7SAnthony Scarpino
580d3b2efc7SAnthony Scarpino default:
581d3b2efc7SAnthony Scarpino cmn_err(CE_WARN, "%s did not unregister with the "
582d3b2efc7SAnthony Scarpino "Cryptographic Framework. (0x%x)",
583d3b2efc7SAnthony Scarpino desc->pd_description, ret);
584d3b2efc7SAnthony Scarpino };
585d3b2efc7SAnthony Scarpino }
586d3b2efc7SAnthony Scarpino
587d3b2efc7SAnthony Scarpino return (ret);
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate
5907c478bd9Sstevel@tonic-gate /*
5917c478bd9Sstevel@tonic-gate * This routine is used to notify the framework that the state of
5927c478bd9Sstevel@tonic-gate * a cryptographic provider has changed. Valid state codes are:
5937c478bd9Sstevel@tonic-gate *
5947c478bd9Sstevel@tonic-gate * CRYPTO_PROVIDER_READY
5957c478bd9Sstevel@tonic-gate * The provider indicates that it can process more requests. A provider
5967c478bd9Sstevel@tonic-gate * will notify with this event if it previously has notified us with a
5977c478bd9Sstevel@tonic-gate * CRYPTO_PROVIDER_BUSY.
5987c478bd9Sstevel@tonic-gate *
5997c478bd9Sstevel@tonic-gate * CRYPTO_PROVIDER_BUSY
6007c478bd9Sstevel@tonic-gate * The provider can not take more requests.
6017c478bd9Sstevel@tonic-gate *
6027c478bd9Sstevel@tonic-gate * CRYPTO_PROVIDER_FAILED
6037c478bd9Sstevel@tonic-gate * The provider encountered an internal error. The framework will not
6047c478bd9Sstevel@tonic-gate * be sending any more requests to the provider. The provider may notify
6057c478bd9Sstevel@tonic-gate * with a CRYPTO_PROVIDER_READY, if it is able to recover from the error.
6067c478bd9Sstevel@tonic-gate *
6077c478bd9Sstevel@tonic-gate * This routine can be called from user or interrupt context.
6087c478bd9Sstevel@tonic-gate */
6097c478bd9Sstevel@tonic-gate void
crypto_provider_notification(crypto_kcf_provider_handle_t handle,uint_t state)6107c478bd9Sstevel@tonic-gate crypto_provider_notification(crypto_kcf_provider_handle_t handle, uint_t state)
6117c478bd9Sstevel@tonic-gate {
6127c478bd9Sstevel@tonic-gate kcf_provider_desc_t *pd;
6137c478bd9Sstevel@tonic-gate
6147c478bd9Sstevel@tonic-gate /* lookup the provider from the given handle */
6157c478bd9Sstevel@tonic-gate if ((pd = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
6167c478bd9Sstevel@tonic-gate return;
6177c478bd9Sstevel@tonic-gate
6187c478bd9Sstevel@tonic-gate mutex_enter(&pd->pd_lock);
6197c478bd9Sstevel@tonic-gate
620fe2f7468Skrishna if (pd->pd_state <= KCF_PROV_VERIFICATION_FAILED)
621fe2f7468Skrishna goto out;
622fe2f7468Skrishna
6237c478bd9Sstevel@tonic-gate if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
6247c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_provider_notification: "
6257c478bd9Sstevel@tonic-gate "logical provider (%x) ignored\n", handle);
6267c478bd9Sstevel@tonic-gate goto out;
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate switch (state) {
6297c478bd9Sstevel@tonic-gate case CRYPTO_PROVIDER_READY:
6307c478bd9Sstevel@tonic-gate switch (pd->pd_state) {
6317c478bd9Sstevel@tonic-gate case KCF_PROV_BUSY:
6327c478bd9Sstevel@tonic-gate pd->pd_state = KCF_PROV_READY;
6337c478bd9Sstevel@tonic-gate /*
63468468c97Skrishna * Signal the per-provider taskq threads that they
63568468c97Skrishna * can start submitting requests.
6367c478bd9Sstevel@tonic-gate */
63768468c97Skrishna cv_broadcast(&pd->pd_resume_cv);
6387c478bd9Sstevel@tonic-gate break;
6397c478bd9Sstevel@tonic-gate
6407c478bd9Sstevel@tonic-gate case KCF_PROV_FAILED:
6417c478bd9Sstevel@tonic-gate /*
6427c478bd9Sstevel@tonic-gate * The provider recovered from the error. Let us
6437c478bd9Sstevel@tonic-gate * use it now.
6447c478bd9Sstevel@tonic-gate */
6457c478bd9Sstevel@tonic-gate pd->pd_state = KCF_PROV_READY;
6467c478bd9Sstevel@tonic-gate break;
6477c478bd9Sstevel@tonic-gate }
6487c478bd9Sstevel@tonic-gate break;
6497c478bd9Sstevel@tonic-gate
6507c478bd9Sstevel@tonic-gate case CRYPTO_PROVIDER_BUSY:
6517c478bd9Sstevel@tonic-gate switch (pd->pd_state) {
6527c478bd9Sstevel@tonic-gate case KCF_PROV_READY:
6537c478bd9Sstevel@tonic-gate pd->pd_state = KCF_PROV_BUSY;
6547c478bd9Sstevel@tonic-gate break;
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate break;
6577c478bd9Sstevel@tonic-gate
6587c478bd9Sstevel@tonic-gate case CRYPTO_PROVIDER_FAILED:
6597c478bd9Sstevel@tonic-gate /*
6607c478bd9Sstevel@tonic-gate * We note the failure and return. The per-provider taskq
66168468c97Skrishna * threads check this flag and start failing the
6627c478bd9Sstevel@tonic-gate * requests, if it is set. See process_req_hwp() for details.
6637c478bd9Sstevel@tonic-gate */
6647c478bd9Sstevel@tonic-gate switch (pd->pd_state) {
6657c478bd9Sstevel@tonic-gate case KCF_PROV_READY:
6667c478bd9Sstevel@tonic-gate pd->pd_state = KCF_PROV_FAILED;
6677c478bd9Sstevel@tonic-gate break;
6687c478bd9Sstevel@tonic-gate
6697c478bd9Sstevel@tonic-gate case KCF_PROV_BUSY:
6707c478bd9Sstevel@tonic-gate pd->pd_state = KCF_PROV_FAILED;
6717c478bd9Sstevel@tonic-gate /*
67268468c97Skrishna * The per-provider taskq threads may be waiting. We
67368468c97Skrishna * signal them so that they can start failing requests.
6747c478bd9Sstevel@tonic-gate */
67568468c97Skrishna cv_broadcast(&pd->pd_resume_cv);
6767c478bd9Sstevel@tonic-gate break;
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate break;
6797c478bd9Sstevel@tonic-gate }
6807c478bd9Sstevel@tonic-gate out:
6817c478bd9Sstevel@tonic-gate mutex_exit(&pd->pd_lock);
6827c478bd9Sstevel@tonic-gate KCF_PROV_REFRELE(pd);
6837c478bd9Sstevel@tonic-gate }
6847c478bd9Sstevel@tonic-gate
6857c478bd9Sstevel@tonic-gate /*
6867c478bd9Sstevel@tonic-gate * This routine is used to notify the framework the result of
6877c478bd9Sstevel@tonic-gate * an asynchronous request handled by a provider. Valid error
6887c478bd9Sstevel@tonic-gate * codes are the same as the CRYPTO_* errors defined in common.h.
6897c478bd9Sstevel@tonic-gate *
6907c478bd9Sstevel@tonic-gate * This routine can be called from user or interrupt context.
6917c478bd9Sstevel@tonic-gate */
6927c478bd9Sstevel@tonic-gate void
crypto_op_notification(crypto_req_handle_t handle,int error)6937c478bd9Sstevel@tonic-gate crypto_op_notification(crypto_req_handle_t handle, int error)
6947c478bd9Sstevel@tonic-gate {
6957c478bd9Sstevel@tonic-gate kcf_call_type_t ctype;
6967c478bd9Sstevel@tonic-gate
697c1591d22SKrishna Yenduri if (handle == NULL)
698c1591d22SKrishna Yenduri return;
699c1591d22SKrishna Yenduri
7007c478bd9Sstevel@tonic-gate if ((ctype = GET_REQ_TYPE(handle)) == CRYPTO_SYNCH) {
7017c478bd9Sstevel@tonic-gate kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)handle;
7027c478bd9Sstevel@tonic-gate
703ef56a3c5SKrishna Yenduri KCF_PROV_JOB_RELE_STAT(sreq->sn_mp, (error != CRYPTO_SUCCESS));
7047c478bd9Sstevel@tonic-gate kcf_sop_done(sreq, error);
7057c478bd9Sstevel@tonic-gate } else {
7067c478bd9Sstevel@tonic-gate kcf_areq_node_t *areq = (kcf_areq_node_t *)handle;
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate ASSERT(ctype == CRYPTO_ASYNCH);
709ef56a3c5SKrishna Yenduri KCF_PROV_JOB_RELE_STAT(areq->an_mp, (error != CRYPTO_SUCCESS));
7107c478bd9Sstevel@tonic-gate kcf_aop_done(areq, error);
7117c478bd9Sstevel@tonic-gate }
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate /*
7157c478bd9Sstevel@tonic-gate * This routine is used by software providers to determine
7167c478bd9Sstevel@tonic-gate * whether to use KM_SLEEP or KM_NOSLEEP during memory allocation.
7177c478bd9Sstevel@tonic-gate * Note that hardware providers can always use KM_SLEEP. So,
7187c478bd9Sstevel@tonic-gate * they do not need to call this routine.
7197c478bd9Sstevel@tonic-gate *
7207c478bd9Sstevel@tonic-gate * This routine can be called from user or interrupt context.
7217c478bd9Sstevel@tonic-gate */
7227c478bd9Sstevel@tonic-gate int
crypto_kmflag(crypto_req_handle_t handle)7237c478bd9Sstevel@tonic-gate crypto_kmflag(crypto_req_handle_t handle)
7247c478bd9Sstevel@tonic-gate {
7257c478bd9Sstevel@tonic-gate return (REQHNDL2_KMFLAG(handle));
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate
7287c478bd9Sstevel@tonic-gate /*
7297c478bd9Sstevel@tonic-gate * Process the mechanism info structures specified by the provider
7307c478bd9Sstevel@tonic-gate * during registration. A NULL crypto_provider_info_t indicates
7317c478bd9Sstevel@tonic-gate * an already initialized provider descriptor.
7327c478bd9Sstevel@tonic-gate *
7337c478bd9Sstevel@tonic-gate * Mechanisms are not added to the kernel's mechanism table if the
7347c478bd9Sstevel@tonic-gate * provider is a logical provider.
7357c478bd9Sstevel@tonic-gate *
7367c478bd9Sstevel@tonic-gate * Returns CRYPTO_SUCCESS on success, CRYPTO_ARGUMENTS if one
7377c478bd9Sstevel@tonic-gate * of the specified mechanisms was malformed, or CRYPTO_HOST_MEMORY
7387c478bd9Sstevel@tonic-gate * if the table of mechanisms is full.
7397c478bd9Sstevel@tonic-gate */
7407c478bd9Sstevel@tonic-gate static int
init_prov_mechs(crypto_provider_info_t * info,kcf_provider_desc_t * desc)7417c478bd9Sstevel@tonic-gate init_prov_mechs(crypto_provider_info_t *info, kcf_provider_desc_t *desc)
7427c478bd9Sstevel@tonic-gate {
7437c478bd9Sstevel@tonic-gate uint_t mech_idx;
7447c478bd9Sstevel@tonic-gate uint_t cleanup_idx;
7457c478bd9Sstevel@tonic-gate int err = CRYPTO_SUCCESS;
7467c478bd9Sstevel@tonic-gate kcf_prov_mech_desc_t *pmd;
7477c478bd9Sstevel@tonic-gate int desc_use_count = 0;
7487c478bd9Sstevel@tonic-gate int mcount = desc->pd_mech_list_count;
7497c478bd9Sstevel@tonic-gate
7507c478bd9Sstevel@tonic-gate if (desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
7517c478bd9Sstevel@tonic-gate if (info != NULL) {
7527c478bd9Sstevel@tonic-gate ASSERT(info->pi_mechanisms != NULL);
7537c478bd9Sstevel@tonic-gate bcopy(info->pi_mechanisms, desc->pd_mechanisms,
7547c478bd9Sstevel@tonic-gate sizeof (crypto_mech_info_t) * mcount);
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS);
7577c478bd9Sstevel@tonic-gate }
7587c478bd9Sstevel@tonic-gate
7597c478bd9Sstevel@tonic-gate /*
7607c478bd9Sstevel@tonic-gate * Copy the mechanism list from the provider info to the provider
7617c478bd9Sstevel@tonic-gate * descriptor. desc->pd_mechanisms has an extra crypto_mech_info_t
7627c478bd9Sstevel@tonic-gate * element if the provider has random_ops since we keep an internal
7637c478bd9Sstevel@tonic-gate * mechanism, SUN_RANDOM, in this case.
7647c478bd9Sstevel@tonic-gate */
7657c478bd9Sstevel@tonic-gate if (info != NULL) {
766894b2776Smcpowers if (info->pi_ops_vector->co_random_ops != NULL) {
7677c478bd9Sstevel@tonic-gate crypto_mech_info_t *rand_mi;
7687c478bd9Sstevel@tonic-gate
7697c478bd9Sstevel@tonic-gate /*
7707c478bd9Sstevel@tonic-gate * Need the following check as it is possible to have
7717c478bd9Sstevel@tonic-gate * a provider that implements just random_ops and has
7727c478bd9Sstevel@tonic-gate * pi_mechanisms == NULL.
7737c478bd9Sstevel@tonic-gate */
7747c478bd9Sstevel@tonic-gate if (info->pi_mechanisms != NULL) {
7757c478bd9Sstevel@tonic-gate bcopy(info->pi_mechanisms, desc->pd_mechanisms,
7767c478bd9Sstevel@tonic-gate sizeof (crypto_mech_info_t) * (mcount - 1));
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate rand_mi = &desc->pd_mechanisms[mcount - 1];
7797c478bd9Sstevel@tonic-gate
7807c478bd9Sstevel@tonic-gate bzero(rand_mi, sizeof (crypto_mech_info_t));
7817c478bd9Sstevel@tonic-gate (void) strncpy(rand_mi->cm_mech_name, SUN_RANDOM,
7827c478bd9Sstevel@tonic-gate CRYPTO_MAX_MECH_NAME);
7837c478bd9Sstevel@tonic-gate rand_mi->cm_func_group_mask = CRYPTO_FG_RANDOM;
7847c478bd9Sstevel@tonic-gate } else {
7857c478bd9Sstevel@tonic-gate ASSERT(info->pi_mechanisms != NULL);
7867c478bd9Sstevel@tonic-gate bcopy(info->pi_mechanisms, desc->pd_mechanisms,
7877c478bd9Sstevel@tonic-gate sizeof (crypto_mech_info_t) * mcount);
7887c478bd9Sstevel@tonic-gate }
7897c478bd9Sstevel@tonic-gate }
7907c478bd9Sstevel@tonic-gate
7917c478bd9Sstevel@tonic-gate /*
7927c478bd9Sstevel@tonic-gate * For each mechanism support by the provider, add the provider
7937c478bd9Sstevel@tonic-gate * to the corresponding KCF mechanism mech_entry chain.
7947c478bd9Sstevel@tonic-gate */
7957c478bd9Sstevel@tonic-gate for (mech_idx = 0; mech_idx < desc->pd_mech_list_count; mech_idx++) {
7967c478bd9Sstevel@tonic-gate crypto_mech_info_t *mi = &desc->pd_mechanisms[mech_idx];
7977c478bd9Sstevel@tonic-gate
7986a1073f8Skrishna if ((mi->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BITS) &&
7996a1073f8Skrishna (mi->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BYTES)) {
8007c478bd9Sstevel@tonic-gate err = CRYPTO_ARGUMENTS_BAD;
8017c478bd9Sstevel@tonic-gate break;
8027c478bd9Sstevel@tonic-gate }
8037c478bd9Sstevel@tonic-gate
804c1591d22SKrishna Yenduri if ((err = kcf_add_mech_provider(mech_idx, desc, &pmd)) !=
805c1591d22SKrishna Yenduri KCF_SUCCESS)
8067c478bd9Sstevel@tonic-gate break;
8077c478bd9Sstevel@tonic-gate
8087c478bd9Sstevel@tonic-gate if (pmd == NULL)
8097c478bd9Sstevel@tonic-gate continue;
8107c478bd9Sstevel@tonic-gate
8117c478bd9Sstevel@tonic-gate /* The provider will be used for this mechanism */
8127c478bd9Sstevel@tonic-gate desc_use_count++;
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate
8157c478bd9Sstevel@tonic-gate /*
8167ce878deSmcpowers * Don't allow multiple software providers with disabled mechanisms
8177ce878deSmcpowers * to register. Subsequent enabling of mechanisms will result in
8187ce878deSmcpowers * an unsupported configuration, i.e. multiple software providers
8197ce878deSmcpowers * per mechanism.
8207c478bd9Sstevel@tonic-gate */
8217ce878deSmcpowers if (desc_use_count == 0 && desc->pd_prov_type == CRYPTO_SW_PROVIDER)
8227c478bd9Sstevel@tonic-gate return (CRYPTO_ARGUMENTS_BAD);
8237c478bd9Sstevel@tonic-gate
8247c478bd9Sstevel@tonic-gate if (err == KCF_SUCCESS)
8257c478bd9Sstevel@tonic-gate return (CRYPTO_SUCCESS);
8267c478bd9Sstevel@tonic-gate
8277c478bd9Sstevel@tonic-gate /*
8287c478bd9Sstevel@tonic-gate * An error occurred while adding the mechanism, cleanup
8297c478bd9Sstevel@tonic-gate * and bail.
8307c478bd9Sstevel@tonic-gate */
8317c478bd9Sstevel@tonic-gate for (cleanup_idx = 0; cleanup_idx < mech_idx; cleanup_idx++) {
8327c478bd9Sstevel@tonic-gate kcf_remove_mech_provider(
8337c478bd9Sstevel@tonic-gate desc->pd_mechanisms[cleanup_idx].cm_mech_name, desc);
8347c478bd9Sstevel@tonic-gate }
8357c478bd9Sstevel@tonic-gate
8367c478bd9Sstevel@tonic-gate if (err == KCF_MECH_TAB_FULL)
8377c478bd9Sstevel@tonic-gate return (CRYPTO_HOST_MEMORY);
8387c478bd9Sstevel@tonic-gate
8397c478bd9Sstevel@tonic-gate return (CRYPTO_ARGUMENTS_BAD);
8407c478bd9Sstevel@tonic-gate }
8417c478bd9Sstevel@tonic-gate
8427c478bd9Sstevel@tonic-gate /*
8437c478bd9Sstevel@tonic-gate * Update routine for kstat. Only privileged users are allowed to
8447c478bd9Sstevel@tonic-gate * access this information, since this information is sensitive.
8457c478bd9Sstevel@tonic-gate * There are some cryptographic attacks (e.g. traffic analysis)
8467c478bd9Sstevel@tonic-gate * which can use this information.
8477c478bd9Sstevel@tonic-gate */
8487c478bd9Sstevel@tonic-gate static int
kcf_prov_kstat_update(kstat_t * ksp,int rw)8497c478bd9Sstevel@tonic-gate kcf_prov_kstat_update(kstat_t *ksp, int rw)
8507c478bd9Sstevel@tonic-gate {
8517c478bd9Sstevel@tonic-gate kcf_prov_stats_t *ks_data;
8527c478bd9Sstevel@tonic-gate kcf_provider_desc_t *pd = (kcf_provider_desc_t *)ksp->ks_private;
853ef56a3c5SKrishna Yenduri int i;
8547c478bd9Sstevel@tonic-gate
8557c478bd9Sstevel@tonic-gate if (rw == KSTAT_WRITE)
8567c478bd9Sstevel@tonic-gate return (EACCES);
8577c478bd9Sstevel@tonic-gate
8587c478bd9Sstevel@tonic-gate ks_data = ksp->ks_data;
8597c478bd9Sstevel@tonic-gate
8607c478bd9Sstevel@tonic-gate if (secpolicy_sys_config(CRED(), B_TRUE) != 0) {
8617c478bd9Sstevel@tonic-gate ks_data->ps_ops_total.value.ui64 = 0;
8627c478bd9Sstevel@tonic-gate ks_data->ps_ops_passed.value.ui64 = 0;
8637c478bd9Sstevel@tonic-gate ks_data->ps_ops_failed.value.ui64 = 0;
8647c478bd9Sstevel@tonic-gate ks_data->ps_ops_busy_rval.value.ui64 = 0;
8657c478bd9Sstevel@tonic-gate } else {
866ef56a3c5SKrishna Yenduri uint64_t dtotal, ftotal, btotal;
867ef56a3c5SKrishna Yenduri
868ef56a3c5SKrishna Yenduri dtotal = ftotal = btotal = 0;
869ef56a3c5SKrishna Yenduri /* No locking done since an exact count is not required. */
870ef56a3c5SKrishna Yenduri for (i = 0; i < pd->pd_nbins; i++) {
871ef56a3c5SKrishna Yenduri dtotal += pd->pd_percpu_bins[i].kp_ndispatches;
872ef56a3c5SKrishna Yenduri ftotal += pd->pd_percpu_bins[i].kp_nfails;
873ef56a3c5SKrishna Yenduri btotal += pd->pd_percpu_bins[i].kp_nbusy_rval;
874ef56a3c5SKrishna Yenduri }
875ef56a3c5SKrishna Yenduri
876ef56a3c5SKrishna Yenduri ks_data->ps_ops_total.value.ui64 = dtotal;
877ef56a3c5SKrishna Yenduri ks_data->ps_ops_failed.value.ui64 = ftotal;
878ef56a3c5SKrishna Yenduri ks_data->ps_ops_busy_rval.value.ui64 = btotal;
879ef56a3c5SKrishna Yenduri ks_data->ps_ops_passed.value.ui64 = dtotal - ftotal - btotal;
8807c478bd9Sstevel@tonic-gate }
8817c478bd9Sstevel@tonic-gate
8827c478bd9Sstevel@tonic-gate return (0);
8837c478bd9Sstevel@tonic-gate }
8847c478bd9Sstevel@tonic-gate
8857c478bd9Sstevel@tonic-gate
8867c478bd9Sstevel@tonic-gate /*
8877c478bd9Sstevel@tonic-gate * Utility routine called from failure paths in crypto_register_provider()
8887c478bd9Sstevel@tonic-gate * and from crypto_load_soft_disabled().
8897c478bd9Sstevel@tonic-gate */
8907c478bd9Sstevel@tonic-gate void
undo_register_provider(kcf_provider_desc_t * desc,boolean_t remove_prov)8917c478bd9Sstevel@tonic-gate undo_register_provider(kcf_provider_desc_t *desc, boolean_t remove_prov)
8927c478bd9Sstevel@tonic-gate {
8937c478bd9Sstevel@tonic-gate uint_t mech_idx;
8947c478bd9Sstevel@tonic-gate
8957c478bd9Sstevel@tonic-gate /* remove the provider from the mechanisms tables */
8967c478bd9Sstevel@tonic-gate for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
8977c478bd9Sstevel@tonic-gate mech_idx++) {
8987c478bd9Sstevel@tonic-gate kcf_remove_mech_provider(
8997c478bd9Sstevel@tonic-gate desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
9007c478bd9Sstevel@tonic-gate }
9017c478bd9Sstevel@tonic-gate
9027c478bd9Sstevel@tonic-gate /* remove provider from providers table */
9037c478bd9Sstevel@tonic-gate if (remove_prov)
9047c478bd9Sstevel@tonic-gate (void) kcf_prov_tab_rem_provider(desc->pd_prov_id);
9057c478bd9Sstevel@tonic-gate }
9067c478bd9Sstevel@tonic-gate
9077c478bd9Sstevel@tonic-gate /*
9087c478bd9Sstevel@tonic-gate * Utility routine called from crypto_load_soft_disabled(). Callers
9097c478bd9Sstevel@tonic-gate * should have done a prior undo_register_provider().
9107c478bd9Sstevel@tonic-gate */
9117c478bd9Sstevel@tonic-gate void
redo_register_provider(kcf_provider_desc_t * pd)9127c478bd9Sstevel@tonic-gate redo_register_provider(kcf_provider_desc_t *pd)
9137c478bd9Sstevel@tonic-gate {
9147c478bd9Sstevel@tonic-gate /* process the mechanisms supported by the provider */
9157c478bd9Sstevel@tonic-gate (void) init_prov_mechs(NULL, pd);
9167c478bd9Sstevel@tonic-gate
9177c478bd9Sstevel@tonic-gate /*
9187c478bd9Sstevel@tonic-gate * Hold provider in providers table. We should not call
9197c478bd9Sstevel@tonic-gate * kcf_prov_tab_add_provider() here as the provider descriptor
9207c478bd9Sstevel@tonic-gate * is still valid which means it has an entry in the provider
9217c478bd9Sstevel@tonic-gate * table.
9227c478bd9Sstevel@tonic-gate */
9237c478bd9Sstevel@tonic-gate KCF_PROV_REFHOLD(pd);
9247c478bd9Sstevel@tonic-gate }
9257c478bd9Sstevel@tonic-gate
9267c478bd9Sstevel@tonic-gate /*
9277c478bd9Sstevel@tonic-gate * Add provider (p1) to another provider's array of providers (p2).
9287c478bd9Sstevel@tonic-gate * Hardware and logical providers use this array to cross-reference
9297c478bd9Sstevel@tonic-gate * each other.
9307c478bd9Sstevel@tonic-gate */
9317c478bd9Sstevel@tonic-gate static void
add_provider_to_array(kcf_provider_desc_t * p1,kcf_provider_desc_t * p2)9327c478bd9Sstevel@tonic-gate add_provider_to_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
9337c478bd9Sstevel@tonic-gate {
9347c478bd9Sstevel@tonic-gate kcf_provider_list_t *new;
9357c478bd9Sstevel@tonic-gate
9367c478bd9Sstevel@tonic-gate new = kmem_alloc(sizeof (kcf_provider_list_t), KM_SLEEP);
9377c478bd9Sstevel@tonic-gate mutex_enter(&p2->pd_lock);
9387c478bd9Sstevel@tonic-gate new->pl_next = p2->pd_provider_list;
9397c478bd9Sstevel@tonic-gate p2->pd_provider_list = new;
9407c478bd9Sstevel@tonic-gate new->pl_provider = p1;
9417c478bd9Sstevel@tonic-gate mutex_exit(&p2->pd_lock);
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate
9447c478bd9Sstevel@tonic-gate /*
9457c478bd9Sstevel@tonic-gate * Remove provider (p1) from another provider's array of providers (p2).
9467c478bd9Sstevel@tonic-gate * Hardware and logical providers use this array to cross-reference
9477c478bd9Sstevel@tonic-gate * each other.
9487c478bd9Sstevel@tonic-gate */
9497c478bd9Sstevel@tonic-gate static void
remove_provider_from_array(kcf_provider_desc_t * p1,kcf_provider_desc_t * p2)9507c478bd9Sstevel@tonic-gate remove_provider_from_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
9517c478bd9Sstevel@tonic-gate {
9527c478bd9Sstevel@tonic-gate
9537c478bd9Sstevel@tonic-gate kcf_provider_list_t *pl = NULL, **prev;
9547c478bd9Sstevel@tonic-gate
9557c478bd9Sstevel@tonic-gate mutex_enter(&p2->pd_lock);
9567c478bd9Sstevel@tonic-gate for (pl = p2->pd_provider_list, prev = &p2->pd_provider_list;
9577c478bd9Sstevel@tonic-gate pl != NULL; prev = &pl->pl_next, pl = pl->pl_next) {
9587c478bd9Sstevel@tonic-gate if (pl->pl_provider == p1) {
9597c478bd9Sstevel@tonic-gate break;
9607c478bd9Sstevel@tonic-gate }
9617c478bd9Sstevel@tonic-gate }
9627c478bd9Sstevel@tonic-gate
9637c478bd9Sstevel@tonic-gate if (p1 == NULL) {
9647c478bd9Sstevel@tonic-gate mutex_exit(&p2->pd_lock);
9657c478bd9Sstevel@tonic-gate return;
9667c478bd9Sstevel@tonic-gate }
9677c478bd9Sstevel@tonic-gate
9687c478bd9Sstevel@tonic-gate /* detach and free kcf_provider_list structure */
9697c478bd9Sstevel@tonic-gate *prev = pl->pl_next;
9707c478bd9Sstevel@tonic-gate kmem_free(pl, sizeof (*pl));
9717c478bd9Sstevel@tonic-gate mutex_exit(&p2->pd_lock);
9727c478bd9Sstevel@tonic-gate }
9737c478bd9Sstevel@tonic-gate
9747c478bd9Sstevel@tonic-gate /*
9757c478bd9Sstevel@tonic-gate * Convert an array of logical provider handles (crypto_provider_id)
9767c478bd9Sstevel@tonic-gate * stored in a crypto_provider_info structure into an array of provider
9777c478bd9Sstevel@tonic-gate * descriptors (kcf_provider_desc_t) attached to a logical provider.
9787c478bd9Sstevel@tonic-gate */
9797c478bd9Sstevel@tonic-gate static void
process_logical_providers(crypto_provider_info_t * info,kcf_provider_desc_t * hp)9807c478bd9Sstevel@tonic-gate process_logical_providers(crypto_provider_info_t *info, kcf_provider_desc_t *hp)
9817c478bd9Sstevel@tonic-gate {
9827c478bd9Sstevel@tonic-gate kcf_provider_desc_t *lp;
9837c478bd9Sstevel@tonic-gate crypto_provider_id_t handle;
9847c478bd9Sstevel@tonic-gate int count = info->pi_logical_provider_count;
9857c478bd9Sstevel@tonic-gate int i;
9867c478bd9Sstevel@tonic-gate
9877c478bd9Sstevel@tonic-gate /* add hardware provider to each logical provider */
9887c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) {
9897c478bd9Sstevel@tonic-gate handle = info->pi_logical_providers[i];
9907c478bd9Sstevel@tonic-gate lp = kcf_prov_tab_lookup((crypto_provider_id_t)handle);
9917c478bd9Sstevel@tonic-gate if (lp == NULL) {
9927c478bd9Sstevel@tonic-gate continue;
9937c478bd9Sstevel@tonic-gate }
9947c478bd9Sstevel@tonic-gate add_provider_to_array(hp, lp);
995c892ebf1Skrishna hp->pd_flags |= KCF_LPROV_MEMBER;
9967c478bd9Sstevel@tonic-gate
9977c478bd9Sstevel@tonic-gate /*
9987c478bd9Sstevel@tonic-gate * A hardware provider has to have the provider descriptor of
9997c478bd9Sstevel@tonic-gate * every logical provider it belongs to, so it can be removed
10007c478bd9Sstevel@tonic-gate * from the logical provider if the hardware provider
10017c478bd9Sstevel@tonic-gate * unregisters from the framework.
10027c478bd9Sstevel@tonic-gate */
10037c478bd9Sstevel@tonic-gate add_provider_to_array(lp, hp);
10047c478bd9Sstevel@tonic-gate KCF_PROV_REFRELE(lp);
10057c478bd9Sstevel@tonic-gate }
10067c478bd9Sstevel@tonic-gate }
10077c478bd9Sstevel@tonic-gate
10087c478bd9Sstevel@tonic-gate /*
10097c478bd9Sstevel@tonic-gate * This routine removes a provider from all of the logical or
10107c478bd9Sstevel@tonic-gate * hardware providers it belongs to, and frees the provider's
10117c478bd9Sstevel@tonic-gate * array of pointers to providers.
10127c478bd9Sstevel@tonic-gate */
10137c478bd9Sstevel@tonic-gate static void
remove_provider(kcf_provider_desc_t * pp)10147c478bd9Sstevel@tonic-gate remove_provider(kcf_provider_desc_t *pp)
10157c478bd9Sstevel@tonic-gate {
10167c478bd9Sstevel@tonic-gate kcf_provider_desc_t *p;
10177c478bd9Sstevel@tonic-gate kcf_provider_list_t *e, *next;
10187c478bd9Sstevel@tonic-gate
10197c478bd9Sstevel@tonic-gate mutex_enter(&pp->pd_lock);
10207c478bd9Sstevel@tonic-gate for (e = pp->pd_provider_list; e != NULL; e = next) {
10217c478bd9Sstevel@tonic-gate p = e->pl_provider;
10227c478bd9Sstevel@tonic-gate remove_provider_from_array(pp, p);
1023c892ebf1Skrishna if (p->pd_prov_type == CRYPTO_HW_PROVIDER &&
1024c892ebf1Skrishna p->pd_provider_list == NULL)
1025c892ebf1Skrishna p->pd_flags &= ~KCF_LPROV_MEMBER;
10267c478bd9Sstevel@tonic-gate next = e->pl_next;
10277c478bd9Sstevel@tonic-gate kmem_free(e, sizeof (*e));
10287c478bd9Sstevel@tonic-gate }
10297c478bd9Sstevel@tonic-gate pp->pd_provider_list = NULL;
10307c478bd9Sstevel@tonic-gate mutex_exit(&pp->pd_lock);
10317c478bd9Sstevel@tonic-gate }
1032fe2f7468Skrishna
1033fe2f7468Skrishna /*
1034fe2f7468Skrishna * Dispatch events as needed for a provider. is_added flag tells
1035fe2f7468Skrishna * whether the provider is registering or unregistering.
1036fe2f7468Skrishna */
1037fe2f7468Skrishna void
kcf_do_notify(kcf_provider_desc_t * prov_desc,boolean_t is_added)1038fe2f7468Skrishna kcf_do_notify(kcf_provider_desc_t *prov_desc, boolean_t is_added)
1039fe2f7468Skrishna {
1040fe2f7468Skrishna int i;
1041fe2f7468Skrishna crypto_notify_event_change_t ec;
1042fe2f7468Skrishna
1043fe2f7468Skrishna ASSERT(prov_desc->pd_state > KCF_PROV_VERIFICATION_FAILED);
1044fe2f7468Skrishna
1045fe2f7468Skrishna /*
1046fe2f7468Skrishna * Inform interested clients of the mechanisms becoming
1047fe2f7468Skrishna * available/unavailable. We skip this for logical providers
1048fe2f7468Skrishna * as they do not affect mechanisms.
1049fe2f7468Skrishna */
1050fe2f7468Skrishna if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
1051fe2f7468Skrishna ec.ec_provider_type = prov_desc->pd_prov_type;
1052fe2f7468Skrishna ec.ec_change = is_added ? CRYPTO_MECH_ADDED :
1053fe2f7468Skrishna CRYPTO_MECH_REMOVED;
1054fe2f7468Skrishna for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
1055fe2f7468Skrishna /* Skip any mechanisms not allowed by the policy */
1056fe2f7468Skrishna if (is_mech_disabled(prov_desc,
1057fe2f7468Skrishna prov_desc->pd_mechanisms[i].cm_mech_name))
1058fe2f7468Skrishna continue;
1059fe2f7468Skrishna
1060fe2f7468Skrishna (void) strncpy(ec.ec_mech_name,
1061fe2f7468Skrishna prov_desc->pd_mechanisms[i].cm_mech_name,
1062fe2f7468Skrishna CRYPTO_MAX_MECH_NAME);
1063fe2f7468Skrishna kcf_walk_ntfylist(CRYPTO_EVENT_MECHS_CHANGED, &ec);
1064fe2f7468Skrishna }
1065fe2f7468Skrishna
1066fe2f7468Skrishna }
1067fe2f7468Skrishna
1068fe2f7468Skrishna /*
1069fe2f7468Skrishna * Inform interested clients about the new or departing provider.
1070fe2f7468Skrishna * In case of a logical provider, we need to notify the event only
1071fe2f7468Skrishna * for the logical provider and not for the underlying
1072fe2f7468Skrishna * providers which are known by the KCF_LPROV_MEMBER bit.
1073fe2f7468Skrishna */
1074fe2f7468Skrishna if (prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER ||
1075fe2f7468Skrishna (prov_desc->pd_flags & KCF_LPROV_MEMBER) == 0) {
1076fe2f7468Skrishna kcf_walk_ntfylist(is_added ? CRYPTO_EVENT_PROVIDER_REGISTERED :
1077fe2f7468Skrishna CRYPTO_EVENT_PROVIDER_UNREGISTERED, prov_desc);
1078fe2f7468Skrishna }
1079fe2f7468Skrishna }
1080fe2f7468Skrishna
1081fe2f7468Skrishna static void
delete_kstat(kcf_provider_desc_t * desc)1082fe2f7468Skrishna delete_kstat(kcf_provider_desc_t *desc)
1083fe2f7468Skrishna {
1084fe2f7468Skrishna /* destroy the kstat created for this provider */
1085fe2f7468Skrishna if (desc->pd_kstat != NULL) {
1086fe2f7468Skrishna kcf_provider_desc_t *kspd = desc->pd_kstat->ks_private;
1087fe2f7468Skrishna
1088fe2f7468Skrishna /* release reference held by desc->pd_kstat->ks_private */
1089fe2f7468Skrishna ASSERT(desc == kspd);
1090fe2f7468Skrishna kstat_delete(kspd->pd_kstat);
1091fe2f7468Skrishna desc->pd_kstat = NULL;
1092fe2f7468Skrishna KCF_PROV_REFRELE(kspd);
1093fe2f7468Skrishna }
1094fe2f7468Skrishna }
1095