]>
Commit | Line | Data |
---|---|---|
c4fc564d RL |
1 | /* |
2 | * Copyright 2020 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/store.h> | |
11 | #include <openssl/crypto.h> | |
12 | #include "internal/core.h" | |
13 | #include "internal/namemap.h" | |
14 | #include "internal/property.h" | |
15 | #include "internal/provider.h" | |
16 | #include "store_local.h" | |
17 | ||
18 | int OSSL_STORE_LOADER_up_ref(OSSL_STORE_LOADER *loader) | |
19 | { | |
20 | int ref = 0; | |
21 | ||
22 | if (loader->prov != NULL) | |
23 | CRYPTO_UP_REF(&loader->refcnt, &ref, loader->lock); | |
24 | return 1; | |
25 | } | |
26 | ||
27 | void OSSL_STORE_LOADER_free(OSSL_STORE_LOADER *loader) | |
28 | { | |
29 | if (loader != NULL && loader->prov != NULL) { | |
30 | int i; | |
31 | ||
32 | CRYPTO_DOWN_REF(&loader->refcnt, &i, loader->lock); | |
33 | if (i > 0) | |
34 | return; | |
35 | ossl_provider_free(loader->prov); | |
36 | CRYPTO_THREAD_lock_free(loader->lock); | |
37 | } | |
38 | OPENSSL_free(loader); | |
39 | } | |
40 | ||
41 | /* | |
42 | * OSSL_STORE_LOADER_new() expects the scheme as a constant string, | |
43 | * which we currently don't have, so we need an alternative allocator. | |
44 | */ | |
45 | static OSSL_STORE_LOADER *new_loader(OSSL_PROVIDER *prov) | |
46 | { | |
47 | OSSL_STORE_LOADER *loader; | |
48 | ||
49 | if ((loader = OPENSSL_zalloc(sizeof(*loader))) == NULL | |
50 | || (loader->lock = CRYPTO_THREAD_lock_new()) == NULL) { | |
51 | OPENSSL_free(loader); | |
52 | return NULL; | |
53 | } | |
54 | loader->prov = prov; | |
55 | ossl_provider_up_ref(prov); | |
56 | loader->refcnt = 1; | |
57 | ||
58 | return loader; | |
59 | } | |
60 | ||
61 | static int up_ref_loader(void *method) | |
62 | { | |
63 | return OSSL_STORE_LOADER_up_ref(method); | |
64 | } | |
65 | ||
66 | static void free_loader(void *method) | |
67 | { | |
68 | OSSL_STORE_LOADER_free(method); | |
69 | } | |
70 | ||
71 | /* Permanent loader method store, constructor and destructor */ | |
72 | static void loader_store_free(void *vstore) | |
73 | { | |
74 | ossl_method_store_free(vstore); | |
75 | } | |
76 | ||
b4250010 | 77 | static void *loader_store_new(OSSL_LIB_CTX *ctx) |
c4fc564d RL |
78 | { |
79 | return ossl_method_store_new(ctx); | |
80 | } | |
81 | ||
82 | ||
b4250010 | 83 | static const OSSL_LIB_CTX_METHOD loader_store_method = { |
c4fc564d RL |
84 | loader_store_new, |
85 | loader_store_free, | |
86 | }; | |
87 | ||
88 | /* Data to be passed through ossl_method_construct() */ | |
89 | struct loader_data_st { | |
b4250010 | 90 | OSSL_LIB_CTX *libctx; |
c4fc564d RL |
91 | OSSL_METHOD_CONSTRUCT_METHOD *mcm; |
92 | int scheme_id; /* For get_loader_from_store() */ | |
93 | const char *scheme; /* For get_loader_from_store() */ | |
94 | const char *propquery; /* For get_loader_from_store() */ | |
95 | }; | |
96 | ||
97 | /* | |
98 | * Generic routines to fetch / create OSSL_STORE methods with | |
99 | * ossl_method_construct() | |
100 | */ | |
101 | ||
102 | /* Temporary loader method store, constructor and destructor */ | |
b4250010 | 103 | static void *alloc_tmp_loader_store(OSSL_LIB_CTX *ctx) |
c4fc564d RL |
104 | { |
105 | return ossl_method_store_new(ctx); | |
106 | } | |
107 | ||
108 | static void dealloc_tmp_loader_store(void *store) | |
109 | { | |
110 | if (store != NULL) | |
111 | ossl_method_store_free(store); | |
112 | } | |
113 | ||
114 | /* Get the permanent loader store */ | |
b4250010 | 115 | static OSSL_METHOD_STORE *get_loader_store(OSSL_LIB_CTX *libctx) |
c4fc564d | 116 | { |
b4250010 | 117 | return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_STORE_LOADER_STORE_INDEX, |
c4fc564d RL |
118 | &loader_store_method); |
119 | } | |
120 | ||
121 | /* Get loader methods from a store, or put one in */ | |
b4250010 | 122 | static void *get_loader_from_store(OSSL_LIB_CTX *libctx, void *store, |
c4fc564d RL |
123 | void *data) |
124 | { | |
125 | struct loader_data_st *methdata = data; | |
126 | void *method = NULL; | |
127 | int id; | |
128 | ||
129 | if ((id = methdata->scheme_id) == 0) { | |
130 | OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); | |
131 | ||
132 | id = ossl_namemap_name2num(namemap, methdata->scheme); | |
133 | } | |
134 | ||
135 | if (store == NULL | |
136 | && (store = get_loader_store(libctx)) == NULL) | |
137 | return NULL; | |
138 | ||
139 | if (!ossl_method_store_fetch(store, id, methdata->propquery, &method)) | |
140 | return NULL; | |
141 | return method; | |
142 | } | |
143 | ||
b4250010 | 144 | static int put_loader_in_store(OSSL_LIB_CTX *libctx, void *store, |
c4fc564d RL |
145 | void *method, const OSSL_PROVIDER *prov, |
146 | int operation_id, const char *scheme, | |
147 | const char *propdef, void *unused) | |
148 | { | |
149 | OSSL_NAMEMAP *namemap; | |
150 | int id; | |
151 | ||
152 | if ((namemap = ossl_namemap_stored(libctx)) == NULL | |
153 | || (id = ossl_namemap_name2num(namemap, scheme)) == 0) | |
154 | return 0; | |
155 | ||
156 | if (store == NULL && (store = get_loader_store(libctx)) == NULL) | |
157 | return 0; | |
158 | ||
159 | return ossl_method_store_add(store, prov, id, propdef, method, | |
160 | up_ref_loader, free_loader); | |
161 | } | |
162 | ||
163 | static void *loader_from_dispatch(int scheme_id, const OSSL_ALGORITHM *algodef, | |
164 | OSSL_PROVIDER *prov) | |
165 | { | |
166 | OSSL_STORE_LOADER *loader = NULL; | |
167 | const OSSL_DISPATCH *fns = algodef->implementation; | |
168 | ||
169 | if ((loader = new_loader(prov)) == NULL) | |
170 | return NULL; | |
171 | loader->scheme_id = scheme_id; | |
172 | loader->propdef = algodef->property_definition; | |
173 | ||
174 | for (; fns->function_id != 0; fns++) { | |
175 | switch (fns->function_id) { | |
176 | case OSSL_FUNC_STORE_OPEN: | |
177 | if (loader->p_open == NULL) | |
178 | loader->p_open = OSSL_FUNC_store_open(fns); | |
179 | break; | |
180 | case OSSL_FUNC_STORE_ATTACH: | |
181 | if (loader->p_attach == NULL) | |
182 | loader->p_attach = OSSL_FUNC_store_attach(fns); | |
183 | break; | |
184 | case OSSL_FUNC_STORE_SETTABLE_CTX_PARAMS: | |
185 | if (loader->p_settable_ctx_params == NULL) | |
186 | loader->p_settable_ctx_params = | |
187 | OSSL_FUNC_store_settable_ctx_params(fns); | |
188 | break; | |
189 | case OSSL_FUNC_STORE_SET_CTX_PARAMS: | |
190 | if (loader->p_set_ctx_params == NULL) | |
191 | loader->p_set_ctx_params = OSSL_FUNC_store_set_ctx_params(fns); | |
192 | break; | |
193 | case OSSL_FUNC_STORE_LOAD: | |
194 | if (loader->p_load == NULL) | |
195 | loader->p_load = OSSL_FUNC_store_load(fns); | |
196 | break; | |
197 | case OSSL_FUNC_STORE_EOF: | |
198 | if (loader->p_eof == NULL) | |
199 | loader->p_eof = OSSL_FUNC_store_eof(fns); | |
200 | break; | |
201 | case OSSL_FUNC_STORE_CLOSE: | |
202 | if (loader->p_close == NULL) | |
203 | loader->p_close = OSSL_FUNC_store_close(fns); | |
204 | break; | |
205 | case OSSL_FUNC_STORE_EXPORT_OBJECT: | |
206 | if (loader->p_export_object == NULL) | |
207 | loader->p_export_object = OSSL_FUNC_store_export_object(fns); | |
208 | break; | |
209 | } | |
210 | } | |
211 | ||
212 | if ((loader->p_open == NULL && loader->p_attach == NULL) | |
213 | || loader->p_load == NULL | |
214 | || loader->p_eof == NULL | |
215 | || loader->p_close == NULL) { | |
216 | /* Only set_ctx_params is optionaal */ | |
217 | OSSL_STORE_LOADER_free(loader); | |
218 | ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADER_INCOMPLETE); | |
219 | return NULL; | |
220 | } | |
221 | return loader; | |
222 | } | |
223 | ||
224 | /* | |
225 | * The core fetching functionality passes the scheme of the implementation. | |
226 | * This function is responsible to getting an identity number for them, | |
227 | * then call loader_from_dispatch() with that identity number. | |
228 | */ | |
229 | static void *construct_loader(const OSSL_ALGORITHM *algodef, | |
230 | OSSL_PROVIDER *prov, void *unused) | |
231 | { | |
232 | /* | |
233 | * This function is only called if get_loader_from_store() returned | |
234 | * NULL, so it's safe to say that of all the spots to create a new | |
235 | * namemap entry, this is it. Should the scheme already exist there, we | |
236 | * know that ossl_namemap_add() will return its corresponding number. | |
237 | */ | |
b4250010 | 238 | OSSL_LIB_CTX *libctx = ossl_provider_library_context(prov); |
c4fc564d RL |
239 | OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); |
240 | const char *scheme = algodef->algorithm_names; | |
241 | int id = ossl_namemap_add_name(namemap, 0, scheme); | |
242 | void *method = NULL; | |
243 | ||
244 | if (id != 0) | |
245 | method = loader_from_dispatch(id, algodef, prov); | |
246 | ||
247 | return method; | |
248 | } | |
249 | ||
250 | /* Intermediary function to avoid ugly casts, used below */ | |
251 | static void destruct_loader(void *method, void *data) | |
252 | { | |
253 | OSSL_STORE_LOADER_free(method); | |
254 | } | |
255 | ||
256 | /* Fetching support. Can fetch by numeric identity or by scheme */ | |
b4250010 | 257 | static OSSL_STORE_LOADER *inner_loader_fetch(OSSL_LIB_CTX *libctx, |
c4fc564d RL |
258 | int id, const char *scheme, |
259 | const char *properties) | |
260 | { | |
261 | OSSL_METHOD_STORE *store = get_loader_store(libctx); | |
262 | OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); | |
263 | void *method = NULL; | |
264 | ||
265 | if (store == NULL || namemap == NULL) | |
266 | return NULL; | |
267 | ||
268 | /* | |
269 | * If we have been passed neither a scheme_id or a scheme, we have an | |
270 | * internal programming error. | |
271 | */ | |
272 | if (!ossl_assert(id != 0 || scheme != NULL)) | |
273 | return NULL; | |
274 | ||
275 | if (id == 0) | |
276 | id = ossl_namemap_name2num(namemap, scheme); | |
277 | ||
278 | if (id == 0 | |
279 | || !ossl_method_store_cache_get(store, id, properties, &method)) { | |
280 | OSSL_METHOD_CONSTRUCT_METHOD mcm = { | |
281 | alloc_tmp_loader_store, | |
282 | dealloc_tmp_loader_store, | |
283 | get_loader_from_store, | |
284 | put_loader_in_store, | |
285 | construct_loader, | |
286 | destruct_loader | |
287 | }; | |
288 | struct loader_data_st mcmdata; | |
289 | ||
290 | mcmdata.libctx = libctx; | |
291 | mcmdata.mcm = &mcm; | |
292 | mcmdata.scheme_id = id; | |
293 | mcmdata.scheme = scheme; | |
294 | mcmdata.propquery = properties; | |
295 | if ((method = ossl_method_construct(libctx, OSSL_OP_STORE, | |
296 | 0 /* !force_cache */, | |
297 | &mcm, &mcmdata)) != NULL) { | |
298 | /* | |
299 | * If construction did create a method for us, we know that there | |
300 | * is a correct scheme_id, since those have already been calculated | |
301 | * in get_loader_from_store() and put_loader_in_store() above. | |
302 | */ | |
303 | if (id == 0) | |
304 | id = ossl_namemap_name2num(namemap, scheme); | |
305 | ossl_method_store_cache_set(store, id, properties, method, | |
306 | up_ref_loader, free_loader); | |
307 | } | |
308 | } | |
309 | ||
310 | return method; | |
311 | } | |
312 | ||
313 | OSSL_STORE_LOADER *OSSL_STORE_LOADER_fetch(const char *scheme, | |
b4250010 | 314 | OSSL_LIB_CTX *libctx, |
c4fc564d RL |
315 | const char *properties) |
316 | { | |
317 | return inner_loader_fetch(libctx, 0, scheme, properties); | |
318 | } | |
319 | ||
b4250010 | 320 | OSSL_STORE_LOADER *ossl_store_loader_fetch_by_number(OSSL_LIB_CTX *libctx, |
c4fc564d RL |
321 | int scheme_id, |
322 | const char *properties) | |
323 | { | |
324 | return inner_loader_fetch(libctx, scheme_id, NULL, properties); | |
325 | } | |
326 | ||
327 | /* | |
328 | * Library of basic method functions | |
329 | */ | |
330 | ||
331 | const OSSL_PROVIDER *OSSL_STORE_LOADER_provider(const OSSL_STORE_LOADER *loader) | |
332 | { | |
333 | if (!ossl_assert(loader != NULL)) { | |
334 | ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER); | |
335 | return 0; | |
336 | } | |
337 | ||
338 | return loader->prov; | |
339 | } | |
340 | ||
341 | const char *OSSL_STORE_LOADER_properties(const OSSL_STORE_LOADER *loader) | |
342 | { | |
343 | if (!ossl_assert(loader != NULL)) { | |
344 | ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER); | |
345 | return 0; | |
346 | } | |
347 | ||
348 | return loader->propdef; | |
349 | } | |
350 | ||
351 | int OSSL_STORE_LOADER_number(const OSSL_STORE_LOADER *loader) | |
352 | { | |
353 | if (!ossl_assert(loader != NULL)) { | |
354 | ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER); | |
355 | return 0; | |
356 | } | |
357 | ||
358 | return loader->scheme_id; | |
359 | } | |
360 | ||
361 | int OSSL_STORE_LOADER_is_a(const OSSL_STORE_LOADER *loader, const char *name) | |
362 | { | |
363 | if (loader->prov != NULL) { | |
b4250010 | 364 | OSSL_LIB_CTX *libctx = ossl_provider_library_context(loader->prov); |
c4fc564d RL |
365 | OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); |
366 | ||
367 | return ossl_namemap_name2num(namemap, name) == loader->scheme_id; | |
368 | } | |
369 | return 0; | |
370 | } | |
371 | ||
372 | struct loader_do_all_data_st { | |
373 | void (*user_fn)(void *method, void *arg); | |
374 | void *user_arg; | |
375 | }; | |
376 | ||
377 | static void loader_do_one(OSSL_PROVIDER *provider, | |
378 | const OSSL_ALGORITHM *algodef, | |
379 | int no_store, void *vdata) | |
380 | { | |
381 | struct loader_do_all_data_st *data = vdata; | |
b4250010 | 382 | OSSL_LIB_CTX *libctx = ossl_provider_library_context(provider); |
c4fc564d RL |
383 | OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); |
384 | const char *name = algodef->algorithm_names; | |
385 | int id = ossl_namemap_add_name(namemap, 0, name); | |
386 | void *method = NULL; | |
387 | ||
388 | if (id != 0) | |
389 | method = | |
390 | loader_from_dispatch(id, algodef, provider); | |
391 | ||
392 | if (method != NULL) { | |
393 | data->user_fn(method, data->user_arg); | |
394 | OSSL_STORE_LOADER_free(method); | |
395 | } | |
396 | } | |
397 | ||
b4250010 | 398 | void OSSL_STORE_LOADER_do_all_provided(OSSL_LIB_CTX *libctx, |
c4fc564d RL |
399 | void (*fn)(OSSL_STORE_LOADER *loader, |
400 | void *arg), | |
401 | void *arg) | |
402 | { | |
403 | struct loader_do_all_data_st data; | |
404 | ||
405 | data.user_fn = (void (*)(void *, void *))fn; | |
406 | data.user_arg = arg; | |
407 | ossl_algorithm_do_all(libctx, OSSL_OP_STORE, NULL, | |
408 | NULL, loader_do_one, NULL, | |
409 | &data); | |
410 | } | |
411 | ||
412 | void OSSL_STORE_LOADER_names_do_all(const OSSL_STORE_LOADER *loader, | |
413 | void (*fn)(const char *name, void *data), | |
414 | void *data) | |
415 | { | |
416 | if (loader == NULL) | |
417 | return; | |
418 | ||
419 | if (loader->prov != NULL) { | |
b4250010 | 420 | OSSL_LIB_CTX *libctx = ossl_provider_library_context(loader->prov); |
c4fc564d RL |
421 | OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); |
422 | ||
423 | ossl_namemap_doall_names(namemap, loader->scheme_id, fn, data); | |
424 | } | |
425 | } |