10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52800Skrishna * Common Development and Distribution License (the "License").
62800Skrishna * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*11751SAnthony.Scarpino@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * This file is part of the core Kernel Cryptographic Framework.
280Sstevel@tonic-gate * It implements the SPI functions exported to cryptographic
290Sstevel@tonic-gate * providers.
300Sstevel@tonic-gate */
310Sstevel@tonic-gate
320Sstevel@tonic-gate #include <sys/ksynch.h>
330Sstevel@tonic-gate #include <sys/cmn_err.h>
340Sstevel@tonic-gate #include <sys/ddi.h>
350Sstevel@tonic-gate #include <sys/sunddi.h>
360Sstevel@tonic-gate #include <sys/modctl.h>
370Sstevel@tonic-gate #include <sys/crypto/common.h>
380Sstevel@tonic-gate #include <sys/crypto/impl.h>
390Sstevel@tonic-gate #include <sys/crypto/sched_impl.h>
400Sstevel@tonic-gate #include <sys/crypto/spi.h>
4110732SAnthony.Scarpino@Sun.COM #include <sys/crypto/ioctladmin.h>
420Sstevel@tonic-gate #include <sys/taskq.h>
430Sstevel@tonic-gate #include <sys/disp.h>
440Sstevel@tonic-gate #include <sys/kstat.h>
450Sstevel@tonic-gate #include <sys/policy.h>
464494Skrishna #include <sys/cpuvar.h>
470Sstevel@tonic-gate
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate * minalloc and maxalloc values to be used for taskq_create().
500Sstevel@tonic-gate */
514494Skrishna int crypto_taskq_threads = CRYPTO_TASKQ_THREADS;
520Sstevel@tonic-gate int crypto_taskq_minalloc = CYRPTO_TASKQ_MIN;
530Sstevel@tonic-gate int crypto_taskq_maxalloc = CRYPTO_TASKQ_MAX;
540Sstevel@tonic-gate
550Sstevel@tonic-gate static void remove_provider(kcf_provider_desc_t *);
560Sstevel@tonic-gate static void process_logical_providers(crypto_provider_info_t *,
570Sstevel@tonic-gate kcf_provider_desc_t *);
580Sstevel@tonic-gate static int init_prov_mechs(crypto_provider_info_t *, kcf_provider_desc_t *);
590Sstevel@tonic-gate static int kcf_prov_kstat_update(kstat_t *, int);
604373Skrishna static void undo_register_provider_extra(kcf_provider_desc_t *);
614373Skrishna static void delete_kstat(kcf_provider_desc_t *);
620Sstevel@tonic-gate
630Sstevel@tonic-gate static kcf_prov_stats_t kcf_stats_ks_data_template = {
640Sstevel@tonic-gate { "kcf_ops_total", KSTAT_DATA_UINT64 },
650Sstevel@tonic-gate { "kcf_ops_passed", KSTAT_DATA_UINT64 },
660Sstevel@tonic-gate { "kcf_ops_failed", KSTAT_DATA_UINT64 },
670Sstevel@tonic-gate { "kcf_ops_returned_busy", KSTAT_DATA_UINT64 }
680Sstevel@tonic-gate };
690Sstevel@tonic-gate
700Sstevel@tonic-gate #define KCF_SPI_COPY_OPS(src, dst, ops) if ((src)->ops != NULL) \
710Sstevel@tonic-gate *((dst)->ops) = *((src)->ops);
720Sstevel@tonic-gate
73*11751SAnthony.Scarpino@Sun.COM extern int sys_shutdown;
74*11751SAnthony.Scarpino@Sun.COM
750Sstevel@tonic-gate /*
764219Smcpowers * Copy an ops vector from src to dst. Used during provider registration
774219Smcpowers * to copy the ops vector from the provider info structure to the
784219Smcpowers * provider descriptor maintained by KCF.
794219Smcpowers * Copying the ops vector specified by the provider is needed since the
804219Smcpowers * framework does not require the provider info structure to be
814219Smcpowers * persistent.
824219Smcpowers */
834219Smcpowers static void
copy_ops_vector_v1(crypto_ops_t * src_ops,crypto_ops_t * dst_ops)844219Smcpowers copy_ops_vector_v1(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
854219Smcpowers {
864219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_control_ops);
874219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_digest_ops);
884219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_cipher_ops);
894219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mac_ops);
904219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_sign_ops);
914219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_verify_ops);
924219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_ops);
934219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_cipher_mac_ops);
944219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_random_ops);
954219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_session_ops);
964219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_object_ops);
974219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_key_ops);
984219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_provider_ops);
994219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_ctx_ops);
1004219Smcpowers }
1014219Smcpowers
1024219Smcpowers static void
copy_ops_vector_v2(crypto_ops_t * src_ops,crypto_ops_t * dst_ops)1034219Smcpowers copy_ops_vector_v2(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
1044219Smcpowers {
1054219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mech_ops);
1064219Smcpowers }
1074219Smcpowers
1084219Smcpowers static void
copy_ops_vector_v3(crypto_ops_t * src_ops,crypto_ops_t * dst_ops)1094219Smcpowers copy_ops_vector_v3(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
1104219Smcpowers {
1114219Smcpowers KCF_SPI_COPY_OPS(src_ops, dst_ops, co_nostore_key_ops);
1124219Smcpowers }
1134219Smcpowers
11410732SAnthony.Scarpino@Sun.COM static void
copy_ops_vector_v4(crypto_ops_t * src_ops,crypto_ops_t * dst_ops)11510732SAnthony.Scarpino@Sun.COM copy_ops_vector_v4(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
11610732SAnthony.Scarpino@Sun.COM {
11710732SAnthony.Scarpino@Sun.COM KCF_SPI_COPY_OPS(src_ops, dst_ops, co_fips140_ops);
11810732SAnthony.Scarpino@Sun.COM }
11910732SAnthony.Scarpino@Sun.COM
1204219Smcpowers /*
1210Sstevel@tonic-gate * This routine is used to add cryptographic providers to the KEF framework.
1220Sstevel@tonic-gate * Providers pass a crypto_provider_info structure to crypto_register_provider()
1230Sstevel@tonic-gate * and get back a handle. The crypto_provider_info structure contains a
1240Sstevel@tonic-gate * list of mechanisms supported by the provider and an ops vector containing
1250Sstevel@tonic-gate * provider entry points. Hardware providers call this routine in their attach
1260Sstevel@tonic-gate * routines. Software providers call this routine in their _init() routine.
1270Sstevel@tonic-gate */
1280Sstevel@tonic-gate int
crypto_register_provider(crypto_provider_info_t * info,crypto_kcf_provider_handle_t * handle)1290Sstevel@tonic-gate crypto_register_provider(crypto_provider_info_t *info,
1300Sstevel@tonic-gate crypto_kcf_provider_handle_t *handle)
1310Sstevel@tonic-gate {
13210732SAnthony.Scarpino@Sun.COM int need_fips140_verify, need_verify = 1;
1330Sstevel@tonic-gate struct modctl *mcp;
1340Sstevel@tonic-gate char *name;
1350Sstevel@tonic-gate char ks_name[KSTAT_STRLEN];
1360Sstevel@tonic-gate kcf_provider_desc_t *prov_desc = NULL;
1370Sstevel@tonic-gate int ret = CRYPTO_ARGUMENTS_BAD;
1380Sstevel@tonic-gate
139*11751SAnthony.Scarpino@Sun.COM if (info->pi_interface_version > CRYPTO_SPI_VERSION_4) {
140*11751SAnthony.Scarpino@Sun.COM ret = CRYPTO_VERSION_MISMATCH;
141*11751SAnthony.Scarpino@Sun.COM goto errormsg;
142*11751SAnthony.Scarpino@Sun.COM }
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate /*
1450Sstevel@tonic-gate * Check provider type, must be software, hardware, or logical.
1460Sstevel@tonic-gate */
1470Sstevel@tonic-gate if (info->pi_provider_type != CRYPTO_HW_PROVIDER &&
1480Sstevel@tonic-gate info->pi_provider_type != CRYPTO_SW_PROVIDER &&
1490Sstevel@tonic-gate info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER)
150*11751SAnthony.Scarpino@Sun.COM goto errormsg;
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate /*
1530Sstevel@tonic-gate * Allocate and initialize a new provider descriptor. We also
1540Sstevel@tonic-gate * hold it and release it when done.
1550Sstevel@tonic-gate */
1560Sstevel@tonic-gate prov_desc = kcf_alloc_provider_desc(info);
1570Sstevel@tonic-gate KCF_PROV_REFHOLD(prov_desc);
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate prov_desc->pd_prov_type = info->pi_provider_type;
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate /* provider-private handle, opaque to KCF */
1620Sstevel@tonic-gate prov_desc->pd_prov_handle = info->pi_provider_handle;
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate /* copy provider description string */
1650Sstevel@tonic-gate if (info->pi_provider_description != NULL) {
1660Sstevel@tonic-gate /*
1670Sstevel@tonic-gate * pi_provider_descriptor is a string that can contain
1680Sstevel@tonic-gate * up to CRYPTO_PROVIDER_DESCR_MAX_LEN + 1 characters
1690Sstevel@tonic-gate * INCLUDING the terminating null character. A bcopy()
1700Sstevel@tonic-gate * is necessary here as pd_description should not have
1710Sstevel@tonic-gate * a null character. See comments in kcf_alloc_provider_desc()
1720Sstevel@tonic-gate * for details on pd_description field.
1730Sstevel@tonic-gate */
1740Sstevel@tonic-gate bcopy(info->pi_provider_description, prov_desc->pd_description,
1750Sstevel@tonic-gate min(strlen(info->pi_provider_description),
1760Sstevel@tonic-gate CRYPTO_PROVIDER_DESCR_MAX_LEN));
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
1800Sstevel@tonic-gate if (info->pi_ops_vector == NULL) {
1814219Smcpowers goto bail;
1820Sstevel@tonic-gate }
183904Smcpowers copy_ops_vector_v1(info->pi_ops_vector,
184904Smcpowers prov_desc->pd_ops_vector);
1854219Smcpowers if (info->pi_interface_version >= CRYPTO_SPI_VERSION_2) {
186904Smcpowers copy_ops_vector_v2(info->pi_ops_vector,
187904Smcpowers prov_desc->pd_ops_vector);
188904Smcpowers prov_desc->pd_flags = info->pi_flags;
189904Smcpowers }
19010732SAnthony.Scarpino@Sun.COM if (info->pi_interface_version >= CRYPTO_SPI_VERSION_3) {
1914219Smcpowers copy_ops_vector_v3(info->pi_ops_vector,
1924219Smcpowers prov_desc->pd_ops_vector);
1934219Smcpowers }
19410732SAnthony.Scarpino@Sun.COM if (info->pi_interface_version == CRYPTO_SPI_VERSION_4) {
19510732SAnthony.Scarpino@Sun.COM copy_ops_vector_v4(info->pi_ops_vector,
19610732SAnthony.Scarpino@Sun.COM prov_desc->pd_ops_vector);
19710732SAnthony.Scarpino@Sun.COM }
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate
2004219Smcpowers /* object_ops and nostore_key_ops are mutually exclusive */
2014219Smcpowers if (prov_desc->pd_ops_vector->co_object_ops &&
2024219Smcpowers prov_desc->pd_ops_vector->co_nostore_key_ops) {
2034219Smcpowers goto bail;
2044219Smcpowers }
2050Sstevel@tonic-gate /*
2060Sstevel@tonic-gate * For software providers, copy the module name and module ID.
2070Sstevel@tonic-gate * For hardware providers, copy the driver name and instance.
2080Sstevel@tonic-gate */
2090Sstevel@tonic-gate switch (info->pi_provider_type) {
2100Sstevel@tonic-gate case CRYPTO_SW_PROVIDER:
2110Sstevel@tonic-gate if (info->pi_provider_dev.pd_sw == NULL)
2120Sstevel@tonic-gate goto bail;
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate if ((mcp = mod_getctl(info->pi_provider_dev.pd_sw)) == NULL)
2150Sstevel@tonic-gate goto bail;
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate prov_desc->pd_module_id = mcp->mod_id;
2180Sstevel@tonic-gate name = mcp->mod_modname;
2190Sstevel@tonic-gate break;
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate case CRYPTO_HW_PROVIDER:
2220Sstevel@tonic-gate case CRYPTO_LOGICAL_PROVIDER:
2230Sstevel@tonic-gate if (info->pi_provider_dev.pd_hw == NULL)
2240Sstevel@tonic-gate goto bail;
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate prov_desc->pd_instance =
2270Sstevel@tonic-gate ddi_get_instance(info->pi_provider_dev.pd_hw);
2280Sstevel@tonic-gate name = (char *)ddi_driver_name(info->pi_provider_dev.pd_hw);
2290Sstevel@tonic-gate break;
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate if (name == NULL)
2320Sstevel@tonic-gate goto bail;
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate prov_desc->pd_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
2350Sstevel@tonic-gate (void) strcpy(prov_desc->pd_name, name);
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate if ((prov_desc->pd_mctlp = kcf_get_modctl(info)) == NULL)
2380Sstevel@tonic-gate goto bail;
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate /* process the mechanisms supported by the provider */
2410Sstevel@tonic-gate if ((ret = init_prov_mechs(info, prov_desc)) != CRYPTO_SUCCESS)
2420Sstevel@tonic-gate goto bail;
2430Sstevel@tonic-gate
2440Sstevel@tonic-gate /*
2450Sstevel@tonic-gate * Add provider to providers tables, also sets the descriptor
2460Sstevel@tonic-gate * pd_prov_id field.
2470Sstevel@tonic-gate */
2480Sstevel@tonic-gate if ((ret = kcf_prov_tab_add_provider(prov_desc)) != CRYPTO_SUCCESS) {
2490Sstevel@tonic-gate undo_register_provider(prov_desc, B_FALSE);
2500Sstevel@tonic-gate goto bail;
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate
2534373Skrishna if ((need_verify = kcf_need_signature_verification(prov_desc)) == -1) {
2544373Skrishna undo_register_provider(prov_desc, B_TRUE);
2554373Skrishna ret = CRYPTO_MODVERIFICATION_FAILED;
2564373Skrishna goto bail;
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate
25910732SAnthony.Scarpino@Sun.COM if ((need_fips140_verify =
26010732SAnthony.Scarpino@Sun.COM kcf_need_fips140_verification(prov_desc)) == -1) {
26110732SAnthony.Scarpino@Sun.COM mutex_enter(&prov_desc->pd_lock);
26210732SAnthony.Scarpino@Sun.COM prov_desc->pd_state = KCF_PROV_VERIFICATION_FAILED;
26310732SAnthony.Scarpino@Sun.COM mutex_exit(&prov_desc->pd_lock);
26410732SAnthony.Scarpino@Sun.COM ret = CRYPTO_FIPS140_ERROR;
26510732SAnthony.Scarpino@Sun.COM goto bail;
26610732SAnthony.Scarpino@Sun.COM }
26710732SAnthony.Scarpino@Sun.COM
2680Sstevel@tonic-gate /*
2690Sstevel@tonic-gate * We create a taskq only for a hardware provider. The global
2704494Skrishna * software queue is used for software providers. We handle ordering
2714494Skrishna * of multi-part requests in the taskq routine. So, it is safe to
2724494Skrishna * have multiple threads for the taskq. We pass TASKQ_PREPOPULATE flag
2734494Skrishna * to keep some entries cached to improve performance.
2740Sstevel@tonic-gate */
2750Sstevel@tonic-gate if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
2769505SBhargava.Yenduri@Sun.COM prov_desc->pd_taskq = taskq_create("kcf_taskq",
2774494Skrishna crypto_taskq_threads, minclsyspri,
2784494Skrishna crypto_taskq_minalloc, crypto_taskq_maxalloc,
2794494Skrishna TASKQ_PREPOPULATE);
2800Sstevel@tonic-gate else
2819505SBhargava.Yenduri@Sun.COM prov_desc->pd_taskq = NULL;
2820Sstevel@tonic-gate
28311304SJanie.Lu@Sun.COM /* no kernel session to logical providers and no pd_flags */
2840Sstevel@tonic-gate if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
2850Sstevel@tonic-gate /*
2860Sstevel@tonic-gate * Open a session for session-oriented providers. This session
2870Sstevel@tonic-gate * is used for all kernel consumers. This is fine as a provider
2880Sstevel@tonic-gate * is required to support multiple thread access to a session.
2890Sstevel@tonic-gate * We can do this only after the taskq has been created as we
2900Sstevel@tonic-gate * do a kcf_submit_request() to open the session.
2910Sstevel@tonic-gate */
2920Sstevel@tonic-gate if (KCF_PROV_SESSION_OPS(prov_desc) != NULL) {
2930Sstevel@tonic-gate kcf_req_params_t params;
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate KCF_WRAP_SESSION_OPS_PARAMS(¶ms,
2960Sstevel@tonic-gate KCF_OP_SESSION_OPEN, &prov_desc->pd_sid, 0,
2970Sstevel@tonic-gate CRYPTO_USER, NULL, 0, prov_desc);
2980Sstevel@tonic-gate ret = kcf_submit_request(prov_desc, NULL, NULL, ¶ms,
2990Sstevel@tonic-gate B_FALSE);
30011304SJanie.Lu@Sun.COM if (ret != CRYPTO_SUCCESS)
30111304SJanie.Lu@Sun.COM goto undo_then_bail;
30211304SJanie.Lu@Sun.COM }
3030Sstevel@tonic-gate
30411304SJanie.Lu@Sun.COM /*
30511304SJanie.Lu@Sun.COM * Get the value for the maximum input length allowed if
30611304SJanie.Lu@Sun.COM * CRYPTO_HASH_NO_UPDATE or CRYPTO_HASH_NO_UPDATE is specified.
30711304SJanie.Lu@Sun.COM */
30811304SJanie.Lu@Sun.COM if (prov_desc->pd_flags &
30911304SJanie.Lu@Sun.COM (CRYPTO_HASH_NO_UPDATE | CRYPTO_HMAC_NO_UPDATE)) {
31011304SJanie.Lu@Sun.COM kcf_req_params_t params;
31111304SJanie.Lu@Sun.COM crypto_provider_ext_info_t ext_info;
31211304SJanie.Lu@Sun.COM
31311304SJanie.Lu@Sun.COM if (KCF_PROV_PROVMGMT_OPS(prov_desc) == NULL)
31411304SJanie.Lu@Sun.COM goto undo_then_bail;
31511304SJanie.Lu@Sun.COM
31611304SJanie.Lu@Sun.COM bzero(&ext_info, sizeof (ext_info));
31711304SJanie.Lu@Sun.COM KCF_WRAP_PROVMGMT_OPS_PARAMS(¶ms,
31811304SJanie.Lu@Sun.COM KCF_OP_MGMT_EXTINFO,
31911304SJanie.Lu@Sun.COM 0, NULL, 0, NULL, 0, NULL, &ext_info, prov_desc);
32011304SJanie.Lu@Sun.COM ret = kcf_submit_request(prov_desc, NULL, NULL,
32111304SJanie.Lu@Sun.COM ¶ms, B_FALSE);
32211304SJanie.Lu@Sun.COM if (ret != CRYPTO_SUCCESS)
32311304SJanie.Lu@Sun.COM goto undo_then_bail;
32411304SJanie.Lu@Sun.COM
32511304SJanie.Lu@Sun.COM if (prov_desc->pd_flags & CRYPTO_HASH_NO_UPDATE) {
32611304SJanie.Lu@Sun.COM prov_desc->pd_hash_limit =
32711304SJanie.Lu@Sun.COM ext_info.ei_hash_max_input_len;
32811304SJanie.Lu@Sun.COM }
32911304SJanie.Lu@Sun.COM if (prov_desc->pd_flags & CRYPTO_HMAC_NO_UPDATE) {
33011304SJanie.Lu@Sun.COM prov_desc->pd_hmac_limit =
33111304SJanie.Lu@Sun.COM ext_info.ei_hmac_max_input_len;
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
3370Sstevel@tonic-gate /*
3380Sstevel@tonic-gate * Create the kstat for this provider. There is a kstat
3390Sstevel@tonic-gate * installed for each successfully registered provider.
3400Sstevel@tonic-gate * This kstat is deleted, when the provider unregisters.
3410Sstevel@tonic-gate */
3420Sstevel@tonic-gate if (prov_desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
3430Sstevel@tonic-gate (void) snprintf(ks_name, KSTAT_STRLEN, "%s_%s",
3440Sstevel@tonic-gate prov_desc->pd_name, "provider_stats");
3450Sstevel@tonic-gate } else {
3460Sstevel@tonic-gate (void) snprintf(ks_name, KSTAT_STRLEN, "%s_%d_%u_%s",
3470Sstevel@tonic-gate prov_desc->pd_name, prov_desc->pd_instance,
3480Sstevel@tonic-gate prov_desc->pd_prov_id, "provider_stats");
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate
3510Sstevel@tonic-gate prov_desc->pd_kstat = kstat_create("kcf", 0, ks_name, "crypto",
3520Sstevel@tonic-gate KSTAT_TYPE_NAMED, sizeof (kcf_prov_stats_t) /
3530Sstevel@tonic-gate sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate if (prov_desc->pd_kstat != NULL) {
3560Sstevel@tonic-gate bcopy(&kcf_stats_ks_data_template,
3570Sstevel@tonic-gate &prov_desc->pd_ks_data,
3580Sstevel@tonic-gate sizeof (kcf_stats_ks_data_template));
3590Sstevel@tonic-gate prov_desc->pd_kstat->ks_data = &prov_desc->pd_ks_data;
3600Sstevel@tonic-gate KCF_PROV_REFHOLD(prov_desc);
3610Sstevel@tonic-gate prov_desc->pd_kstat->ks_private = prov_desc;
3620Sstevel@tonic-gate prov_desc->pd_kstat->ks_update = kcf_prov_kstat_update;
3630Sstevel@tonic-gate kstat_install(prov_desc->pd_kstat);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate
3670Sstevel@tonic-gate if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
3680Sstevel@tonic-gate process_logical_providers(info, prov_desc);
3690Sstevel@tonic-gate
37010732SAnthony.Scarpino@Sun.COM /* This provider needs to wait until we know the FIPS 140 status */
37110732SAnthony.Scarpino@Sun.COM if (need_fips140_verify == 1) {
37210732SAnthony.Scarpino@Sun.COM mutex_enter(&prov_desc->pd_lock);
37310732SAnthony.Scarpino@Sun.COM prov_desc->pd_state = KCF_PROV_UNVERIFIED_FIPS140;
37410732SAnthony.Scarpino@Sun.COM mutex_exit(&prov_desc->pd_lock);
37510732SAnthony.Scarpino@Sun.COM goto exit;
37610732SAnthony.Scarpino@Sun.COM }
37710732SAnthony.Scarpino@Sun.COM
37810732SAnthony.Scarpino@Sun.COM /* This provider needs to have the signature verified */
3794373Skrishna if (need_verify == 1) {
38010732SAnthony.Scarpino@Sun.COM mutex_enter(&prov_desc->pd_lock);
38110732SAnthony.Scarpino@Sun.COM prov_desc->pd_state = KCF_PROV_UNVERIFIED;
38210732SAnthony.Scarpino@Sun.COM mutex_exit(&prov_desc->pd_lock);
38310732SAnthony.Scarpino@Sun.COM
3849505SBhargava.Yenduri@Sun.COM /* kcf_verify_signature routine will release this hold */
3854373Skrishna KCF_PROV_REFHOLD(prov_desc);
3860Sstevel@tonic-gate
3874373Skrishna if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER) {
3884373Skrishna /*
3894373Skrishna * It is not safe to make the door upcall to kcfd from
3904373Skrishna * this context since the kcfd thread could reenter
3914373Skrishna * devfs. So, we dispatch a taskq job to do the
3924373Skrishna * verification and return to the provider.
3934373Skrishna */
3944373Skrishna (void) taskq_dispatch(system_taskq,
3954373Skrishna kcf_verify_signature, (void *)prov_desc, TQ_SLEEP);
3964373Skrishna } else if (prov_desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
3974373Skrishna kcf_verify_signature(prov_desc);
3984373Skrishna if (prov_desc->pd_state ==
3994373Skrishna KCF_PROV_VERIFICATION_FAILED) {
4004373Skrishna undo_register_provider_extra(prov_desc);
4014373Skrishna ret = CRYPTO_MODVERIFICATION_FAILED;
4024373Skrishna goto bail;
4034373Skrishna }
4040Sstevel@tonic-gate }
4054373Skrishna } else {
4064373Skrishna mutex_enter(&prov_desc->pd_lock);
4074373Skrishna prov_desc->pd_state = KCF_PROV_READY;
4084373Skrishna mutex_exit(&prov_desc->pd_lock);
4094373Skrishna kcf_do_notify(prov_desc, B_TRUE);
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate
41210732SAnthony.Scarpino@Sun.COM exit:
4130Sstevel@tonic-gate *handle = prov_desc->pd_kcf_prov_handle;
41411304SJanie.Lu@Sun.COM KCF_PROV_REFRELE(prov_desc);
41511304SJanie.Lu@Sun.COM return (CRYPTO_SUCCESS);
4160Sstevel@tonic-gate
41711304SJanie.Lu@Sun.COM undo_then_bail:
41811304SJanie.Lu@Sun.COM undo_register_provider(prov_desc, B_TRUE);
41911304SJanie.Lu@Sun.COM ret = CRYPTO_FAILED;
4200Sstevel@tonic-gate bail:
4210Sstevel@tonic-gate KCF_PROV_REFRELE(prov_desc);
422*11751SAnthony.Scarpino@Sun.COM
423*11751SAnthony.Scarpino@Sun.COM errormsg:
424*11751SAnthony.Scarpino@Sun.COM if (ret != CRYPTO_SUCCESS && sys_shutdown == 0) {
425*11751SAnthony.Scarpino@Sun.COM switch (ret) {
426*11751SAnthony.Scarpino@Sun.COM case CRYPTO_FAILED:
427*11751SAnthony.Scarpino@Sun.COM cmn_err(CE_WARN, "%s failed when registering with the "
428*11751SAnthony.Scarpino@Sun.COM "Cryptographic Framework.",
429*11751SAnthony.Scarpino@Sun.COM info->pi_provider_description);
430*11751SAnthony.Scarpino@Sun.COM break;
431*11751SAnthony.Scarpino@Sun.COM
432*11751SAnthony.Scarpino@Sun.COM case CRYPTO_MODVERIFICATION_FAILED:
433*11751SAnthony.Scarpino@Sun.COM cmn_err(CE_WARN, "%s failed module verification when "
434*11751SAnthony.Scarpino@Sun.COM "registering with the Cryptographic Framework.",
435*11751SAnthony.Scarpino@Sun.COM info->pi_provider_description);
436*11751SAnthony.Scarpino@Sun.COM break;
437*11751SAnthony.Scarpino@Sun.COM
438*11751SAnthony.Scarpino@Sun.COM case CRYPTO_ARGUMENTS_BAD:
439*11751SAnthony.Scarpino@Sun.COM cmn_err(CE_WARN, "%s provided bad arguments and was "
440*11751SAnthony.Scarpino@Sun.COM "not registered with the Cryptographic Framework.",
441*11751SAnthony.Scarpino@Sun.COM info->pi_provider_description);
442*11751SAnthony.Scarpino@Sun.COM break;
443*11751SAnthony.Scarpino@Sun.COM
444*11751SAnthony.Scarpino@Sun.COM case CRYPTO_VERSION_MISMATCH:
445*11751SAnthony.Scarpino@Sun.COM cmn_err(CE_WARN, "%s was not registered with the "
446*11751SAnthony.Scarpino@Sun.COM "Cryptographic Framework as there is a SPI version "
447*11751SAnthony.Scarpino@Sun.COM "mismatch (%d) error.",
448*11751SAnthony.Scarpino@Sun.COM info->pi_provider_description,
449*11751SAnthony.Scarpino@Sun.COM info->pi_interface_version);
450*11751SAnthony.Scarpino@Sun.COM break;
451*11751SAnthony.Scarpino@Sun.COM
452*11751SAnthony.Scarpino@Sun.COM case CRYPTO_FIPS140_ERROR:
453*11751SAnthony.Scarpino@Sun.COM cmn_err(CE_WARN, "%s was not registered with the "
454*11751SAnthony.Scarpino@Sun.COM "Cryptographic Framework as there was a FIPS 140 "
455*11751SAnthony.Scarpino@Sun.COM "validation error.", info->pi_provider_description);
456*11751SAnthony.Scarpino@Sun.COM break;
457*11751SAnthony.Scarpino@Sun.COM
458*11751SAnthony.Scarpino@Sun.COM default:
459*11751SAnthony.Scarpino@Sun.COM cmn_err(CE_WARN, "%s did not register with the "
460*11751SAnthony.Scarpino@Sun.COM "Cryptographic Framework. (0x%x)",
461*11751SAnthony.Scarpino@Sun.COM info->pi_provider_description, ret);
462*11751SAnthony.Scarpino@Sun.COM };
463*11751SAnthony.Scarpino@Sun.COM }
464*11751SAnthony.Scarpino@Sun.COM
4650Sstevel@tonic-gate return (ret);
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate
4689505SBhargava.Yenduri@Sun.COM /* Return the number of holds on a provider. */
4699505SBhargava.Yenduri@Sun.COM int
kcf_get_refcnt(kcf_provider_desc_t * pd,boolean_t do_lock)4709505SBhargava.Yenduri@Sun.COM kcf_get_refcnt(kcf_provider_desc_t *pd, boolean_t do_lock)
4719505SBhargava.Yenduri@Sun.COM {
4729505SBhargava.Yenduri@Sun.COM int i;
4739505SBhargava.Yenduri@Sun.COM int refcnt = 0;
4749505SBhargava.Yenduri@Sun.COM
4759505SBhargava.Yenduri@Sun.COM if (do_lock)
4769505SBhargava.Yenduri@Sun.COM for (i = 0; i < pd->pd_nbins; i++)
4779505SBhargava.Yenduri@Sun.COM mutex_enter(&(pd->pd_percpu_bins[i].kp_lock));
4789505SBhargava.Yenduri@Sun.COM
4799505SBhargava.Yenduri@Sun.COM for (i = 0; i < pd->pd_nbins; i++)
4809505SBhargava.Yenduri@Sun.COM refcnt += pd->pd_percpu_bins[i].kp_holdcnt;
4819505SBhargava.Yenduri@Sun.COM
4829505SBhargava.Yenduri@Sun.COM if (do_lock)
4839505SBhargava.Yenduri@Sun.COM for (i = 0; i < pd->pd_nbins; i++)
4849505SBhargava.Yenduri@Sun.COM mutex_exit(&(pd->pd_percpu_bins[i].kp_lock));
4859505SBhargava.Yenduri@Sun.COM
4869505SBhargava.Yenduri@Sun.COM return (refcnt);
4879505SBhargava.Yenduri@Sun.COM }
4889505SBhargava.Yenduri@Sun.COM
4890Sstevel@tonic-gate /*
4900Sstevel@tonic-gate * This routine is used to notify the framework when a provider is being
4910Sstevel@tonic-gate * removed. Hardware providers call this routine in their detach routines.
4920Sstevel@tonic-gate * Software providers call this routine in their _fini() routine.
4930Sstevel@tonic-gate */
4940Sstevel@tonic-gate int
crypto_unregister_provider(crypto_kcf_provider_handle_t handle)4950Sstevel@tonic-gate crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
4960Sstevel@tonic-gate {
4970Sstevel@tonic-gate uint_t mech_idx;
4980Sstevel@tonic-gate kcf_provider_desc_t *desc;
4990Sstevel@tonic-gate kcf_prov_state_t saved_state;
500*11751SAnthony.Scarpino@Sun.COM int ret = CRYPTO_SUCCESS;
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate /* lookup provider descriptor */
503*11751SAnthony.Scarpino@Sun.COM if ((desc = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) ==
504*11751SAnthony.Scarpino@Sun.COM NULL) {
505*11751SAnthony.Scarpino@Sun.COM ret = CRYPTO_UNKNOWN_PROVIDER;
506*11751SAnthony.Scarpino@Sun.COM goto errormsg;
507*11751SAnthony.Scarpino@Sun.COM }
5080Sstevel@tonic-gate
5090Sstevel@tonic-gate mutex_enter(&desc->pd_lock);
5100Sstevel@tonic-gate /*
5110Sstevel@tonic-gate * Check if any other thread is disabling or removing
5120Sstevel@tonic-gate * this provider. We return if this is the case.
5130Sstevel@tonic-gate */
5140Sstevel@tonic-gate if (desc->pd_state >= KCF_PROV_DISABLED) {
5150Sstevel@tonic-gate mutex_exit(&desc->pd_lock);
5160Sstevel@tonic-gate /* Release reference held by kcf_prov_tab_lookup(). */
5170Sstevel@tonic-gate KCF_PROV_REFRELE(desc);
518*11751SAnthony.Scarpino@Sun.COM ret = CRYPTO_BUSY;
519*11751SAnthony.Scarpino@Sun.COM goto errormsg;
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate
5220Sstevel@tonic-gate saved_state = desc->pd_state;
5239505SBhargava.Yenduri@Sun.COM desc->pd_state = KCF_PROV_UNREGISTERING;
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate if (saved_state == KCF_PROV_BUSY) {
5260Sstevel@tonic-gate /*
5274912Skrishna * The per-provider taskq threads may be waiting. We
5284912Skrishna * signal them so that they can start failing requests.
5290Sstevel@tonic-gate */
5304912Skrishna cv_broadcast(&desc->pd_resume_cv);
5310Sstevel@tonic-gate }
5320Sstevel@tonic-gate
5330Sstevel@tonic-gate mutex_exit(&desc->pd_lock);
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate if (desc->pd_prov_type != CRYPTO_SW_PROVIDER) {
5360Sstevel@tonic-gate remove_provider(desc);
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate if (desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
5400Sstevel@tonic-gate /* remove the provider from the mechanisms tables */
5410Sstevel@tonic-gate for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
5420Sstevel@tonic-gate mech_idx++) {
5430Sstevel@tonic-gate kcf_remove_mech_provider(
5440Sstevel@tonic-gate desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
5450Sstevel@tonic-gate }
5460Sstevel@tonic-gate }
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate /* remove provider from providers table */
5490Sstevel@tonic-gate if (kcf_prov_tab_rem_provider((crypto_provider_id_t)handle) !=
5500Sstevel@tonic-gate CRYPTO_SUCCESS) {
5510Sstevel@tonic-gate /* Release reference held by kcf_prov_tab_lookup(). */
5520Sstevel@tonic-gate KCF_PROV_REFRELE(desc);
553*11751SAnthony.Scarpino@Sun.COM ret = CRYPTO_UNKNOWN_PROVIDER;
554*11751SAnthony.Scarpino@Sun.COM goto errormsg;
5550Sstevel@tonic-gate }
5560Sstevel@tonic-gate
5574373Skrishna delete_kstat(desc);
5580Sstevel@tonic-gate
5590Sstevel@tonic-gate if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
5600Sstevel@tonic-gate /*
5619505SBhargava.Yenduri@Sun.COM * Wait till the existing requests with the provider complete
5629505SBhargava.Yenduri@Sun.COM * and all the holds are released. All the holds on a software
5639505SBhargava.Yenduri@Sun.COM * provider are from kernel clients and the hold time
5649505SBhargava.Yenduri@Sun.COM * is expected to be short. So, we won't be stuck here forever.
5650Sstevel@tonic-gate */
5669505SBhargava.Yenduri@Sun.COM while (kcf_get_refcnt(desc, B_TRUE) > 1) {
5679505SBhargava.Yenduri@Sun.COM /* wait 1 second and try again. */
5689505SBhargava.Yenduri@Sun.COM delay(1 * drv_usectohz(1000000));
5699505SBhargava.Yenduri@Sun.COM }
5700Sstevel@tonic-gate } else {
5719505SBhargava.Yenduri@Sun.COM int i;
5729505SBhargava.Yenduri@Sun.COM kcf_prov_cpu_t *mp;
5739505SBhargava.Yenduri@Sun.COM
5740Sstevel@tonic-gate /*
5750Sstevel@tonic-gate * Wait until requests that have been sent to the provider
5760Sstevel@tonic-gate * complete.
5770Sstevel@tonic-gate */
5789505SBhargava.Yenduri@Sun.COM for (i = 0; i < desc->pd_nbins; i++) {
5799505SBhargava.Yenduri@Sun.COM mp = &(desc->pd_percpu_bins[i]);
5809505SBhargava.Yenduri@Sun.COM
5819505SBhargava.Yenduri@Sun.COM mutex_enter(&mp->kp_lock);
5829505SBhargava.Yenduri@Sun.COM while (mp->kp_jobcnt > 0) {
5839505SBhargava.Yenduri@Sun.COM cv_wait(&mp->kp_cv, &mp->kp_lock);
5849505SBhargava.Yenduri@Sun.COM }
5859505SBhargava.Yenduri@Sun.COM mutex_exit(&mp->kp_lock);
5869505SBhargava.Yenduri@Sun.COM }
5870Sstevel@tonic-gate }
5880Sstevel@tonic-gate
5899505SBhargava.Yenduri@Sun.COM mutex_enter(&desc->pd_lock);
5909505SBhargava.Yenduri@Sun.COM desc->pd_state = KCF_PROV_UNREGISTERED;
5919505SBhargava.Yenduri@Sun.COM mutex_exit(&desc->pd_lock);
5929505SBhargava.Yenduri@Sun.COM
5934373Skrishna kcf_do_notify(desc, B_FALSE);
5942800Skrishna
59510166SBhargava.Yenduri@Sun.COM mutex_enter(&prov_tab_mutex);
5969505SBhargava.Yenduri@Sun.COM /* Release reference held by kcf_prov_tab_lookup(). */
5979505SBhargava.Yenduri@Sun.COM KCF_PROV_REFRELE(desc);
5989505SBhargava.Yenduri@Sun.COM
5999505SBhargava.Yenduri@Sun.COM if (kcf_get_refcnt(desc, B_TRUE) == 0) {
60010166SBhargava.Yenduri@Sun.COM /* kcf_free_provider_desc drops prov_tab_mutex */
6010Sstevel@tonic-gate kcf_free_provider_desc(desc);
6020Sstevel@tonic-gate } else {
6039505SBhargava.Yenduri@Sun.COM ASSERT(desc->pd_prov_type != CRYPTO_SW_PROVIDER);
6049505SBhargava.Yenduri@Sun.COM /*
6059505SBhargava.Yenduri@Sun.COM * We could avoid this if /dev/crypto can proactively
6069505SBhargava.Yenduri@Sun.COM * remove any holds on us from a dormant PKCS #11 app.
60710166SBhargava.Yenduri@Sun.COM * For now, we check the provider table for
60810166SBhargava.Yenduri@Sun.COM * KCF_PROV_UNREGISTERED entries when a provider is
60910166SBhargava.Yenduri@Sun.COM * added to the table or when a provider is removed from it
61010166SBhargava.Yenduri@Sun.COM * and free them when refcnt reaches zero.
6119505SBhargava.Yenduri@Sun.COM */
6129505SBhargava.Yenduri@Sun.COM kcf_need_provtab_walk = B_TRUE;
6139505SBhargava.Yenduri@Sun.COM mutex_exit(&prov_tab_mutex);
6140Sstevel@tonic-gate }
6150Sstevel@tonic-gate
616*11751SAnthony.Scarpino@Sun.COM errormsg:
617*11751SAnthony.Scarpino@Sun.COM if (ret != CRYPTO_SUCCESS && sys_shutdown == 0) {
618*11751SAnthony.Scarpino@Sun.COM switch (ret) {
619*11751SAnthony.Scarpino@Sun.COM case CRYPTO_UNKNOWN_PROVIDER:
620*11751SAnthony.Scarpino@Sun.COM cmn_err(CE_WARN, "Unknown provider \"%s\" was "
621*11751SAnthony.Scarpino@Sun.COM "requested to unregister from the cryptographic "
622*11751SAnthony.Scarpino@Sun.COM "framework.", desc->pd_description);
623*11751SAnthony.Scarpino@Sun.COM break;
624*11751SAnthony.Scarpino@Sun.COM
625*11751SAnthony.Scarpino@Sun.COM case CRYPTO_BUSY:
626*11751SAnthony.Scarpino@Sun.COM cmn_err(CE_WARN, "%s could not be unregistered from "
627*11751SAnthony.Scarpino@Sun.COM "the Cryptographic Framework as it is busy.",
628*11751SAnthony.Scarpino@Sun.COM desc->pd_description);
629*11751SAnthony.Scarpino@Sun.COM break;
630*11751SAnthony.Scarpino@Sun.COM
631*11751SAnthony.Scarpino@Sun.COM default:
632*11751SAnthony.Scarpino@Sun.COM cmn_err(CE_WARN, "%s did not unregister with the "
633*11751SAnthony.Scarpino@Sun.COM "Cryptographic Framework. (0x%x)",
634*11751SAnthony.Scarpino@Sun.COM desc->pd_description, ret);
635*11751SAnthony.Scarpino@Sun.COM };
636*11751SAnthony.Scarpino@Sun.COM }
637*11751SAnthony.Scarpino@Sun.COM
638*11751SAnthony.Scarpino@Sun.COM return (ret);
6390Sstevel@tonic-gate }
6400Sstevel@tonic-gate
6410Sstevel@tonic-gate /*
6420Sstevel@tonic-gate * This routine is used to notify the framework that the state of
6430Sstevel@tonic-gate * a cryptographic provider has changed. Valid state codes are:
6440Sstevel@tonic-gate *
6450Sstevel@tonic-gate * CRYPTO_PROVIDER_READY
6460Sstevel@tonic-gate * The provider indicates that it can process more requests. A provider
6470Sstevel@tonic-gate * will notify with this event if it previously has notified us with a
6480Sstevel@tonic-gate * CRYPTO_PROVIDER_BUSY.
6490Sstevel@tonic-gate *
6500Sstevel@tonic-gate * CRYPTO_PROVIDER_BUSY
6510Sstevel@tonic-gate * The provider can not take more requests.
6520Sstevel@tonic-gate *
6530Sstevel@tonic-gate * CRYPTO_PROVIDER_FAILED
6540Sstevel@tonic-gate * The provider encountered an internal error. The framework will not
6550Sstevel@tonic-gate * be sending any more requests to the provider. The provider may notify
6560Sstevel@tonic-gate * with a CRYPTO_PROVIDER_READY, if it is able to recover from the error.
6570Sstevel@tonic-gate *
6580Sstevel@tonic-gate * This routine can be called from user or interrupt context.
6590Sstevel@tonic-gate */
6600Sstevel@tonic-gate void
crypto_provider_notification(crypto_kcf_provider_handle_t handle,uint_t state)6610Sstevel@tonic-gate crypto_provider_notification(crypto_kcf_provider_handle_t handle, uint_t state)
6620Sstevel@tonic-gate {
6630Sstevel@tonic-gate kcf_provider_desc_t *pd;
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate /* lookup the provider from the given handle */
6660Sstevel@tonic-gate if ((pd = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
6670Sstevel@tonic-gate return;
6680Sstevel@tonic-gate
6690Sstevel@tonic-gate mutex_enter(&pd->pd_lock);
6700Sstevel@tonic-gate
6714373Skrishna if (pd->pd_state <= KCF_PROV_VERIFICATION_FAILED)
6724373Skrishna goto out;
6734373Skrishna
6740Sstevel@tonic-gate if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
6750Sstevel@tonic-gate cmn_err(CE_WARN, "crypto_provider_notification: "
6760Sstevel@tonic-gate "logical provider (%x) ignored\n", handle);
6770Sstevel@tonic-gate goto out;
6780Sstevel@tonic-gate }
6790Sstevel@tonic-gate switch (state) {
6800Sstevel@tonic-gate case CRYPTO_PROVIDER_READY:
6810Sstevel@tonic-gate switch (pd->pd_state) {
6820Sstevel@tonic-gate case KCF_PROV_BUSY:
6830Sstevel@tonic-gate pd->pd_state = KCF_PROV_READY;
6840Sstevel@tonic-gate /*
6854912Skrishna * Signal the per-provider taskq threads that they
6864912Skrishna * can start submitting requests.
6870Sstevel@tonic-gate */
6884912Skrishna cv_broadcast(&pd->pd_resume_cv);
6890Sstevel@tonic-gate break;
6900Sstevel@tonic-gate
6910Sstevel@tonic-gate case KCF_PROV_FAILED:
6920Sstevel@tonic-gate /*
6930Sstevel@tonic-gate * The provider recovered from the error. Let us
6940Sstevel@tonic-gate * use it now.
6950Sstevel@tonic-gate */
6960Sstevel@tonic-gate pd->pd_state = KCF_PROV_READY;
6970Sstevel@tonic-gate break;
6980Sstevel@tonic-gate }
6990Sstevel@tonic-gate break;
7000Sstevel@tonic-gate
7010Sstevel@tonic-gate case CRYPTO_PROVIDER_BUSY:
7020Sstevel@tonic-gate switch (pd->pd_state) {
7030Sstevel@tonic-gate case KCF_PROV_READY:
7040Sstevel@tonic-gate pd->pd_state = KCF_PROV_BUSY;
7050Sstevel@tonic-gate break;
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate break;
7080Sstevel@tonic-gate
7090Sstevel@tonic-gate case CRYPTO_PROVIDER_FAILED:
7100Sstevel@tonic-gate /*
7110Sstevel@tonic-gate * We note the failure and return. The per-provider taskq
7124912Skrishna * threads check this flag and start failing the
7130Sstevel@tonic-gate * requests, if it is set. See process_req_hwp() for details.
7140Sstevel@tonic-gate */
7150Sstevel@tonic-gate switch (pd->pd_state) {
7160Sstevel@tonic-gate case KCF_PROV_READY:
7170Sstevel@tonic-gate pd->pd_state = KCF_PROV_FAILED;
7180Sstevel@tonic-gate break;
7190Sstevel@tonic-gate
7200Sstevel@tonic-gate case KCF_PROV_BUSY:
7210Sstevel@tonic-gate pd->pd_state = KCF_PROV_FAILED;
7220Sstevel@tonic-gate /*
7234912Skrishna * The per-provider taskq threads may be waiting. We
7244912Skrishna * signal them so that they can start failing requests.
7250Sstevel@tonic-gate */
7264912Skrishna cv_broadcast(&pd->pd_resume_cv);
7270Sstevel@tonic-gate break;
7280Sstevel@tonic-gate }
7290Sstevel@tonic-gate break;
7300Sstevel@tonic-gate }
7310Sstevel@tonic-gate out:
7320Sstevel@tonic-gate mutex_exit(&pd->pd_lock);
7330Sstevel@tonic-gate KCF_PROV_REFRELE(pd);
7340Sstevel@tonic-gate }
7350Sstevel@tonic-gate
7360Sstevel@tonic-gate /*
7370Sstevel@tonic-gate * This routine is used to notify the framework the result of
7380Sstevel@tonic-gate * an asynchronous request handled by a provider. Valid error
7390Sstevel@tonic-gate * codes are the same as the CRYPTO_* errors defined in common.h.
7400Sstevel@tonic-gate *
7410Sstevel@tonic-gate * This routine can be called from user or interrupt context.
7420Sstevel@tonic-gate */
7430Sstevel@tonic-gate void
crypto_op_notification(crypto_req_handle_t handle,int error)7440Sstevel@tonic-gate crypto_op_notification(crypto_req_handle_t handle, int error)
7450Sstevel@tonic-gate {
7460Sstevel@tonic-gate kcf_call_type_t ctype;
7470Sstevel@tonic-gate
7488384SBhargava.Yenduri@Sun.COM if (handle == NULL)
7498384SBhargava.Yenduri@Sun.COM return;
7508384SBhargava.Yenduri@Sun.COM
7510Sstevel@tonic-gate if ((ctype = GET_REQ_TYPE(handle)) == CRYPTO_SYNCH) {
7520Sstevel@tonic-gate kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)handle;
7530Sstevel@tonic-gate
7549505SBhargava.Yenduri@Sun.COM KCF_PROV_JOB_RELE_STAT(sreq->sn_mp, (error != CRYPTO_SUCCESS));
7550Sstevel@tonic-gate kcf_sop_done(sreq, error);
7560Sstevel@tonic-gate } else {
7570Sstevel@tonic-gate kcf_areq_node_t *areq = (kcf_areq_node_t *)handle;
7580Sstevel@tonic-gate
7590Sstevel@tonic-gate ASSERT(ctype == CRYPTO_ASYNCH);
7609505SBhargava.Yenduri@Sun.COM KCF_PROV_JOB_RELE_STAT(areq->an_mp, (error != CRYPTO_SUCCESS));
7610Sstevel@tonic-gate kcf_aop_done(areq, error);
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate }
7640Sstevel@tonic-gate
7650Sstevel@tonic-gate /*
7660Sstevel@tonic-gate * This routine is used by software providers to determine
7670Sstevel@tonic-gate * whether to use KM_SLEEP or KM_NOSLEEP during memory allocation.
7680Sstevel@tonic-gate * Note that hardware providers can always use KM_SLEEP. So,
7690Sstevel@tonic-gate * they do not need to call this routine.
7700Sstevel@tonic-gate *
7710Sstevel@tonic-gate * This routine can be called from user or interrupt context.
7720Sstevel@tonic-gate */
7730Sstevel@tonic-gate int
crypto_kmflag(crypto_req_handle_t handle)7740Sstevel@tonic-gate crypto_kmflag(crypto_req_handle_t handle)
7750Sstevel@tonic-gate {
7760Sstevel@tonic-gate return (REQHNDL2_KMFLAG(handle));
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate
7790Sstevel@tonic-gate /*
7800Sstevel@tonic-gate * Process the mechanism info structures specified by the provider
7810Sstevel@tonic-gate * during registration. A NULL crypto_provider_info_t indicates
7820Sstevel@tonic-gate * an already initialized provider descriptor.
7830Sstevel@tonic-gate *
7840Sstevel@tonic-gate * Mechanisms are not added to the kernel's mechanism table if the
7850Sstevel@tonic-gate * provider is a logical provider.
7860Sstevel@tonic-gate *
7870Sstevel@tonic-gate * Returns CRYPTO_SUCCESS on success, CRYPTO_ARGUMENTS if one
7880Sstevel@tonic-gate * of the specified mechanisms was malformed, or CRYPTO_HOST_MEMORY
7890Sstevel@tonic-gate * if the table of mechanisms is full.
7900Sstevel@tonic-gate */
7910Sstevel@tonic-gate static int
init_prov_mechs(crypto_provider_info_t * info,kcf_provider_desc_t * desc)7920Sstevel@tonic-gate init_prov_mechs(crypto_provider_info_t *info, kcf_provider_desc_t *desc)
7930Sstevel@tonic-gate {
7940Sstevel@tonic-gate uint_t mech_idx;
7950Sstevel@tonic-gate uint_t cleanup_idx;
7960Sstevel@tonic-gate int err = CRYPTO_SUCCESS;
7970Sstevel@tonic-gate kcf_prov_mech_desc_t *pmd;
7980Sstevel@tonic-gate int desc_use_count = 0;
7990Sstevel@tonic-gate int mcount = desc->pd_mech_list_count;
8000Sstevel@tonic-gate
8010Sstevel@tonic-gate if (desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
8020Sstevel@tonic-gate if (info != NULL) {
8030Sstevel@tonic-gate ASSERT(info->pi_mechanisms != NULL);
8040Sstevel@tonic-gate bcopy(info->pi_mechanisms, desc->pd_mechanisms,
8050Sstevel@tonic-gate sizeof (crypto_mech_info_t) * mcount);
8060Sstevel@tonic-gate }
8070Sstevel@tonic-gate return (CRYPTO_SUCCESS);
8080Sstevel@tonic-gate }
8090Sstevel@tonic-gate
8100Sstevel@tonic-gate /*
8110Sstevel@tonic-gate * Copy the mechanism list from the provider info to the provider
8120Sstevel@tonic-gate * descriptor. desc->pd_mechanisms has an extra crypto_mech_info_t
8130Sstevel@tonic-gate * element if the provider has random_ops since we keep an internal
8140Sstevel@tonic-gate * mechanism, SUN_RANDOM, in this case.
8150Sstevel@tonic-gate */
8160Sstevel@tonic-gate if (info != NULL) {
817904Smcpowers if (info->pi_ops_vector->co_random_ops != NULL) {
8180Sstevel@tonic-gate crypto_mech_info_t *rand_mi;
8190Sstevel@tonic-gate
8200Sstevel@tonic-gate /*
8210Sstevel@tonic-gate * Need the following check as it is possible to have
8220Sstevel@tonic-gate * a provider that implements just random_ops and has
8230Sstevel@tonic-gate * pi_mechanisms == NULL.
8240Sstevel@tonic-gate */
8250Sstevel@tonic-gate if (info->pi_mechanisms != NULL) {
8260Sstevel@tonic-gate bcopy(info->pi_mechanisms, desc->pd_mechanisms,
8270Sstevel@tonic-gate sizeof (crypto_mech_info_t) * (mcount - 1));
8280Sstevel@tonic-gate }
8290Sstevel@tonic-gate rand_mi = &desc->pd_mechanisms[mcount - 1];
8300Sstevel@tonic-gate
8310Sstevel@tonic-gate bzero(rand_mi, sizeof (crypto_mech_info_t));
8320Sstevel@tonic-gate (void) strncpy(rand_mi->cm_mech_name, SUN_RANDOM,
8330Sstevel@tonic-gate CRYPTO_MAX_MECH_NAME);
8340Sstevel@tonic-gate rand_mi->cm_func_group_mask = CRYPTO_FG_RANDOM;
8350Sstevel@tonic-gate } else {
8360Sstevel@tonic-gate ASSERT(info->pi_mechanisms != NULL);
8370Sstevel@tonic-gate bcopy(info->pi_mechanisms, desc->pd_mechanisms,
8380Sstevel@tonic-gate sizeof (crypto_mech_info_t) * mcount);
8390Sstevel@tonic-gate }
8400Sstevel@tonic-gate }
8410Sstevel@tonic-gate
8420Sstevel@tonic-gate /*
8430Sstevel@tonic-gate * For each mechanism support by the provider, add the provider
8440Sstevel@tonic-gate * to the corresponding KCF mechanism mech_entry chain.
8450Sstevel@tonic-gate */
8460Sstevel@tonic-gate for (mech_idx = 0; mech_idx < desc->pd_mech_list_count; mech_idx++) {
8470Sstevel@tonic-gate crypto_mech_info_t *mi = &desc->pd_mechanisms[mech_idx];
8480Sstevel@tonic-gate
8493708Skrishna if ((mi->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BITS) &&
8503708Skrishna (mi->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BYTES)) {
8510Sstevel@tonic-gate err = CRYPTO_ARGUMENTS_BAD;
8520Sstevel@tonic-gate break;
8530Sstevel@tonic-gate }
8540Sstevel@tonic-gate
8558384SBhargava.Yenduri@Sun.COM if ((err = kcf_add_mech_provider(mech_idx, desc, &pmd)) !=
8568384SBhargava.Yenduri@Sun.COM KCF_SUCCESS)
8570Sstevel@tonic-gate break;
8580Sstevel@tonic-gate
8590Sstevel@tonic-gate if (pmd == NULL)
8600Sstevel@tonic-gate continue;
8610Sstevel@tonic-gate
8620Sstevel@tonic-gate /* The provider will be used for this mechanism */
8630Sstevel@tonic-gate desc_use_count++;
8640Sstevel@tonic-gate }
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate /*
8672817Smcpowers * Don't allow multiple software providers with disabled mechanisms
8682817Smcpowers * to register. Subsequent enabling of mechanisms will result in
8692817Smcpowers * an unsupported configuration, i.e. multiple software providers
8702817Smcpowers * per mechanism.
8710Sstevel@tonic-gate */
8722817Smcpowers if (desc_use_count == 0 && desc->pd_prov_type == CRYPTO_SW_PROVIDER)
8730Sstevel@tonic-gate return (CRYPTO_ARGUMENTS_BAD);
8740Sstevel@tonic-gate
8750Sstevel@tonic-gate if (err == KCF_SUCCESS)
8760Sstevel@tonic-gate return (CRYPTO_SUCCESS);
8770Sstevel@tonic-gate
8780Sstevel@tonic-gate /*
8790Sstevel@tonic-gate * An error occurred while adding the mechanism, cleanup
8800Sstevel@tonic-gate * and bail.
8810Sstevel@tonic-gate */
8820Sstevel@tonic-gate for (cleanup_idx = 0; cleanup_idx < mech_idx; cleanup_idx++) {
8830Sstevel@tonic-gate kcf_remove_mech_provider(
8840Sstevel@tonic-gate desc->pd_mechanisms[cleanup_idx].cm_mech_name, desc);
8850Sstevel@tonic-gate }
8860Sstevel@tonic-gate
8870Sstevel@tonic-gate if (err == KCF_MECH_TAB_FULL)
8880Sstevel@tonic-gate return (CRYPTO_HOST_MEMORY);
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate return (CRYPTO_ARGUMENTS_BAD);
8910Sstevel@tonic-gate }
8920Sstevel@tonic-gate
8930Sstevel@tonic-gate /*
8940Sstevel@tonic-gate * Update routine for kstat. Only privileged users are allowed to
8950Sstevel@tonic-gate * access this information, since this information is sensitive.
8960Sstevel@tonic-gate * There are some cryptographic attacks (e.g. traffic analysis)
8970Sstevel@tonic-gate * which can use this information.
8980Sstevel@tonic-gate */
8990Sstevel@tonic-gate static int
kcf_prov_kstat_update(kstat_t * ksp,int rw)9000Sstevel@tonic-gate kcf_prov_kstat_update(kstat_t *ksp, int rw)
9010Sstevel@tonic-gate {
9020Sstevel@tonic-gate kcf_prov_stats_t *ks_data;
9030Sstevel@tonic-gate kcf_provider_desc_t *pd = (kcf_provider_desc_t *)ksp->ks_private;
9049505SBhargava.Yenduri@Sun.COM int i;
9050Sstevel@tonic-gate
9060Sstevel@tonic-gate if (rw == KSTAT_WRITE)
9070Sstevel@tonic-gate return (EACCES);
9080Sstevel@tonic-gate
9090Sstevel@tonic-gate ks_data = ksp->ks_data;
9100Sstevel@tonic-gate
9110Sstevel@tonic-gate if (secpolicy_sys_config(CRED(), B_TRUE) != 0) {
9120Sstevel@tonic-gate ks_data->ps_ops_total.value.ui64 = 0;
9130Sstevel@tonic-gate ks_data->ps_ops_passed.value.ui64 = 0;
9140Sstevel@tonic-gate ks_data->ps_ops_failed.value.ui64 = 0;
9150Sstevel@tonic-gate ks_data->ps_ops_busy_rval.value.ui64 = 0;
9160Sstevel@tonic-gate } else {
9179505SBhargava.Yenduri@Sun.COM uint64_t dtotal, ftotal, btotal;
9189505SBhargava.Yenduri@Sun.COM
9199505SBhargava.Yenduri@Sun.COM dtotal = ftotal = btotal = 0;
9209505SBhargava.Yenduri@Sun.COM /* No locking done since an exact count is not required. */
9219505SBhargava.Yenduri@Sun.COM for (i = 0; i < pd->pd_nbins; i++) {
9229505SBhargava.Yenduri@Sun.COM dtotal += pd->pd_percpu_bins[i].kp_ndispatches;
9239505SBhargava.Yenduri@Sun.COM ftotal += pd->pd_percpu_bins[i].kp_nfails;
9249505SBhargava.Yenduri@Sun.COM btotal += pd->pd_percpu_bins[i].kp_nbusy_rval;
9259505SBhargava.Yenduri@Sun.COM }
9269505SBhargava.Yenduri@Sun.COM
9279505SBhargava.Yenduri@Sun.COM ks_data->ps_ops_total.value.ui64 = dtotal;
9289505SBhargava.Yenduri@Sun.COM ks_data->ps_ops_failed.value.ui64 = ftotal;
9299505SBhargava.Yenduri@Sun.COM ks_data->ps_ops_busy_rval.value.ui64 = btotal;
9309505SBhargava.Yenduri@Sun.COM ks_data->ps_ops_passed.value.ui64 = dtotal - ftotal - btotal;
9310Sstevel@tonic-gate }
9320Sstevel@tonic-gate
9330Sstevel@tonic-gate return (0);
9340Sstevel@tonic-gate }
9350Sstevel@tonic-gate
9360Sstevel@tonic-gate
9370Sstevel@tonic-gate /*
9380Sstevel@tonic-gate * Utility routine called from failure paths in crypto_register_provider()
9390Sstevel@tonic-gate * and from crypto_load_soft_disabled().
9400Sstevel@tonic-gate */
9410Sstevel@tonic-gate void
undo_register_provider(kcf_provider_desc_t * desc,boolean_t remove_prov)9420Sstevel@tonic-gate undo_register_provider(kcf_provider_desc_t *desc, boolean_t remove_prov)
9430Sstevel@tonic-gate {
9440Sstevel@tonic-gate uint_t mech_idx;
9450Sstevel@tonic-gate
9460Sstevel@tonic-gate /* remove the provider from the mechanisms tables */
9470Sstevel@tonic-gate for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
9480Sstevel@tonic-gate mech_idx++) {
9490Sstevel@tonic-gate kcf_remove_mech_provider(
9500Sstevel@tonic-gate desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
9510Sstevel@tonic-gate }
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate /* remove provider from providers table */
9540Sstevel@tonic-gate if (remove_prov)
9550Sstevel@tonic-gate (void) kcf_prov_tab_rem_provider(desc->pd_prov_id);
9560Sstevel@tonic-gate }
9570Sstevel@tonic-gate
9584373Skrishna static void
undo_register_provider_extra(kcf_provider_desc_t * desc)9594373Skrishna undo_register_provider_extra(kcf_provider_desc_t *desc)
9604373Skrishna {
9614373Skrishna delete_kstat(desc);
9624373Skrishna undo_register_provider(desc, B_TRUE);
9634373Skrishna }
9644373Skrishna
9650Sstevel@tonic-gate /*
9660Sstevel@tonic-gate * Utility routine called from crypto_load_soft_disabled(). Callers
9670Sstevel@tonic-gate * should have done a prior undo_register_provider().
9680Sstevel@tonic-gate */
9690Sstevel@tonic-gate void
redo_register_provider(kcf_provider_desc_t * pd)9700Sstevel@tonic-gate redo_register_provider(kcf_provider_desc_t *pd)
9710Sstevel@tonic-gate {
9720Sstevel@tonic-gate /* process the mechanisms supported by the provider */
9730Sstevel@tonic-gate (void) init_prov_mechs(NULL, pd);
9740Sstevel@tonic-gate
9750Sstevel@tonic-gate /*
9760Sstevel@tonic-gate * Hold provider in providers table. We should not call
9770Sstevel@tonic-gate * kcf_prov_tab_add_provider() here as the provider descriptor
9780Sstevel@tonic-gate * is still valid which means it has an entry in the provider
9790Sstevel@tonic-gate * table.
9800Sstevel@tonic-gate */
9810Sstevel@tonic-gate KCF_PROV_REFHOLD(pd);
9820Sstevel@tonic-gate }
9830Sstevel@tonic-gate
9840Sstevel@tonic-gate /*
9850Sstevel@tonic-gate * Add provider (p1) to another provider's array of providers (p2).
9860Sstevel@tonic-gate * Hardware and logical providers use this array to cross-reference
9870Sstevel@tonic-gate * each other.
9880Sstevel@tonic-gate */
9890Sstevel@tonic-gate static void
add_provider_to_array(kcf_provider_desc_t * p1,kcf_provider_desc_t * p2)9900Sstevel@tonic-gate add_provider_to_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
9910Sstevel@tonic-gate {
9920Sstevel@tonic-gate kcf_provider_list_t *new;
9930Sstevel@tonic-gate
9940Sstevel@tonic-gate new = kmem_alloc(sizeof (kcf_provider_list_t), KM_SLEEP);
9950Sstevel@tonic-gate mutex_enter(&p2->pd_lock);
9960Sstevel@tonic-gate new->pl_next = p2->pd_provider_list;
9970Sstevel@tonic-gate p2->pd_provider_list = new;
9980Sstevel@tonic-gate new->pl_provider = p1;
9990Sstevel@tonic-gate mutex_exit(&p2->pd_lock);
10000Sstevel@tonic-gate }
10010Sstevel@tonic-gate
10020Sstevel@tonic-gate /*
10030Sstevel@tonic-gate * Remove provider (p1) from another provider's array of providers (p2).
10040Sstevel@tonic-gate * Hardware and logical providers use this array to cross-reference
10050Sstevel@tonic-gate * each other.
10060Sstevel@tonic-gate */
10070Sstevel@tonic-gate static void
remove_provider_from_array(kcf_provider_desc_t * p1,kcf_provider_desc_t * p2)10080Sstevel@tonic-gate remove_provider_from_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
10090Sstevel@tonic-gate {
10100Sstevel@tonic-gate
10110Sstevel@tonic-gate kcf_provider_list_t *pl = NULL, **prev;
10120Sstevel@tonic-gate
10130Sstevel@tonic-gate mutex_enter(&p2->pd_lock);
10140Sstevel@tonic-gate for (pl = p2->pd_provider_list, prev = &p2->pd_provider_list;
10150Sstevel@tonic-gate pl != NULL; prev = &pl->pl_next, pl = pl->pl_next) {
10160Sstevel@tonic-gate if (pl->pl_provider == p1) {
10170Sstevel@tonic-gate break;
10180Sstevel@tonic-gate }
10190Sstevel@tonic-gate }
10200Sstevel@tonic-gate
10210Sstevel@tonic-gate if (p1 == NULL) {
10220Sstevel@tonic-gate mutex_exit(&p2->pd_lock);
10230Sstevel@tonic-gate return;
10240Sstevel@tonic-gate }
10250Sstevel@tonic-gate
10260Sstevel@tonic-gate /* detach and free kcf_provider_list structure */
10270Sstevel@tonic-gate *prev = pl->pl_next;
10280Sstevel@tonic-gate kmem_free(pl, sizeof (*pl));
10290Sstevel@tonic-gate mutex_exit(&p2->pd_lock);
10300Sstevel@tonic-gate }
10310Sstevel@tonic-gate
10320Sstevel@tonic-gate /*
10330Sstevel@tonic-gate * Convert an array of logical provider handles (crypto_provider_id)
10340Sstevel@tonic-gate * stored in a crypto_provider_info structure into an array of provider
10350Sstevel@tonic-gate * descriptors (kcf_provider_desc_t) attached to a logical provider.
10360Sstevel@tonic-gate */
10370Sstevel@tonic-gate static void
process_logical_providers(crypto_provider_info_t * info,kcf_provider_desc_t * hp)10380Sstevel@tonic-gate process_logical_providers(crypto_provider_info_t *info, kcf_provider_desc_t *hp)
10390Sstevel@tonic-gate {
10400Sstevel@tonic-gate kcf_provider_desc_t *lp;
10410Sstevel@tonic-gate crypto_provider_id_t handle;
10420Sstevel@tonic-gate int count = info->pi_logical_provider_count;
10430Sstevel@tonic-gate int i;
10440Sstevel@tonic-gate
10450Sstevel@tonic-gate /* add hardware provider to each logical provider */
10460Sstevel@tonic-gate for (i = 0; i < count; i++) {
10470Sstevel@tonic-gate handle = info->pi_logical_providers[i];
10480Sstevel@tonic-gate lp = kcf_prov_tab_lookup((crypto_provider_id_t)handle);
10490Sstevel@tonic-gate if (lp == NULL) {
10500Sstevel@tonic-gate continue;
10510Sstevel@tonic-gate }
10520Sstevel@tonic-gate add_provider_to_array(hp, lp);
10532800Skrishna hp->pd_flags |= KCF_LPROV_MEMBER;
10540Sstevel@tonic-gate
10550Sstevel@tonic-gate /*
10560Sstevel@tonic-gate * A hardware provider has to have the provider descriptor of
10570Sstevel@tonic-gate * every logical provider it belongs to, so it can be removed
10580Sstevel@tonic-gate * from the logical provider if the hardware provider
10590Sstevel@tonic-gate * unregisters from the framework.
10600Sstevel@tonic-gate */
10610Sstevel@tonic-gate add_provider_to_array(lp, hp);
10620Sstevel@tonic-gate KCF_PROV_REFRELE(lp);
10630Sstevel@tonic-gate }
10640Sstevel@tonic-gate }
10650Sstevel@tonic-gate
10660Sstevel@tonic-gate /*
10670Sstevel@tonic-gate * This routine removes a provider from all of the logical or
10680Sstevel@tonic-gate * hardware providers it belongs to, and frees the provider's
10690Sstevel@tonic-gate * array of pointers to providers.
10700Sstevel@tonic-gate */
10710Sstevel@tonic-gate static void
remove_provider(kcf_provider_desc_t * pp)10720Sstevel@tonic-gate remove_provider(kcf_provider_desc_t *pp)
10730Sstevel@tonic-gate {
10740Sstevel@tonic-gate kcf_provider_desc_t *p;
10750Sstevel@tonic-gate kcf_provider_list_t *e, *next;
10760Sstevel@tonic-gate
10770Sstevel@tonic-gate mutex_enter(&pp->pd_lock);
10780Sstevel@tonic-gate for (e = pp->pd_provider_list; e != NULL; e = next) {
10790Sstevel@tonic-gate p = e->pl_provider;
10800Sstevel@tonic-gate remove_provider_from_array(pp, p);
10812800Skrishna if (p->pd_prov_type == CRYPTO_HW_PROVIDER &&
10822800Skrishna p->pd_provider_list == NULL)
10832800Skrishna p->pd_flags &= ~KCF_LPROV_MEMBER;
10840Sstevel@tonic-gate next = e->pl_next;
10850Sstevel@tonic-gate kmem_free(e, sizeof (*e));
10860Sstevel@tonic-gate }
10870Sstevel@tonic-gate pp->pd_provider_list = NULL;
10880Sstevel@tonic-gate mutex_exit(&pp->pd_lock);
10890Sstevel@tonic-gate }
10904373Skrishna
10914373Skrishna /*
10924373Skrishna * Dispatch events as needed for a provider. is_added flag tells
10934373Skrishna * whether the provider is registering or unregistering.
10944373Skrishna */
10954373Skrishna void
kcf_do_notify(kcf_provider_desc_t * prov_desc,boolean_t is_added)10964373Skrishna kcf_do_notify(kcf_provider_desc_t *prov_desc, boolean_t is_added)
10974373Skrishna {
10984373Skrishna int i;
10994373Skrishna crypto_notify_event_change_t ec;
11004373Skrishna
11014373Skrishna ASSERT(prov_desc->pd_state > KCF_PROV_VERIFICATION_FAILED);
11024373Skrishna
11034373Skrishna /*
11044373Skrishna * Inform interested clients of the mechanisms becoming
11054373Skrishna * available/unavailable. We skip this for logical providers
11064373Skrishna * as they do not affect mechanisms.
11074373Skrishna */
11084373Skrishna if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
11094373Skrishna ec.ec_provider_type = prov_desc->pd_prov_type;
11104373Skrishna ec.ec_change = is_added ? CRYPTO_MECH_ADDED :
11114373Skrishna CRYPTO_MECH_REMOVED;
11124373Skrishna for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
11134373Skrishna /* Skip any mechanisms not allowed by the policy */
11144373Skrishna if (is_mech_disabled(prov_desc,
11154373Skrishna prov_desc->pd_mechanisms[i].cm_mech_name))
11164373Skrishna continue;
11174373Skrishna
11184373Skrishna (void) strncpy(ec.ec_mech_name,
11194373Skrishna prov_desc->pd_mechanisms[i].cm_mech_name,
11204373Skrishna CRYPTO_MAX_MECH_NAME);
11214373Skrishna kcf_walk_ntfylist(CRYPTO_EVENT_MECHS_CHANGED, &ec);
11224373Skrishna }
11234373Skrishna
11244373Skrishna }
11254373Skrishna
11264373Skrishna /*
11274373Skrishna * Inform interested clients about the new or departing provider.
11284373Skrishna * In case of a logical provider, we need to notify the event only
11294373Skrishna * for the logical provider and not for the underlying
11304373Skrishna * providers which are known by the KCF_LPROV_MEMBER bit.
11314373Skrishna */
11324373Skrishna if (prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER ||
11334373Skrishna (prov_desc->pd_flags & KCF_LPROV_MEMBER) == 0) {
11344373Skrishna kcf_walk_ntfylist(is_added ? CRYPTO_EVENT_PROVIDER_REGISTERED :
11354373Skrishna CRYPTO_EVENT_PROVIDER_UNREGISTERED, prov_desc);
11364373Skrishna }
11374373Skrishna }
11384373Skrishna
11394373Skrishna static void
delete_kstat(kcf_provider_desc_t * desc)11404373Skrishna delete_kstat(kcf_provider_desc_t *desc)
11414373Skrishna {
11424373Skrishna /* destroy the kstat created for this provider */
11434373Skrishna if (desc->pd_kstat != NULL) {
11444373Skrishna kcf_provider_desc_t *kspd = desc->pd_kstat->ks_private;
11454373Skrishna
11464373Skrishna /* release reference held by desc->pd_kstat->ks_private */
11474373Skrishna ASSERT(desc == kspd);
11484373Skrishna kstat_delete(kspd->pd_kstat);
11494373Skrishna desc->pd_kstat = NULL;
11504373Skrishna KCF_PROV_REFRELE(kspd);
11514373Skrishna }
11524373Skrishna }
1153