]>
Commit | Line | Data |
---|---|---|
f12a5690 | 1 | /* |
fecb3aae | 2 | * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. |
f12a5690 MC |
3 | * |
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use | |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8 | */ | |
9 | ||
8c627075 | 10 | #include <assert.h> |
f12a5690 MC |
11 | #include <openssl/crypto.h> |
12 | #include <openssl/core_dispatch.h> | |
13 | #include <openssl/core_names.h> | |
14 | #include <openssl/provider.h> | |
447588b6 | 15 | #include <openssl/evp.h> |
f12a5690 MC |
16 | #include "internal/provider.h" |
17 | #include "internal/cryptlib.h" | |
b1c053ac | 18 | #include "crypto/evp.h" |
927d0566 | 19 | #include "crypto/context.h" |
f12a5690 MC |
20 | |
21 | DEFINE_STACK_OF(OSSL_PROVIDER) | |
22 | ||
23 | struct child_prov_globals { | |
24 | const OSSL_CORE_HANDLE *handle; | |
7b88c184 | 25 | const OSSL_CORE_HANDLE *curr_prov; |
f12a5690 MC |
26 | CRYPTO_RWLOCK *lock; |
27 | OSSL_FUNC_core_get_libctx_fn *c_get_libctx; | |
7b88c184 MC |
28 | OSSL_FUNC_provider_register_child_cb_fn *c_provider_register_child_cb; |
29 | OSSL_FUNC_provider_deregister_child_cb_fn *c_provider_deregister_child_cb; | |
30 | OSSL_FUNC_provider_name_fn *c_prov_name; | |
31 | OSSL_FUNC_provider_get0_provider_ctx_fn *c_prov_get0_provider_ctx; | |
32 | OSSL_FUNC_provider_get0_dispatch_fn *c_prov_get0_dispatch; | |
8c627075 MC |
33 | OSSL_FUNC_provider_up_ref_fn *c_prov_up_ref; |
34 | OSSL_FUNC_provider_free_fn *c_prov_free; | |
f12a5690 MC |
35 | }; |
36 | ||
927d0566 | 37 | void *ossl_child_prov_ctx_new(OSSL_LIB_CTX *libctx) |
f12a5690 MC |
38 | { |
39 | return OPENSSL_zalloc(sizeof(struct child_prov_globals)); | |
40 | } | |
41 | ||
927d0566 | 42 | void ossl_child_prov_ctx_free(void *vgbl) |
f12a5690 MC |
43 | { |
44 | struct child_prov_globals *gbl = vgbl; | |
45 | ||
f12a5690 MC |
46 | CRYPTO_THREAD_lock_free(gbl->lock); |
47 | OPENSSL_free(gbl); | |
48 | } | |
49 | ||
f12a5690 MC |
50 | static OSSL_provider_init_fn ossl_child_provider_init; |
51 | ||
52 | static int ossl_child_provider_init(const OSSL_CORE_HANDLE *handle, | |
53 | const OSSL_DISPATCH *in, | |
54 | const OSSL_DISPATCH **out, | |
55 | void **provctx) | |
56 | { | |
57 | OSSL_FUNC_core_get_libctx_fn *c_get_libctx = NULL; | |
58 | OSSL_LIB_CTX *ctx; | |
59 | struct child_prov_globals *gbl; | |
60 | ||
61 | for (; in->function_id != 0; in++) { | |
62 | switch (in->function_id) { | |
63 | case OSSL_FUNC_CORE_GET_LIBCTX: | |
64 | c_get_libctx = OSSL_FUNC_core_get_libctx(in); | |
65 | break; | |
66 | default: | |
67 | /* Just ignore anything we don't understand */ | |
68 | break; | |
69 | } | |
70 | } | |
71 | ||
72 | if (c_get_libctx == NULL) | |
73 | return 0; | |
74 | ||
75 | /* | |
76 | * We need an OSSL_LIB_CTX but c_get_libctx returns OPENSSL_CORE_CTX. We are | |
77 | * a built-in provider and so we can get away with this cast. Normal | |
78 | * providers can't do this. | |
79 | */ | |
80 | ctx = (OSSL_LIB_CTX *)c_get_libctx(handle); | |
81 | ||
927d0566 | 82 | gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX); |
f12a5690 MC |
83 | if (gbl == NULL) |
84 | return 0; | |
85 | ||
86 | *provctx = gbl->c_prov_get0_provider_ctx(gbl->curr_prov); | |
87 | *out = gbl->c_prov_get0_dispatch(gbl->curr_prov); | |
88 | ||
89 | return 1; | |
90 | } | |
91 | ||
7b88c184 | 92 | static int provider_create_child_cb(const OSSL_CORE_HANDLE *prov, void *cbdata) |
f12a5690 MC |
93 | { |
94 | OSSL_LIB_CTX *ctx = cbdata; | |
95 | struct child_prov_globals *gbl; | |
96 | const char *provname; | |
97 | OSSL_PROVIDER *cprov; | |
7b88c184 | 98 | int ret = 0; |
f12a5690 | 99 | |
927d0566 | 100 | gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX); |
f12a5690 MC |
101 | if (gbl == NULL) |
102 | return 0; | |
103 | ||
464c2b98 | 104 | if (!CRYPTO_THREAD_write_lock(gbl->lock)) |
7b88c184 MC |
105 | return 0; |
106 | ||
f12a5690 MC |
107 | provname = gbl->c_prov_name(prov); |
108 | ||
109 | /* | |
110 | * We're operating under a lock so we can store the "current" provider in | |
111 | * the global data. | |
112 | */ | |
113 | gbl->curr_prov = prov; | |
114 | ||
abaa2dd2 MC |
115 | if ((cprov = ossl_provider_find(ctx, provname, 1)) != NULL) { |
116 | /* | |
59a783d0 MC |
117 | * We free the newly created ref. We rely on the provider sticking around |
118 | * in the provider store. | |
119 | */ | |
abaa2dd2 MC |
120 | ossl_provider_free(cprov); |
121 | ||
122 | /* | |
d5fbd5b4 MC |
123 | * The provider already exists. It could be a previously created child, |
124 | * or it could have been explicitly loaded. If explicitly loaded we | |
125 | * ignore it - i.e. we don't start treating it like a child. | |
abaa2dd2 | 126 | */ |
814c2018 | 127 | if (!ossl_provider_activate(cprov, 0, 1)) |
abaa2dd2 MC |
128 | goto err; |
129 | } else { | |
130 | /* | |
131 | * Create it - passing 1 as final param so we don't try and recursively | |
132 | * init children | |
133 | */ | |
134 | if ((cprov = ossl_provider_new(ctx, provname, ossl_child_provider_init, | |
135 | 1)) == NULL) | |
136 | goto err; | |
137 | ||
814c2018 | 138 | if (!ossl_provider_activate(cprov, 0, 0)) |
abaa2dd2 MC |
139 | goto err; |
140 | ||
29aff653 | 141 | if (!ossl_provider_set_child(cprov, prov) |
59a783d0 | 142 | || !ossl_provider_add_to_store(cprov, NULL, 0)) { |
c59fc87b | 143 | ossl_provider_deactivate(cprov, 0); |
29aff653 | 144 | ossl_provider_free(cprov); |
abaa2dd2 MC |
145 | goto err; |
146 | } | |
f12a5690 MC |
147 | } |
148 | ||
7b88c184 MC |
149 | ret = 1; |
150 | err: | |
464c2b98 | 151 | CRYPTO_THREAD_unlock(gbl->lock); |
7b88c184 MC |
152 | return ret; |
153 | } | |
154 | ||
155 | static int provider_remove_child_cb(const OSSL_CORE_HANDLE *prov, void *cbdata) | |
156 | { | |
157 | OSSL_LIB_CTX *ctx = cbdata; | |
158 | struct child_prov_globals *gbl; | |
159 | const char *provname; | |
160 | OSSL_PROVIDER *cprov; | |
161 | ||
927d0566 | 162 | gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX); |
7b88c184 MC |
163 | if (gbl == NULL) |
164 | return 0; | |
165 | ||
166 | provname = gbl->c_prov_name(prov); | |
167 | cprov = ossl_provider_find(ctx, provname, 1); | |
abaa2dd2 | 168 | if (cprov == NULL) |
8c627075 | 169 | return 0; |
abaa2dd2 MC |
170 | /* |
171 | * ossl_provider_find ups the ref count, so we free it again here. We can | |
172 | * rely on the provider store reference count. | |
173 | */ | |
8c627075 | 174 | ossl_provider_free(cprov); |
abaa2dd2 | 175 | if (ossl_provider_is_child(cprov) |
c59fc87b | 176 | && !ossl_provider_deactivate(cprov, 1)) |
abaa2dd2 | 177 | return 0; |
7b88c184 | 178 | |
f12a5690 MC |
179 | return 1; |
180 | } | |
181 | ||
447588b6 MC |
182 | static int provider_global_props_cb(const char *props, void *cbdata) |
183 | { | |
184 | OSSL_LIB_CTX *ctx = cbdata; | |
185 | ||
186 | return evp_set_default_properties_int(ctx, props, 0, 1); | |
187 | } | |
188 | ||
f12a5690 MC |
189 | int ossl_provider_init_as_child(OSSL_LIB_CTX *ctx, |
190 | const OSSL_CORE_HANDLE *handle, | |
191 | const OSSL_DISPATCH *in) | |
192 | { | |
193 | struct child_prov_globals *gbl; | |
194 | ||
195 | if (ctx == NULL) | |
196 | return 0; | |
197 | ||
927d0566 | 198 | gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX); |
f12a5690 MC |
199 | if (gbl == NULL) |
200 | return 0; | |
201 | ||
202 | gbl->handle = handle; | |
203 | for (; in->function_id != 0; in++) { | |
204 | switch (in->function_id) { | |
205 | case OSSL_FUNC_CORE_GET_LIBCTX: | |
206 | gbl->c_get_libctx = OSSL_FUNC_core_get_libctx(in); | |
207 | break; | |
7b88c184 MC |
208 | case OSSL_FUNC_PROVIDER_REGISTER_CHILD_CB: |
209 | gbl->c_provider_register_child_cb | |
210 | = OSSL_FUNC_provider_register_child_cb(in); | |
211 | break; | |
212 | case OSSL_FUNC_PROVIDER_DEREGISTER_CHILD_CB: | |
213 | gbl->c_provider_deregister_child_cb | |
214 | = OSSL_FUNC_provider_deregister_child_cb(in); | |
f12a5690 | 215 | break; |
7b88c184 MC |
216 | case OSSL_FUNC_PROVIDER_NAME: |
217 | gbl->c_prov_name = OSSL_FUNC_provider_name(in); | |
f12a5690 | 218 | break; |
7b88c184 | 219 | case OSSL_FUNC_PROVIDER_GET0_PROVIDER_CTX: |
f12a5690 | 220 | gbl->c_prov_get0_provider_ctx |
7b88c184 | 221 | = OSSL_FUNC_provider_get0_provider_ctx(in); |
f12a5690 | 222 | break; |
7b88c184 MC |
223 | case OSSL_FUNC_PROVIDER_GET0_DISPATCH: |
224 | gbl->c_prov_get0_dispatch = OSSL_FUNC_provider_get0_dispatch(in); | |
f12a5690 | 225 | break; |
8c627075 MC |
226 | case OSSL_FUNC_PROVIDER_UP_REF: |
227 | gbl->c_prov_up_ref | |
228 | = OSSL_FUNC_provider_up_ref(in); | |
229 | break; | |
230 | case OSSL_FUNC_PROVIDER_FREE: | |
231 | gbl->c_prov_free = OSSL_FUNC_provider_free(in); | |
232 | break; | |
f12a5690 MC |
233 | default: |
234 | /* Just ignore anything we don't understand */ | |
235 | break; | |
236 | } | |
237 | } | |
238 | ||
7b88c184 MC |
239 | if (gbl->c_get_libctx == NULL |
240 | || gbl->c_provider_register_child_cb == NULL | |
f12a5690 MC |
241 | || gbl->c_prov_name == NULL |
242 | || gbl->c_prov_get0_provider_ctx == NULL | |
8c627075 MC |
243 | || gbl->c_prov_get0_dispatch == NULL |
244 | || gbl->c_prov_up_ref == NULL | |
245 | || gbl->c_prov_free == NULL) | |
f12a5690 MC |
246 | return 0; |
247 | ||
f12a5690 MC |
248 | gbl->lock = CRYPTO_THREAD_lock_new(); |
249 | if (gbl->lock == NULL) | |
250 | return 0; | |
251 | ||
36a89c04 MC |
252 | if (!gbl->c_provider_register_child_cb(gbl->handle, |
253 | provider_create_child_cb, | |
254 | provider_remove_child_cb, | |
447588b6 | 255 | provider_global_props_cb, |
36a89c04 MC |
256 | ctx)) |
257 | return 0; | |
258 | ||
f12a5690 MC |
259 | return 1; |
260 | } | |
8c627075 | 261 | |
cad22202 MC |
262 | void ossl_provider_deinit_child(OSSL_LIB_CTX *ctx) |
263 | { | |
264 | struct child_prov_globals *gbl | |
927d0566 | 265 | = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX); |
cad22202 MC |
266 | if (gbl == NULL) |
267 | return; | |
268 | ||
269 | gbl->c_provider_deregister_child_cb(gbl->handle); | |
270 | } | |
271 | ||
4da7663b RL |
272 | /* |
273 | * ossl_provider_up_ref_parent() and ossl_provider_free_parent() do | |
274 | * nothing in "self-referencing" child providers, i.e. when the parent | |
275 | * of the child provider is the same as the provider where this child | |
276 | * provider was created. | |
277 | * This allows the teardown function in the parent provider to be called | |
278 | * at the correct moment. | |
279 | * For child providers in other providers, the reference count is done to | |
280 | * ensure that cross referencing is recorded. These should be cleared up | |
281 | * through that providers teardown, as part of freeing its child libctx. | |
282 | */ | |
283 | ||
8c627075 MC |
284 | int ossl_provider_up_ref_parent(OSSL_PROVIDER *prov, int activate) |
285 | { | |
286 | struct child_prov_globals *gbl; | |
4da7663b | 287 | const OSSL_CORE_HANDLE *parent_handle; |
8c627075 MC |
288 | |
289 | gbl = ossl_lib_ctx_get_data(ossl_provider_libctx(prov), | |
927d0566 | 290 | OSSL_LIB_CTX_CHILD_PROVIDER_INDEX); |
8c627075 MC |
291 | if (gbl == NULL) |
292 | return 0; | |
293 | ||
4da7663b RL |
294 | parent_handle = ossl_provider_get_parent(prov); |
295 | if (parent_handle == gbl->handle) | |
296 | return 1; | |
297 | return gbl->c_prov_up_ref(parent_handle, activate); | |
8c627075 MC |
298 | } |
299 | ||
300 | int ossl_provider_free_parent(OSSL_PROVIDER *prov, int deactivate) | |
301 | { | |
302 | struct child_prov_globals *gbl; | |
4da7663b | 303 | const OSSL_CORE_HANDLE *parent_handle; |
8c627075 MC |
304 | |
305 | gbl = ossl_lib_ctx_get_data(ossl_provider_libctx(prov), | |
927d0566 | 306 | OSSL_LIB_CTX_CHILD_PROVIDER_INDEX); |
8c627075 MC |
307 | if (gbl == NULL) |
308 | return 0; | |
309 | ||
4da7663b RL |
310 | parent_handle = ossl_provider_get_parent(prov); |
311 | if (parent_handle == gbl->handle) | |
312 | return 1; | |
8c627075 MC |
313 | return gbl->c_prov_free(ossl_provider_get_parent(prov), deactivate); |
314 | } |