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