1eda14cbcSMatt Macy /*
2eda14cbcSMatt Macy * CDDL HEADER START
3eda14cbcSMatt Macy *
4eda14cbcSMatt Macy * The contents of this file are subject to the terms of the
5eda14cbcSMatt Macy * Common Development and Distribution License (the "License").
6eda14cbcSMatt Macy * You may not use this file except in compliance with the License.
7eda14cbcSMatt Macy *
8eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0.
10eda14cbcSMatt Macy * See the License for the specific language governing permissions
11eda14cbcSMatt Macy * and limitations under the License.
12eda14cbcSMatt Macy *
13eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each
14eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the
16eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying
17eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner]
18eda14cbcSMatt Macy *
19eda14cbcSMatt Macy * CDDL HEADER END
20eda14cbcSMatt Macy */
21eda14cbcSMatt Macy /*
22eda14cbcSMatt Macy * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23eda14cbcSMatt Macy * Use is subject to license terms.
24eda14cbcSMatt Macy */
25eda14cbcSMatt Macy
26eda14cbcSMatt Macy /*
27eda14cbcSMatt Macy * This file is part of the core Kernel Cryptographic Framework.
28eda14cbcSMatt Macy * It implements the SPI functions exported to cryptographic
29eda14cbcSMatt Macy * providers.
30eda14cbcSMatt Macy */
31eda14cbcSMatt Macy
32eda14cbcSMatt Macy
33eda14cbcSMatt Macy #include <sys/zfs_context.h>
34eda14cbcSMatt Macy #include <sys/crypto/common.h>
35eda14cbcSMatt Macy #include <sys/crypto/impl.h>
36eda14cbcSMatt Macy #include <sys/crypto/sched_impl.h>
37eda14cbcSMatt Macy #include <sys/crypto/spi.h>
38eda14cbcSMatt Macy
39e92ffd9bSMartin Matuska static int init_prov_mechs(const crypto_provider_info_t *,
40e92ffd9bSMartin Matuska kcf_provider_desc_t *);
41eda14cbcSMatt Macy
42eda14cbcSMatt Macy /*
43eda14cbcSMatt Macy * This routine is used to add cryptographic providers to the KEF framework.
44eda14cbcSMatt Macy * Providers pass a crypto_provider_info structure to crypto_register_provider()
45eda14cbcSMatt Macy * and get back a handle. The crypto_provider_info structure contains a
46eda14cbcSMatt Macy * list of mechanisms supported by the provider and an ops vector containing
47c03c5b1cSMartin Matuska * provider entry points. Providers call this routine in their _init() routine.
48eda14cbcSMatt Macy */
49eda14cbcSMatt Macy int
crypto_register_provider(const crypto_provider_info_t * info,crypto_kcf_provider_handle_t * handle)50e92ffd9bSMartin Matuska crypto_register_provider(const crypto_provider_info_t *info,
51eda14cbcSMatt Macy crypto_kcf_provider_handle_t *handle)
52eda14cbcSMatt Macy {
53eda14cbcSMatt Macy kcf_provider_desc_t *prov_desc = NULL;
54eda14cbcSMatt Macy int ret = CRYPTO_ARGUMENTS_BAD;
55eda14cbcSMatt Macy
56eda14cbcSMatt Macy /*
57eda14cbcSMatt Macy * Allocate and initialize a new provider descriptor. We also
58eda14cbcSMatt Macy * hold it and release it when done.
59eda14cbcSMatt Macy */
60c03c5b1cSMartin Matuska prov_desc = kcf_alloc_provider_desc();
61eda14cbcSMatt Macy KCF_PROV_REFHOLD(prov_desc);
62eda14cbcSMatt Macy
63eda14cbcSMatt Macy /* copy provider description string */
64c03c5b1cSMartin Matuska prov_desc->pd_description = info->pi_provider_description;
65eda14cbcSMatt Macy
66c03c5b1cSMartin Matuska /* Change from Illumos: the ops vector is persistent. */
67c03c5b1cSMartin Matuska prov_desc->pd_ops_vector = info->pi_ops_vector;
68eda14cbcSMatt Macy
69eda14cbcSMatt Macy /* process the mechanisms supported by the provider */
70eda14cbcSMatt Macy if ((ret = init_prov_mechs(info, prov_desc)) != CRYPTO_SUCCESS)
71eda14cbcSMatt Macy goto bail;
72eda14cbcSMatt Macy
73eda14cbcSMatt Macy /*
74eda14cbcSMatt Macy * Add provider to providers tables, also sets the descriptor
75eda14cbcSMatt Macy * pd_prov_id field.
76eda14cbcSMatt Macy */
77eda14cbcSMatt Macy if ((ret = kcf_prov_tab_add_provider(prov_desc)) != CRYPTO_SUCCESS) {
78eda14cbcSMatt Macy undo_register_provider(prov_desc, B_FALSE);
79eda14cbcSMatt Macy goto bail;
80eda14cbcSMatt Macy }
81eda14cbcSMatt Macy
82eda14cbcSMatt Macy /*
83c03c5b1cSMartin Matuska * The global queue is used for providers. We handle ordering
84eda14cbcSMatt Macy * of multi-part requests in the taskq routine. So, it is safe to
85eda14cbcSMatt Macy * have multiple threads for the taskq. We pass TASKQ_PREPOPULATE flag
86eda14cbcSMatt Macy * to keep some entries cached to improve performance.
87eda14cbcSMatt Macy */
88eda14cbcSMatt Macy
89eda14cbcSMatt Macy mutex_enter(&prov_desc->pd_lock);
90eda14cbcSMatt Macy prov_desc->pd_state = KCF_PROV_READY;
91eda14cbcSMatt Macy mutex_exit(&prov_desc->pd_lock);
92eda14cbcSMatt Macy
93eda14cbcSMatt Macy *handle = prov_desc->pd_kcf_prov_handle;
94eda14cbcSMatt Macy ret = CRYPTO_SUCCESS;
95eda14cbcSMatt Macy
96eda14cbcSMatt Macy bail:
97eda14cbcSMatt Macy KCF_PROV_REFRELE(prov_desc);
98eda14cbcSMatt Macy return (ret);
99eda14cbcSMatt Macy }
100eda14cbcSMatt Macy
101eda14cbcSMatt Macy /*
102eda14cbcSMatt Macy * This routine is used to notify the framework when a provider is being
103c03c5b1cSMartin Matuska * removed. Providers call this routine in their _fini() routine.
104eda14cbcSMatt Macy */
105eda14cbcSMatt Macy int
crypto_unregister_provider(crypto_kcf_provider_handle_t handle)106eda14cbcSMatt Macy crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
107eda14cbcSMatt Macy {
108eda14cbcSMatt Macy uint_t mech_idx;
109eda14cbcSMatt Macy kcf_provider_desc_t *desc;
110eda14cbcSMatt Macy kcf_prov_state_t saved_state;
111eda14cbcSMatt Macy
112eda14cbcSMatt Macy /* lookup provider descriptor */
113eda14cbcSMatt Macy if ((desc = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
114eda14cbcSMatt Macy return (CRYPTO_UNKNOWN_PROVIDER);
115eda14cbcSMatt Macy
116eda14cbcSMatt Macy mutex_enter(&desc->pd_lock);
117eda14cbcSMatt Macy /*
118eda14cbcSMatt Macy * Check if any other thread is disabling or removing
119eda14cbcSMatt Macy * this provider. We return if this is the case.
120eda14cbcSMatt Macy */
121eda14cbcSMatt Macy if (desc->pd_state >= KCF_PROV_DISABLED) {
122eda14cbcSMatt Macy mutex_exit(&desc->pd_lock);
123eda14cbcSMatt Macy /* Release reference held by kcf_prov_tab_lookup(). */
124eda14cbcSMatt Macy KCF_PROV_REFRELE(desc);
125eda14cbcSMatt Macy return (CRYPTO_BUSY);
126eda14cbcSMatt Macy }
127eda14cbcSMatt Macy
128eda14cbcSMatt Macy saved_state = desc->pd_state;
129eda14cbcSMatt Macy desc->pd_state = KCF_PROV_REMOVED;
130eda14cbcSMatt Macy
131eda14cbcSMatt Macy /*
132eda14cbcSMatt Macy * Check if this provider is currently being used.
133eda14cbcSMatt Macy * pd_irefcnt is the number of holds from the internal
134eda14cbcSMatt Macy * structures. We add one to account for the above lookup.
135eda14cbcSMatt Macy */
136eda14cbcSMatt Macy if (desc->pd_refcnt > desc->pd_irefcnt + 1) {
137eda14cbcSMatt Macy desc->pd_state = saved_state;
138eda14cbcSMatt Macy mutex_exit(&desc->pd_lock);
139eda14cbcSMatt Macy /* Release reference held by kcf_prov_tab_lookup(). */
140eda14cbcSMatt Macy KCF_PROV_REFRELE(desc);
141eda14cbcSMatt Macy /*
142c03c5b1cSMartin Matuska * The administrator will presumably stop the clients,
143eda14cbcSMatt Macy * thus removing the holds, when they get the busy
144eda14cbcSMatt Macy * return value. Any retry will succeed then.
145eda14cbcSMatt Macy */
146eda14cbcSMatt Macy return (CRYPTO_BUSY);
147eda14cbcSMatt Macy }
148eda14cbcSMatt Macy mutex_exit(&desc->pd_lock);
149eda14cbcSMatt Macy
150eda14cbcSMatt Macy /* remove the provider from the mechanisms tables */
151eda14cbcSMatt Macy for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
152eda14cbcSMatt Macy mech_idx++) {
153eda14cbcSMatt Macy kcf_remove_mech_provider(
154eda14cbcSMatt Macy desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
155eda14cbcSMatt Macy }
156eda14cbcSMatt Macy
157eda14cbcSMatt Macy /* remove provider from providers table */
158eda14cbcSMatt Macy if (kcf_prov_tab_rem_provider((crypto_provider_id_t)handle) !=
159eda14cbcSMatt Macy CRYPTO_SUCCESS) {
160eda14cbcSMatt Macy /* Release reference held by kcf_prov_tab_lookup(). */
161eda14cbcSMatt Macy KCF_PROV_REFRELE(desc);
162eda14cbcSMatt Macy return (CRYPTO_UNKNOWN_PROVIDER);
163eda14cbcSMatt Macy }
164eda14cbcSMatt Macy
165eda14cbcSMatt Macy /* Release reference held by kcf_prov_tab_lookup(). */
166eda14cbcSMatt Macy KCF_PROV_REFRELE(desc);
167eda14cbcSMatt Macy
168eda14cbcSMatt Macy /*
169eda14cbcSMatt Macy * Wait till the existing requests complete.
170eda14cbcSMatt Macy */
171eda14cbcSMatt Macy mutex_enter(&desc->pd_lock);
172eda14cbcSMatt Macy while (desc->pd_state != KCF_PROV_FREED)
173eda14cbcSMatt Macy cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
174eda14cbcSMatt Macy mutex_exit(&desc->pd_lock);
175eda14cbcSMatt Macy
176eda14cbcSMatt Macy /*
177eda14cbcSMatt Macy * This is the only place where kcf_free_provider_desc()
178eda14cbcSMatt Macy * is called directly. KCF_PROV_REFRELE() should free the
179eda14cbcSMatt Macy * structure in all other places.
180eda14cbcSMatt Macy */
181eda14cbcSMatt Macy ASSERT(desc->pd_state == KCF_PROV_FREED &&
182eda14cbcSMatt Macy desc->pd_refcnt == 0);
183eda14cbcSMatt Macy kcf_free_provider_desc(desc);
184eda14cbcSMatt Macy
185eda14cbcSMatt Macy return (CRYPTO_SUCCESS);
186eda14cbcSMatt Macy }
187eda14cbcSMatt Macy
188eda14cbcSMatt Macy /*
189eda14cbcSMatt Macy * Process the mechanism info structures specified by the provider
190eda14cbcSMatt Macy * during registration. A NULL crypto_provider_info_t indicates
191eda14cbcSMatt Macy * an already initialized provider descriptor.
192eda14cbcSMatt Macy *
193eda14cbcSMatt Macy * Returns CRYPTO_SUCCESS on success, CRYPTO_ARGUMENTS if one
194eda14cbcSMatt Macy * of the specified mechanisms was malformed, or CRYPTO_HOST_MEMORY
195eda14cbcSMatt Macy * if the table of mechanisms is full.
196eda14cbcSMatt Macy */
197eda14cbcSMatt Macy static int
init_prov_mechs(const crypto_provider_info_t * info,kcf_provider_desc_t * desc)198e92ffd9bSMartin Matuska init_prov_mechs(const crypto_provider_info_t *info, kcf_provider_desc_t *desc)
199eda14cbcSMatt Macy {
200eda14cbcSMatt Macy uint_t mech_idx;
201eda14cbcSMatt Macy uint_t cleanup_idx;
202eda14cbcSMatt Macy int err = CRYPTO_SUCCESS;
203eda14cbcSMatt Macy kcf_prov_mech_desc_t *pmd;
204eda14cbcSMatt Macy int desc_use_count = 0;
205eda14cbcSMatt Macy
206eda14cbcSMatt Macy /*
207eda14cbcSMatt Macy * Copy the mechanism list from the provider info to the provider
208eda14cbcSMatt Macy * descriptor. desc->pd_mechanisms has an extra crypto_mech_info_t
209eda14cbcSMatt Macy * element if the provider has random_ops since we keep an internal
210eda14cbcSMatt Macy * mechanism, SUN_RANDOM, in this case.
211eda14cbcSMatt Macy */
212eda14cbcSMatt Macy if (info != NULL) {
213eda14cbcSMatt Macy ASSERT(info->pi_mechanisms != NULL);
214c03c5b1cSMartin Matuska desc->pd_mech_list_count = info->pi_mech_list_count;
215c03c5b1cSMartin Matuska desc->pd_mechanisms = info->pi_mechanisms;
216eda14cbcSMatt Macy }
217eda14cbcSMatt Macy
218eda14cbcSMatt Macy /*
219eda14cbcSMatt Macy * For each mechanism support by the provider, add the provider
220eda14cbcSMatt Macy * to the corresponding KCF mechanism mech_entry chain.
221eda14cbcSMatt Macy */
222eda14cbcSMatt Macy for (mech_idx = 0; mech_idx < desc->pd_mech_list_count; mech_idx++) {
223eda14cbcSMatt Macy if ((err = kcf_add_mech_provider(mech_idx, desc, &pmd)) !=
224eda14cbcSMatt Macy KCF_SUCCESS)
225eda14cbcSMatt Macy break;
226eda14cbcSMatt Macy
227eda14cbcSMatt Macy if (pmd == NULL)
228eda14cbcSMatt Macy continue;
229eda14cbcSMatt Macy
230eda14cbcSMatt Macy /* The provider will be used for this mechanism */
231eda14cbcSMatt Macy desc_use_count++;
232eda14cbcSMatt Macy }
233eda14cbcSMatt Macy
234eda14cbcSMatt Macy /*
235c03c5b1cSMartin Matuska * Don't allow multiple providers with disabled mechanisms
236eda14cbcSMatt Macy * to register. Subsequent enabling of mechanisms will result in
237c03c5b1cSMartin Matuska * an unsupported configuration, i.e. multiple providers
238eda14cbcSMatt Macy * per mechanism.
239eda14cbcSMatt Macy */
240c03c5b1cSMartin Matuska if (desc_use_count == 0)
241eda14cbcSMatt Macy return (CRYPTO_ARGUMENTS_BAD);
242eda14cbcSMatt Macy
243eda14cbcSMatt Macy if (err == KCF_SUCCESS)
244eda14cbcSMatt Macy return (CRYPTO_SUCCESS);
245eda14cbcSMatt Macy
246eda14cbcSMatt Macy /*
247eda14cbcSMatt Macy * An error occurred while adding the mechanism, cleanup
248eda14cbcSMatt Macy * and bail.
249eda14cbcSMatt Macy */
250eda14cbcSMatt Macy for (cleanup_idx = 0; cleanup_idx < mech_idx; cleanup_idx++) {
251eda14cbcSMatt Macy kcf_remove_mech_provider(
252eda14cbcSMatt Macy desc->pd_mechanisms[cleanup_idx].cm_mech_name, desc);
253eda14cbcSMatt Macy }
254eda14cbcSMatt Macy
255eda14cbcSMatt Macy if (err == KCF_MECH_TAB_FULL)
256eda14cbcSMatt Macy return (CRYPTO_HOST_MEMORY);
257eda14cbcSMatt Macy
258eda14cbcSMatt Macy return (CRYPTO_ARGUMENTS_BAD);
259eda14cbcSMatt Macy }
260eda14cbcSMatt Macy
261eda14cbcSMatt Macy /*
262eda14cbcSMatt Macy * Utility routine called from failure paths in crypto_register_provider()
263eda14cbcSMatt Macy * and from crypto_load_soft_disabled().
264eda14cbcSMatt Macy */
265eda14cbcSMatt Macy void
undo_register_provider(kcf_provider_desc_t * desc,boolean_t remove_prov)266eda14cbcSMatt Macy undo_register_provider(kcf_provider_desc_t *desc, boolean_t remove_prov)
267eda14cbcSMatt Macy {
268eda14cbcSMatt Macy uint_t mech_idx;
269eda14cbcSMatt Macy
270eda14cbcSMatt Macy /* remove the provider from the mechanisms tables */
271eda14cbcSMatt Macy for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
272eda14cbcSMatt Macy mech_idx++) {
273eda14cbcSMatt Macy kcf_remove_mech_provider(
274eda14cbcSMatt Macy desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
275eda14cbcSMatt Macy }
276eda14cbcSMatt Macy
277eda14cbcSMatt Macy /* remove provider from providers table */
278eda14cbcSMatt Macy if (remove_prov)
279eda14cbcSMatt Macy (void) kcf_prov_tab_rem_provider(desc->pd_prov_id);
280eda14cbcSMatt Macy }
281