4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or https://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * This file is part of the core Kernel Cryptographic Framework.
28 * It implements the SPI functions exported to cryptographic
33 #include <sys/zfs_context.h>
34 #include <sys/crypto/common.h>
35 #include <sys/crypto/impl.h>
36 #include <sys/crypto/sched_impl.h>
37 #include <sys/crypto/spi.h>
39 static int init_prov_mechs(const crypto_provider_info_t
*,
40 kcf_provider_desc_t
*);
43 * This routine is used to add cryptographic providers to the KEF framework.
44 * Providers pass a crypto_provider_info structure to crypto_register_provider()
45 * and get back a handle. The crypto_provider_info structure contains a
46 * list of mechanisms supported by the provider and an ops vector containing
47 * provider entry points. Providers call this routine in their _init() routine.
50 crypto_register_provider(const crypto_provider_info_t
*info
,
51 crypto_kcf_provider_handle_t
*handle
)
53 kcf_provider_desc_t
*prov_desc
= NULL
;
54 int ret
= CRYPTO_ARGUMENTS_BAD
;
57 * Allocate and initialize a new provider descriptor. We also
58 * hold it and release it when done.
60 prov_desc
= kcf_alloc_provider_desc();
61 KCF_PROV_REFHOLD(prov_desc
);
63 /* copy provider description string */
64 prov_desc
->pd_description
= info
->pi_provider_description
;
66 /* Change from Illumos: the ops vector is persistent. */
67 prov_desc
->pd_ops_vector
= info
->pi_ops_vector
;
69 /* process the mechanisms supported by the provider */
70 if ((ret
= init_prov_mechs(info
, prov_desc
)) != CRYPTO_SUCCESS
)
74 * Add provider to providers tables, also sets the descriptor
77 if ((ret
= kcf_prov_tab_add_provider(prov_desc
)) != CRYPTO_SUCCESS
) {
78 undo_register_provider(prov_desc
, B_FALSE
);
83 * The global queue is used for providers. We handle ordering
84 * of multi-part requests in the taskq routine. So, it is safe to
85 * have multiple threads for the taskq. We pass TASKQ_PREPOPULATE flag
86 * to keep some entries cached to improve performance.
89 mutex_enter(&prov_desc
->pd_lock
);
90 prov_desc
->pd_state
= KCF_PROV_READY
;
91 mutex_exit(&prov_desc
->pd_lock
);
93 *handle
= prov_desc
->pd_kcf_prov_handle
;
97 KCF_PROV_REFRELE(prov_desc
);
102 * This routine is used to notify the framework when a provider is being
103 * removed. Providers call this routine in their _fini() routine.
106 crypto_unregister_provider(crypto_kcf_provider_handle_t handle
)
109 kcf_provider_desc_t
*desc
;
110 kcf_prov_state_t saved_state
;
112 /* lookup provider descriptor */
113 if ((desc
= kcf_prov_tab_lookup((crypto_provider_id_t
)handle
)) == NULL
)
114 return (CRYPTO_UNKNOWN_PROVIDER
);
116 mutex_enter(&desc
->pd_lock
);
118 * Check if any other thread is disabling or removing
119 * this provider. We return if this is the case.
121 if (desc
->pd_state
>= KCF_PROV_DISABLED
) {
122 mutex_exit(&desc
->pd_lock
);
123 /* Release reference held by kcf_prov_tab_lookup(). */
124 KCF_PROV_REFRELE(desc
);
125 return (CRYPTO_BUSY
);
128 saved_state
= desc
->pd_state
;
129 desc
->pd_state
= KCF_PROV_REMOVED
;
132 * Check if this provider is currently being used.
133 * pd_irefcnt is the number of holds from the internal
134 * structures. We add one to account for the above lookup.
136 if (desc
->pd_refcnt
> desc
->pd_irefcnt
+ 1) {
137 desc
->pd_state
= saved_state
;
138 mutex_exit(&desc
->pd_lock
);
139 /* Release reference held by kcf_prov_tab_lookup(). */
140 KCF_PROV_REFRELE(desc
);
142 * The administrator will presumably stop the clients,
143 * thus removing the holds, when they get the busy
144 * return value. Any retry will succeed then.
146 return (CRYPTO_BUSY
);
148 mutex_exit(&desc
->pd_lock
);
150 /* remove the provider from the mechanisms tables */
151 for (mech_idx
= 0; mech_idx
< desc
->pd_mech_list_count
;
153 kcf_remove_mech_provider(
154 desc
->pd_mechanisms
[mech_idx
].cm_mech_name
, desc
);
157 /* remove provider from providers table */
158 if (kcf_prov_tab_rem_provider((crypto_provider_id_t
)handle
) !=
160 /* Release reference held by kcf_prov_tab_lookup(). */
161 KCF_PROV_REFRELE(desc
);
162 return (CRYPTO_UNKNOWN_PROVIDER
);
165 /* Release reference held by kcf_prov_tab_lookup(). */
166 KCF_PROV_REFRELE(desc
);
169 * Wait till the existing requests complete.
171 mutex_enter(&desc
->pd_lock
);
172 while (desc
->pd_state
!= KCF_PROV_FREED
)
173 cv_wait(&desc
->pd_remove_cv
, &desc
->pd_lock
);
174 mutex_exit(&desc
->pd_lock
);
177 * This is the only place where kcf_free_provider_desc()
178 * is called directly. KCF_PROV_REFRELE() should free the
179 * structure in all other places.
181 ASSERT(desc
->pd_state
== KCF_PROV_FREED
&&
182 desc
->pd_refcnt
== 0);
183 kcf_free_provider_desc(desc
);
185 return (CRYPTO_SUCCESS
);
189 * Process the mechanism info structures specified by the provider
190 * during registration. A NULL crypto_provider_info_t indicates
191 * an already initialized provider descriptor.
193 * Returns CRYPTO_SUCCESS on success, CRYPTO_ARGUMENTS if one
194 * of the specified mechanisms was malformed, or CRYPTO_HOST_MEMORY
195 * if the table of mechanisms is full.
198 init_prov_mechs(const crypto_provider_info_t
*info
, kcf_provider_desc_t
*desc
)
202 int err
= CRYPTO_SUCCESS
;
203 kcf_prov_mech_desc_t
*pmd
;
204 int desc_use_count
= 0;
207 * Copy the mechanism list from the provider info to the provider
208 * descriptor. desc->pd_mechanisms has an extra crypto_mech_info_t
209 * element if the provider has random_ops since we keep an internal
210 * mechanism, SUN_RANDOM, in this case.
213 ASSERT(info
->pi_mechanisms
!= NULL
);
214 desc
->pd_mech_list_count
= info
->pi_mech_list_count
;
215 desc
->pd_mechanisms
= info
->pi_mechanisms
;
219 * For each mechanism support by the provider, add the provider
220 * to the corresponding KCF mechanism mech_entry chain.
222 for (mech_idx
= 0; mech_idx
< desc
->pd_mech_list_count
; mech_idx
++) {
223 if ((err
= kcf_add_mech_provider(mech_idx
, desc
, &pmd
)) !=
230 /* The provider will be used for this mechanism */
235 * Don't allow multiple providers with disabled mechanisms
236 * to register. Subsequent enabling of mechanisms will result in
237 * an unsupported configuration, i.e. multiple providers
240 if (desc_use_count
== 0)
241 return (CRYPTO_ARGUMENTS_BAD
);
243 if (err
== KCF_SUCCESS
)
244 return (CRYPTO_SUCCESS
);
247 * An error occurred while adding the mechanism, cleanup
250 for (cleanup_idx
= 0; cleanup_idx
< mech_idx
; cleanup_idx
++) {
251 kcf_remove_mech_provider(
252 desc
->pd_mechanisms
[cleanup_idx
].cm_mech_name
, desc
);
255 if (err
== KCF_MECH_TAB_FULL
)
256 return (CRYPTO_HOST_MEMORY
);
258 return (CRYPTO_ARGUMENTS_BAD
);
262 * Utility routine called from failure paths in crypto_register_provider()
263 * and from crypto_load_soft_disabled().
266 undo_register_provider(kcf_provider_desc_t
*desc
, boolean_t remove_prov
)
270 /* remove the provider from the mechanisms tables */
271 for (mech_idx
= 0; mech_idx
< desc
->pd_mech_list_count
;
273 kcf_remove_mech_provider(
274 desc
->pd_mechanisms
[mech_idx
].cm_mech_name
, desc
);
277 /* remove provider from providers table */
279 (void) kcf_prov_tab_rem_provider(desc
->pd_prov_id
);