]>
Commit | Line | Data |
---|---|---|
4c2883a9 RL |
1 | /* |
2 | * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. | |
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 | ||
10 | #include <openssl/core.h> | |
11 | #include <openssl/core_numbers.h> | |
12 | #include <openssl/opensslv.h> | |
13 | #include "internal/cryptlib.h" | |
14 | #include "internal/thread_once.h" | |
15 | #include "internal/provider.h" | |
16 | #include "internal/refcount.h" | |
17 | ||
18 | /*- | |
19 | * Provider Object structure | |
20 | * ========================= | |
21 | */ | |
22 | ||
23 | struct provider_store_st; /* Forward declaration */ | |
24 | ||
25 | struct ossl_provider_st { | |
26 | /* Flag bits */ | |
27 | unsigned int flag_initialized:1; | |
28 | ||
29 | /* OpenSSL library side data */ | |
30 | CRYPTO_REF_COUNT refcnt; | |
085bef9f | 31 | CRYPTO_RWLOCK *refcnt_lock; /* For the ref counter */ |
4c2883a9 RL |
32 | char *name; |
33 | DSO *module; | |
34 | OSSL_provider_init_fn *init_function; | |
35 | ||
36 | /* Provider side functions */ | |
37 | OSSL_provider_teardown_fn *teardown; | |
38 | OSSL_provider_get_param_types_fn *get_param_types; | |
39 | OSSL_provider_get_params_fn *get_params; | |
099bd339 | 40 | OSSL_provider_query_operation_fn *query_operation; |
4c2883a9 RL |
41 | }; |
42 | DEFINE_STACK_OF(OSSL_PROVIDER) | |
43 | ||
44 | static int ossl_provider_cmp(const OSSL_PROVIDER * const *a, | |
45 | const OSSL_PROVIDER * const *b) | |
46 | { | |
47 | return strcmp((*a)->name, (*b)->name); | |
48 | } | |
49 | ||
50 | /*- | |
51 | * Provider Object store | |
52 | * ===================== | |
53 | * | |
54 | * The Provider Object store is a library context object, and therefore needs | |
55 | * an index. | |
56 | */ | |
57 | ||
58 | struct provider_store_st { | |
59 | STACK_OF(OSSL_PROVIDER) *providers; | |
60 | CRYPTO_RWLOCK *lock; | |
61 | }; | |
62 | static int provider_store_index = -1; | |
63 | ||
64 | static void provider_store_free(void *vstore) | |
65 | { | |
66 | struct provider_store_st *store = vstore; | |
67 | ||
68 | if (store == NULL) | |
69 | return; | |
70 | sk_OSSL_PROVIDER_pop_free(store->providers, ossl_provider_free); | |
71 | CRYPTO_THREAD_lock_free(store->lock); | |
72 | OPENSSL_free(store); | |
73 | } | |
74 | ||
75 | static void *provider_store_new(void) | |
76 | { | |
77 | struct provider_store_st *store = OPENSSL_zalloc(sizeof(*store)); | |
78 | ||
79 | if (store == NULL | |
80 | || (store->providers = sk_OSSL_PROVIDER_new(ossl_provider_cmp)) == NULL | |
81 | || (store->lock = CRYPTO_THREAD_lock_new()) == NULL) { | |
82 | provider_store_free(store); | |
83 | store = NULL; | |
84 | } | |
85 | return store; | |
86 | } | |
87 | ||
88 | static const OPENSSL_CTX_METHOD provider_store_method = { | |
89 | provider_store_new, | |
90 | provider_store_free, | |
91 | }; | |
92 | ||
93 | static CRYPTO_ONCE provider_store_init_flag = CRYPTO_ONCE_STATIC_INIT; | |
94 | DEFINE_RUN_ONCE_STATIC(do_provider_store_init) | |
95 | { | |
96 | return OPENSSL_init_crypto(0, NULL) | |
97 | && (provider_store_index = | |
98 | openssl_ctx_new_index(&provider_store_method)) != -1; | |
99 | } | |
100 | ||
101 | ||
102 | static struct provider_store_st *get_provider_store(OPENSSL_CTX *libctx) | |
103 | { | |
104 | struct provider_store_st *store = NULL; | |
105 | ||
106 | if (!RUN_ONCE(&provider_store_init_flag, do_provider_store_init)) | |
107 | return NULL; | |
108 | ||
109 | store = openssl_ctx_get_data(libctx, provider_store_index); | |
110 | if (store == NULL) | |
111 | CRYPTOerr(CRYPTO_F_GET_PROVIDER_STORE, ERR_R_INTERNAL_ERROR); | |
112 | return store; | |
113 | } | |
114 | ||
115 | /*- | |
116 | * Provider Object methods | |
117 | * ======================= | |
118 | */ | |
119 | ||
120 | int ossl_provider_upref(OSSL_PROVIDER *prov) | |
121 | { | |
122 | int ref = 0; | |
123 | ||
4c2883a9 | 124 | CRYPTO_UP_REF(&prov->refcnt, &ref, prov->refcnt_lock); |
4c2883a9 RL |
125 | return ref; |
126 | } | |
127 | ||
128 | /* Finder, constructor and destructor */ | |
129 | OSSL_PROVIDER *ossl_provider_find(OPENSSL_CTX *libctx, const char *name) | |
130 | { | |
131 | struct provider_store_st *store = NULL; | |
132 | OSSL_PROVIDER *prov = NULL; | |
133 | ||
134 | if ((store = get_provider_store(libctx)) != NULL) { | |
135 | OSSL_PROVIDER tmpl = { 0, }; | |
136 | int i; | |
137 | ||
138 | tmpl.name = (char *)name; | |
139 | CRYPTO_THREAD_write_lock(store->lock); | |
140 | if ((i = sk_OSSL_PROVIDER_find(store->providers, &tmpl)) == -1 | |
141 | || (prov = sk_OSSL_PROVIDER_value(store->providers, i)) == NULL | |
142 | || !ossl_provider_upref(prov)) | |
143 | prov = NULL; | |
144 | CRYPTO_THREAD_unlock(store->lock); | |
145 | } | |
146 | ||
147 | return prov; | |
148 | } | |
149 | ||
150 | OSSL_PROVIDER *ossl_provider_new(OPENSSL_CTX *libctx, const char *name, | |
151 | OSSL_provider_init_fn *init_function) | |
152 | { | |
153 | struct provider_store_st *store = NULL; | |
154 | OSSL_PROVIDER *prov = NULL; | |
155 | ||
156 | if ((store = get_provider_store(libctx)) == NULL) | |
157 | return NULL; | |
158 | ||
159 | if ((prov = ossl_provider_find(libctx, name)) != NULL) { /* refcount +1 */ | |
160 | ossl_provider_free(prov); /* refcount -1 */ | |
161 | CRYPTOerr(CRYPTO_F_OSSL_PROVIDER_NEW, | |
162 | CRYPTO_R_PROVIDER_ALREADY_EXISTS); | |
163 | ERR_add_error_data(2, "name=", name); | |
164 | return NULL; | |
165 | } | |
166 | ||
167 | if ((prov = OPENSSL_zalloc(sizeof(*prov))) == NULL | |
085bef9f RL |
168 | #ifndef HAVE_ATOMICS |
169 | || (prov->refcnt_lock = CRYPTO_THREAD_lock_new()) == NULL | |
170 | #endif | |
4c2883a9 RL |
171 | || !ossl_provider_upref(prov) /* +1 One reference to be returned */ |
172 | || (prov->name = OPENSSL_strdup(name)) == NULL) { | |
173 | ossl_provider_free(prov); | |
174 | CRYPTOerr(CRYPTO_F_OSSL_PROVIDER_NEW, ERR_R_MALLOC_FAILURE); | |
175 | return NULL; | |
176 | } | |
177 | ||
178 | prov->init_function = init_function; | |
179 | ||
180 | CRYPTO_THREAD_write_lock(store->lock); | |
181 | if (!ossl_provider_upref(prov)) { /* +1 One reference for the store */ | |
182 | ossl_provider_free(prov); /* -1 Reference that was to be returned */ | |
183 | prov = NULL; | |
184 | } else if (sk_OSSL_PROVIDER_push(store->providers, prov) == 0) { | |
185 | ossl_provider_free(prov); /* -1 Store reference */ | |
186 | ossl_provider_free(prov); /* -1 Reference that was to be returned */ | |
187 | prov = NULL; | |
188 | } | |
189 | CRYPTO_THREAD_unlock(store->lock); | |
190 | ||
191 | if (prov == NULL) | |
192 | CRYPTOerr(CRYPTO_F_OSSL_PROVIDER_NEW, ERR_R_MALLOC_FAILURE); | |
193 | ||
194 | /* | |
195 | * At this point, the provider is only partially "loaded". To be | |
196 | * fully "loaded", ossl_provider_activate() must also be called. | |
197 | */ | |
198 | ||
199 | return prov; | |
200 | } | |
201 | ||
202 | void ossl_provider_free(OSSL_PROVIDER *prov) | |
203 | { | |
204 | if (prov != NULL) { | |
205 | int ref = 0; | |
206 | ||
085bef9f | 207 | CRYPTO_DOWN_REF(&prov->refcnt, &ref, prov->refcnt_lock); |
4c2883a9 RL |
208 | |
209 | /* | |
210 | * When the refcount drops down to one, there is only one reference, | |
211 | * the store. | |
212 | * When that happens, the provider is inactivated. | |
213 | */ | |
214 | if (ref == 1 && prov->flag_initialized) { | |
215 | if (prov->teardown != NULL) | |
216 | prov->teardown(); | |
217 | prov->flag_initialized = 0; | |
218 | } | |
219 | ||
220 | /* | |
221 | * When the refcount drops to zero, it has been taken out of | |
222 | * the store. All we have to do here is clean it out. | |
223 | */ | |
224 | if (ref == 0) { | |
225 | DSO_free(prov->module); | |
226 | OPENSSL_free(prov->name); | |
085bef9f RL |
227 | #ifndef HAVE_ATOMICS |
228 | CRYPTO_THREAD_lock_free(prov->refcnt_lock); | |
229 | #endif | |
4c2883a9 RL |
230 | OPENSSL_free(prov); |
231 | } | |
232 | } | |
233 | } | |
234 | ||
235 | /* | |
236 | * Provider activation. | |
237 | * | |
238 | * What "activation" means depends on the provider form; for built in | |
239 | * providers (in the library or the application alike), the provider | |
240 | * can already be considered to be loaded, all that's needed is to | |
241 | * initialize it. However, for dynamically loadable provider modules, | |
242 | * we must first load that module. | |
243 | * | |
244 | * Built in modules are distinguished from dynamically loaded modules | |
245 | * with an already assigned init function. | |
246 | */ | |
247 | static const OSSL_DISPATCH *core_dispatch; /* Define further down */ | |
248 | ||
249 | int ossl_provider_activate(OSSL_PROVIDER *prov) | |
250 | { | |
251 | const OSSL_DISPATCH *provider_dispatch = NULL; | |
252 | ||
253 | if (prov->flag_initialized) | |
254 | return 1; | |
255 | ||
256 | /* | |
257 | * If the init function isn't set, it indicates that this provider is | |
258 | * a loadable module. | |
259 | */ | |
260 | if (prov->init_function == NULL) { | |
261 | if (prov->module == NULL) { | |
262 | char *platform_module_name = NULL; | |
263 | char *module_path = NULL; | |
264 | const char *load_dir = ossl_safe_getenv("OPENSSL_MODULES"); | |
265 | ||
266 | if ((prov->module = DSO_new()) == NULL) { | |
267 | /* DSO_new() generates an error already */ | |
268 | return 0; | |
269 | } | |
270 | ||
271 | if (load_dir == NULL) | |
272 | load_dir = MODULESDIR; | |
273 | ||
274 | DSO_ctrl(prov->module, DSO_CTRL_SET_FLAGS, | |
275 | DSO_FLAG_NAME_TRANSLATION_EXT_ONLY, NULL); | |
276 | if ((platform_module_name = | |
277 | DSO_convert_filename(prov->module, prov->name)) == NULL | |
278 | || (module_path = | |
279 | DSO_merge(prov->module, platform_module_name, | |
280 | load_dir)) == NULL | |
281 | || DSO_load(prov->module, module_path, NULL, | |
282 | DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == NULL) { | |
283 | DSO_free(prov->module); | |
284 | prov->module = NULL; | |
285 | } | |
286 | ||
287 | OPENSSL_free(platform_module_name); | |
288 | OPENSSL_free(module_path); | |
289 | } | |
290 | ||
291 | if (prov->module != NULL) | |
292 | prov->init_function = (OSSL_provider_init_fn *) | |
293 | DSO_bind_func(prov->module, "OSSL_provider_init"); | |
294 | } | |
295 | ||
296 | if (prov->init_function == NULL | |
297 | || !prov->init_function(prov, core_dispatch, &provider_dispatch)) { | |
298 | CRYPTOerr(CRYPTO_F_OSSL_PROVIDER_ACTIVATE, ERR_R_INIT_FAIL); | |
299 | ERR_add_error_data(2, "name=", prov->name); | |
300 | DSO_free(prov->module); | |
301 | prov->module = NULL; | |
302 | return 0; | |
303 | } | |
304 | ||
305 | for (; provider_dispatch->function_id != 0; provider_dispatch++) { | |
306 | switch (provider_dispatch->function_id) { | |
307 | case OSSL_FUNC_PROVIDER_TEARDOWN: | |
308 | prov->teardown = | |
309 | OSSL_get_provider_teardown(provider_dispatch); | |
310 | break; | |
311 | case OSSL_FUNC_PROVIDER_GET_PARAM_TYPES: | |
312 | prov->get_param_types = | |
313 | OSSL_get_provider_get_param_types(provider_dispatch); | |
314 | break; | |
315 | case OSSL_FUNC_PROVIDER_GET_PARAMS: | |
316 | prov->get_params = | |
317 | OSSL_get_provider_get_params(provider_dispatch); | |
318 | break; | |
099bd339 RL |
319 | case OSSL_FUNC_PROVIDER_QUERY_OPERATION: |
320 | prov->query_operation = | |
321 | OSSL_get_provider_query_operation(provider_dispatch); | |
322 | break; | |
4c2883a9 RL |
323 | } |
324 | } | |
325 | ||
326 | /* With this flag set, this provider has become fully "loaded". */ | |
327 | prov->flag_initialized = 1; | |
328 | ||
329 | return 1; | |
330 | } | |
331 | ||
85e2417c RL |
332 | int ossl_provider_forall_loaded(OPENSSL_CTX *ctx, |
333 | int (*cb)(OSSL_PROVIDER *provider, | |
334 | void *cbdata), | |
335 | void *cbdata) | |
336 | { | |
337 | int ret = 1; | |
338 | int i; | |
339 | struct provider_store_st *store = get_provider_store(ctx); | |
340 | ||
341 | if (store != NULL) { | |
342 | CRYPTO_THREAD_read_lock(store->lock); | |
343 | for (i = 0; i < sk_OSSL_PROVIDER_num(store->providers); i++) { | |
344 | OSSL_PROVIDER *prov = sk_OSSL_PROVIDER_value(store->providers, i); | |
345 | ||
346 | if (prov->flag_initialized | |
347 | && !(ret = cb(prov, cbdata))) | |
348 | break; | |
349 | } | |
350 | CRYPTO_THREAD_unlock(store->lock); | |
351 | } | |
352 | ||
353 | return ret; | |
354 | } | |
355 | ||
4c2883a9 RL |
356 | /* Getters of Provider Object data */ |
357 | const char *ossl_provider_name(OSSL_PROVIDER *prov) | |
358 | { | |
359 | return prov->name; | |
360 | } | |
361 | ||
362 | const DSO *ossl_provider_dso(OSSL_PROVIDER *prov) | |
363 | { | |
364 | return prov->module; | |
365 | } | |
366 | ||
367 | const char *ossl_provider_module_name(OSSL_PROVIDER *prov) | |
368 | { | |
369 | return DSO_get_filename(prov->module); | |
370 | } | |
371 | ||
372 | const char *ossl_provider_module_path(OSSL_PROVIDER *prov) | |
373 | { | |
374 | /* FIXME: Ensure it's a full path */ | |
375 | return DSO_get_filename(prov->module); | |
376 | } | |
377 | ||
378 | /* Wrappers around calls to the provider */ | |
379 | void ossl_provider_teardown(const OSSL_PROVIDER *prov) | |
380 | { | |
381 | if (prov->teardown != NULL) | |
382 | prov->teardown(); | |
383 | } | |
384 | ||
385 | const OSSL_ITEM *ossl_provider_get_param_types(const OSSL_PROVIDER *prov) | |
386 | { | |
387 | return prov->get_param_types == NULL ? NULL : prov->get_param_types(prov); | |
388 | } | |
389 | ||
390 | int ossl_provider_get_params(const OSSL_PROVIDER *prov, | |
391 | const OSSL_PARAM params[]) | |
392 | { | |
393 | return prov->get_params == NULL ? 0 : prov->get_params(prov, params); | |
394 | } | |
395 | ||
099bd339 RL |
396 | |
397 | const OSSL_ALGORITHM *ossl_provider_query_operation(const OSSL_PROVIDER *prov, | |
398 | int operation_id, | |
399 | int *no_cache) | |
400 | { | |
401 | return prov->query_operation(prov, operation_id, no_cache); | |
402 | } | |
403 | ||
4c2883a9 RL |
404 | /*- |
405 | * Core functions for the provider | |
406 | * =============================== | |
407 | * | |
408 | * This is the set of functions that the core makes available to the provider | |
409 | */ | |
410 | ||
411 | /* | |
412 | * This returns a list of Provider Object parameters with their types, for | |
413 | * discovery. We do not expect that many providers will use this, but one | |
414 | * never knows. | |
415 | */ | |
416 | static const OSSL_ITEM param_types[] = { | |
e2146e12 RL |
417 | { OSSL_PARAM_UTF8_PTR, "openssl-version" }, |
418 | { OSSL_PARAM_UTF8_PTR, "provider-name" }, | |
4c2883a9 RL |
419 | { 0, NULL } |
420 | }; | |
421 | ||
422 | static const OSSL_ITEM *core_get_param_types(const OSSL_PROVIDER *prov) | |
423 | { | |
424 | return param_types; | |
425 | } | |
426 | ||
427 | static int core_get_params(const OSSL_PROVIDER *prov, const OSSL_PARAM params[]) | |
428 | { | |
429 | int i; | |
430 | ||
431 | for (i = 0; params[i].key != NULL; i++) { | |
432 | if (strcmp(params[i].key, "openssl-version") == 0) { | |
8c4412ed | 433 | *(void **)params[i].data = OPENSSL_VERSION_STR; |
4c2883a9 RL |
434 | if (params[i].return_size) |
435 | *params[i].return_size = sizeof(OPENSSL_VERSION_STR); | |
436 | } else if (strcmp(params[i].key, "provider-name") == 0) { | |
8c4412ed | 437 | *(void **)params[i].data = prov->name; |
4c2883a9 RL |
438 | if (params[i].return_size) |
439 | *params[i].return_size = strlen(prov->name) + 1; | |
440 | } | |
441 | } | |
442 | ||
443 | return 1; | |
444 | } | |
445 | ||
446 | static const OSSL_DISPATCH core_dispatch_[] = { | |
447 | { OSSL_FUNC_CORE_GET_PARAM_TYPES, (void (*)(void))core_get_param_types }, | |
448 | { OSSL_FUNC_CORE_GET_PARAMS, (void (*)(void))core_get_params }, | |
449 | { 0, NULL } | |
450 | }; | |
451 | static const OSSL_DISPATCH *core_dispatch = core_dispatch_; |