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
108698 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/crypto/common.h>
35
#include <sys/crypto/impl.h>
36
#include <sys/crypto/sched_impl.h>
37
#include <sys/crypto/spi.h>
38
39
static int init_prov_mechs(const crypto_provider_info_t *,
40
kcf_provider_desc_t *);
41
42
/*
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.
48
*/
49
int
50
crypto_register_provider(const crypto_provider_info_t *info,
51
crypto_kcf_provider_handle_t *handle)
52
{
53
kcf_provider_desc_t *prov_desc = NULL;
54
int ret = CRYPTO_ARGUMENTS_BAD;
55
56
/*
57
* Allocate and initialize a new provider descriptor. We also
58
* hold it and release it when done.
59
*/
60
prov_desc = kcf_alloc_provider_desc();
61
KCF_PROV_REFHOLD(prov_desc);
62
63
/* copy provider description string */
64
prov_desc->pd_description = info->pi_provider_description;
65
66
/* Change from Illumos: the ops vector is persistent. */
67
prov_desc->pd_ops_vector = info->pi_ops_vector;
68
69
/* process the mechanisms supported by the provider */
70
if ((ret = init_prov_mechs(info, prov_desc)) != CRYPTO_SUCCESS)
71
goto bail;
72
73
/*
74
* Add provider to providers tables, also sets the descriptor
75
* pd_prov_id field.
76
*/
77
if ((ret = kcf_prov_tab_add_provider(prov_desc)) != CRYPTO_SUCCESS) {
78
undo_register_provider(prov_desc, B_FALSE);
79
goto bail;
80
}
81
82
/*
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.
87
*/
88
89
mutex_enter(&prov_desc->pd_lock);
90
prov_desc->pd_state = KCF_PROV_READY;
91
mutex_exit(&prov_desc->pd_lock);
92
93
*handle = prov_desc->pd_kcf_prov_handle;
94
ret = CRYPTO_SUCCESS;
95
96
bail:
97
KCF_PROV_REFRELE(prov_desc);
98
return (ret);
99
}
100
101
/*
102
* This routine is used to notify the framework when a provider is being
103
* removed. Providers call this routine in their _fini() routine.
104
*/
105
int
106
crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
107
{
108
uint_t mech_idx;
109
kcf_provider_desc_t *desc;
110
kcf_prov_state_t saved_state;
111
112
/* lookup provider descriptor */
113
if ((desc = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
114
return (CRYPTO_UNKNOWN_PROVIDER);
115
116
mutex_enter(&desc->pd_lock);
117
/*
118
* Check if any other thread is disabling or removing
119
* this provider. We return if this is the case.
120
*/
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);
126
}
127
128
saved_state = desc->pd_state;
129
desc->pd_state = KCF_PROV_REMOVED;
130
131
/*
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.
135
*/
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);
141
/*
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.
145
*/
146
return (CRYPTO_BUSY);
147
}
148
mutex_exit(&desc->pd_lock);
149
150
/* remove the provider from the mechanisms tables */
151
for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
152
mech_idx++) {
153
kcf_remove_mech_provider(
154
desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
155
}
156
157
/* remove provider from providers table */
158
if (kcf_prov_tab_rem_provider((crypto_provider_id_t)handle) !=
159
CRYPTO_SUCCESS) {
160
/* Release reference held by kcf_prov_tab_lookup(). */
161
KCF_PROV_REFRELE(desc);
162
return (CRYPTO_UNKNOWN_PROVIDER);
163
}
164
165
/* Release reference held by kcf_prov_tab_lookup(). */
166
KCF_PROV_REFRELE(desc);
167
168
/*
169
* Wait till the existing requests complete.
170
*/
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);
175
176
/*
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.
180
*/
181
ASSERT(desc->pd_state == KCF_PROV_FREED &&
182
desc->pd_refcnt == 0);
183
kcf_free_provider_desc(desc);
184
185
return (CRYPTO_SUCCESS);
186
}
187
188
/*
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.
192
*
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.
196
*/
197
static int
198
init_prov_mechs(const crypto_provider_info_t *info, kcf_provider_desc_t *desc)
199
{
200
uint_t mech_idx;
201
uint_t cleanup_idx;
202
int err = CRYPTO_SUCCESS;
203
kcf_prov_mech_desc_t *pmd;
204
int desc_use_count = 0;
205
206
/*
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.
211
*/
212
if (info != NULL) {
213
ASSERT(info->pi_mechanisms != NULL);
214
desc->pd_mech_list_count = info->pi_mech_list_count;
215
desc->pd_mechanisms = info->pi_mechanisms;
216
}
217
218
/*
219
* For each mechanism support by the provider, add the provider
220
* to the corresponding KCF mechanism mech_entry chain.
221
*/
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)) !=
224
KCF_SUCCESS)
225
break;
226
227
if (pmd == NULL)
228
continue;
229
230
/* The provider will be used for this mechanism */
231
desc_use_count++;
232
}
233
234
/*
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
238
* per mechanism.
239
*/
240
if (desc_use_count == 0)
241
return (CRYPTO_ARGUMENTS_BAD);
242
243
if (err == KCF_SUCCESS)
244
return (CRYPTO_SUCCESS);
245
246
/*
247
* An error occurred while adding the mechanism, cleanup
248
* and bail.
249
*/
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);
253
}
254
255
if (err == KCF_MECH_TAB_FULL)
256
return (CRYPTO_HOST_MEMORY);
257
258
return (CRYPTO_ARGUMENTS_BAD);
259
}
260
261
/*
262
* Utility routine called from failure paths in crypto_register_provider()
263
* and from crypto_load_soft_disabled().
264
*/
265
void
266
undo_register_provider(kcf_provider_desc_t *desc, boolean_t remove_prov)
267
{
268
uint_t mech_idx;
269
270
/* remove the provider from the mechanisms tables */
271
for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
272
mech_idx++) {
273
kcf_remove_mech_provider(
274
desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
275
}
276
277
/* remove provider from providers table */
278
if (remove_prov)
279
(void) kcf_prov_tab_rem_provider(desc->pd_prov_id);
280
}
281
282