]>
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() */ | |
d6d42cda RL |
95 | |
96 | unsigned int flag_construct_error_occured : 1; | |
c4fc564d RL |
97 | }; |
98 | ||
99 | /* | |
100 | * Generic routines to fetch / create OSSL_STORE methods with | |
101 | * ossl_method_construct() | |
102 | */ | |
103 | ||
104 | /* Temporary loader method store, constructor and destructor */ | |
b4250010 | 105 | static void *alloc_tmp_loader_store(OSSL_LIB_CTX *ctx) |
c4fc564d RL |
106 | { |
107 | return ossl_method_store_new(ctx); | |
108 | } | |
109 | ||
110 | static void dealloc_tmp_loader_store(void *store) | |
111 | { | |
112 | if (store != NULL) | |
113 | ossl_method_store_free(store); | |
114 | } | |
115 | ||
116 | /* Get the permanent loader store */ | |
b4250010 | 117 | static OSSL_METHOD_STORE *get_loader_store(OSSL_LIB_CTX *libctx) |
c4fc564d | 118 | { |
b4250010 | 119 | return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_STORE_LOADER_STORE_INDEX, |
c4fc564d RL |
120 | &loader_store_method); |
121 | } | |
122 | ||
123 | /* Get loader methods from a store, or put one in */ | |
b4250010 | 124 | static void *get_loader_from_store(OSSL_LIB_CTX *libctx, void *store, |
c4fc564d RL |
125 | void *data) |
126 | { | |
127 | struct loader_data_st *methdata = data; | |
128 | void *method = NULL; | |
129 | int id; | |
130 | ||
131 | if ((id = methdata->scheme_id) == 0) { | |
132 | OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); | |
133 | ||
134 | id = ossl_namemap_name2num(namemap, methdata->scheme); | |
135 | } | |
136 | ||
137 | if (store == NULL | |
138 | && (store = get_loader_store(libctx)) == NULL) | |
139 | return NULL; | |
140 | ||
141 | if (!ossl_method_store_fetch(store, id, methdata->propquery, &method)) | |
142 | return NULL; | |
143 | return method; | |
144 | } | |
145 | ||
b4250010 | 146 | static int put_loader_in_store(OSSL_LIB_CTX *libctx, void *store, |
c4fc564d RL |
147 | void *method, const OSSL_PROVIDER *prov, |
148 | int operation_id, const char *scheme, | |
149 | const char *propdef, void *unused) | |
150 | { | |
151 | OSSL_NAMEMAP *namemap; | |
152 | int id; | |
153 | ||
154 | if ((namemap = ossl_namemap_stored(libctx)) == NULL | |
155 | || (id = ossl_namemap_name2num(namemap, scheme)) == 0) | |
156 | return 0; | |
157 | ||
158 | if (store == NULL && (store = get_loader_store(libctx)) == NULL) | |
159 | return 0; | |
160 | ||
161 | return ossl_method_store_add(store, prov, id, propdef, method, | |
162 | up_ref_loader, free_loader); | |
163 | } | |
164 | ||
165 | static void *loader_from_dispatch(int scheme_id, const OSSL_ALGORITHM *algodef, | |
166 | OSSL_PROVIDER *prov) | |
167 | { | |
168 | OSSL_STORE_LOADER *loader = NULL; | |
169 | const OSSL_DISPATCH *fns = algodef->implementation; | |
170 | ||
171 | if ((loader = new_loader(prov)) == NULL) | |
172 | return NULL; | |
173 | loader->scheme_id = scheme_id; | |
174 | loader->propdef = algodef->property_definition; | |
175 | ||
176 | for (; fns->function_id != 0; fns++) { | |
177 | switch (fns->function_id) { | |
178 | case OSSL_FUNC_STORE_OPEN: | |
179 | if (loader->p_open == NULL) | |
180 | loader->p_open = OSSL_FUNC_store_open(fns); | |
181 | break; | |
182 | case OSSL_FUNC_STORE_ATTACH: | |
183 | if (loader->p_attach == NULL) | |
184 | loader->p_attach = OSSL_FUNC_store_attach(fns); | |
185 | break; | |
186 | case OSSL_FUNC_STORE_SETTABLE_CTX_PARAMS: | |
187 | if (loader->p_settable_ctx_params == NULL) | |
188 | loader->p_settable_ctx_params = | |
189 | OSSL_FUNC_store_settable_ctx_params(fns); | |
190 | break; | |
191 | case OSSL_FUNC_STORE_SET_CTX_PARAMS: | |
192 | if (loader->p_set_ctx_params == NULL) | |
193 | loader->p_set_ctx_params = OSSL_FUNC_store_set_ctx_params(fns); | |
194 | break; | |
195 | case OSSL_FUNC_STORE_LOAD: | |
196 | if (loader->p_load == NULL) | |
197 | loader->p_load = OSSL_FUNC_store_load(fns); | |
198 | break; | |
199 | case OSSL_FUNC_STORE_EOF: | |
200 | if (loader->p_eof == NULL) | |
201 | loader->p_eof = OSSL_FUNC_store_eof(fns); | |
202 | break; | |
203 | case OSSL_FUNC_STORE_CLOSE: | |
204 | if (loader->p_close == NULL) | |
205 | loader->p_close = OSSL_FUNC_store_close(fns); | |
206 | break; | |
207 | case OSSL_FUNC_STORE_EXPORT_OBJECT: | |
208 | if (loader->p_export_object == NULL) | |
209 | loader->p_export_object = OSSL_FUNC_store_export_object(fns); | |
210 | break; | |
211 | } | |
212 | } | |
213 | ||
214 | if ((loader->p_open == NULL && loader->p_attach == NULL) | |
215 | || loader->p_load == NULL | |
216 | || loader->p_eof == NULL | |
217 | || loader->p_close == NULL) { | |
218 | /* Only set_ctx_params is optionaal */ | |
219 | OSSL_STORE_LOADER_free(loader); | |
220 | ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADER_INCOMPLETE); | |
221 | return NULL; | |
222 | } | |
223 | return loader; | |
224 | } | |
225 | ||
226 | /* | |
227 | * The core fetching functionality passes the scheme of the implementation. | |
228 | * This function is responsible to getting an identity number for them, | |
229 | * then call loader_from_dispatch() with that identity number. | |
230 | */ | |
231 | static void *construct_loader(const OSSL_ALGORITHM *algodef, | |
d6d42cda | 232 | OSSL_PROVIDER *prov, void *data) |
c4fc564d RL |
233 | { |
234 | /* | |
235 | * This function is only called if get_loader_from_store() returned | |
236 | * NULL, so it's safe to say that of all the spots to create a new | |
237 | * namemap entry, this is it. Should the scheme already exist there, we | |
238 | * know that ossl_namemap_add() will return its corresponding number. | |
239 | */ | |
d6d42cda | 240 | struct loader_data_st *methdata = data; |
a829b735 | 241 | OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov); |
c4fc564d RL |
242 | OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); |
243 | const char *scheme = algodef->algorithm_names; | |
244 | int id = ossl_namemap_add_name(namemap, 0, scheme); | |
245 | void *method = NULL; | |
246 | ||
247 | if (id != 0) | |
248 | method = loader_from_dispatch(id, algodef, prov); | |
249 | ||
d6d42cda RL |
250 | /* |
251 | * Flag to indicate that there was actual construction errors. This | |
252 | * helps inner_evp_generic_fetch() determine what error it should | |
253 | * record on inaccessible algorithms. | |
254 | */ | |
255 | if (method == NULL) | |
256 | methdata->flag_construct_error_occured = 1; | |
257 | ||
c4fc564d RL |
258 | return method; |
259 | } | |
260 | ||
261 | /* Intermediary function to avoid ugly casts, used below */ | |
262 | static void destruct_loader(void *method, void *data) | |
263 | { | |
264 | OSSL_STORE_LOADER_free(method); | |
265 | } | |
266 | ||
267 | /* Fetching support. Can fetch by numeric identity or by scheme */ | |
b4250010 | 268 | static OSSL_STORE_LOADER *inner_loader_fetch(OSSL_LIB_CTX *libctx, |
c4fc564d RL |
269 | int id, const char *scheme, |
270 | const char *properties) | |
271 | { | |
272 | OSSL_METHOD_STORE *store = get_loader_store(libctx); | |
273 | OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); | |
274 | void *method = NULL; | |
d6d42cda | 275 | int unsupported = 0; |
c4fc564d | 276 | |
d6d42cda RL |
277 | if (store == NULL || namemap == NULL) { |
278 | ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_INVALID_ARGUMENT); | |
c4fc564d | 279 | return NULL; |
d6d42cda | 280 | } |
c4fc564d RL |
281 | |
282 | /* | |
283 | * If we have been passed neither a scheme_id or a scheme, we have an | |
284 | * internal programming error. | |
285 | */ | |
d6d42cda RL |
286 | if (!ossl_assert(id != 0 || scheme != NULL)) { |
287 | ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_INTERNAL_ERROR); | |
c4fc564d | 288 | return NULL; |
d6d42cda | 289 | } |
c4fc564d | 290 | |
d6d42cda | 291 | /* If we haven't received a name id yet, try to get one for the name */ |
c4fc564d RL |
292 | if (id == 0) |
293 | id = ossl_namemap_name2num(namemap, scheme); | |
294 | ||
d6d42cda RL |
295 | /* |
296 | * If we haven't found the name yet, chances are that the algorithm to | |
297 | * be fetched is unsupported. | |
298 | */ | |
299 | if (id == 0) | |
300 | unsupported = 1; | |
301 | ||
c4fc564d RL |
302 | if (id == 0 |
303 | || !ossl_method_store_cache_get(store, id, properties, &method)) { | |
304 | OSSL_METHOD_CONSTRUCT_METHOD mcm = { | |
305 | alloc_tmp_loader_store, | |
306 | dealloc_tmp_loader_store, | |
307 | get_loader_from_store, | |
308 | put_loader_in_store, | |
309 | construct_loader, | |
310 | destruct_loader | |
311 | }; | |
312 | struct loader_data_st mcmdata; | |
313 | ||
314 | mcmdata.libctx = libctx; | |
315 | mcmdata.mcm = &mcm; | |
316 | mcmdata.scheme_id = id; | |
317 | mcmdata.scheme = scheme; | |
318 | mcmdata.propquery = properties; | |
d6d42cda | 319 | mcmdata.flag_construct_error_occured = 0; |
c4fc564d RL |
320 | if ((method = ossl_method_construct(libctx, OSSL_OP_STORE, |
321 | 0 /* !force_cache */, | |
322 | &mcm, &mcmdata)) != NULL) { | |
323 | /* | |
324 | * If construction did create a method for us, we know that there | |
325 | * is a correct scheme_id, since those have already been calculated | |
326 | * in get_loader_from_store() and put_loader_in_store() above. | |
327 | */ | |
328 | if (id == 0) | |
329 | id = ossl_namemap_name2num(namemap, scheme); | |
330 | ossl_method_store_cache_set(store, id, properties, method, | |
331 | up_ref_loader, free_loader); | |
332 | } | |
d6d42cda RL |
333 | |
334 | /* | |
335 | * If we never were in the constructor, the algorithm to be fetched | |
336 | * is unsupported. | |
337 | */ | |
338 | unsupported = !mcmdata.flag_construct_error_occured; | |
339 | } | |
340 | ||
341 | if (method == NULL) { | |
342 | int code = unsupported ? ERR_R_UNSUPPORTED : ERR_R_FETCH_FAILED; | |
343 | ||
344 | if (scheme == NULL) | |
345 | scheme = ossl_namemap_num2name(namemap, id, 0); | |
346 | ERR_raise_data(ERR_LIB_OSSL_STORE, code, | |
347 | "%s, Scheme (%s : %d), Properties (%s)", | |
348 | ossl_lib_ctx_get_descriptor(libctx), | |
349 | scheme = NULL ? "<null>" : scheme, id, | |
350 | properties == NULL ? "<null>" : properties); | |
c4fc564d RL |
351 | } |
352 | ||
353 | return method; | |
354 | } | |
355 | ||
356 | OSSL_STORE_LOADER *OSSL_STORE_LOADER_fetch(const char *scheme, | |
b4250010 | 357 | OSSL_LIB_CTX *libctx, |
c4fc564d RL |
358 | const char *properties) |
359 | { | |
360 | return inner_loader_fetch(libctx, 0, scheme, properties); | |
361 | } | |
362 | ||
b4250010 | 363 | OSSL_STORE_LOADER *ossl_store_loader_fetch_by_number(OSSL_LIB_CTX *libctx, |
c4fc564d RL |
364 | int scheme_id, |
365 | const char *properties) | |
366 | { | |
367 | return inner_loader_fetch(libctx, scheme_id, NULL, properties); | |
368 | } | |
369 | ||
370 | /* | |
371 | * Library of basic method functions | |
372 | */ | |
373 | ||
374 | const OSSL_PROVIDER *OSSL_STORE_LOADER_provider(const OSSL_STORE_LOADER *loader) | |
375 | { | |
376 | if (!ossl_assert(loader != NULL)) { | |
377 | ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER); | |
378 | return 0; | |
379 | } | |
380 | ||
381 | return loader->prov; | |
382 | } | |
383 | ||
384 | const char *OSSL_STORE_LOADER_properties(const OSSL_STORE_LOADER *loader) | |
385 | { | |
386 | if (!ossl_assert(loader != NULL)) { | |
387 | ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER); | |
388 | return 0; | |
389 | } | |
390 | ||
391 | return loader->propdef; | |
392 | } | |
393 | ||
394 | int OSSL_STORE_LOADER_number(const OSSL_STORE_LOADER *loader) | |
395 | { | |
396 | if (!ossl_assert(loader != NULL)) { | |
397 | ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER); | |
398 | return 0; | |
399 | } | |
400 | ||
401 | return loader->scheme_id; | |
402 | } | |
403 | ||
404 | int OSSL_STORE_LOADER_is_a(const OSSL_STORE_LOADER *loader, const char *name) | |
405 | { | |
406 | if (loader->prov != NULL) { | |
a829b735 | 407 | OSSL_LIB_CTX *libctx = ossl_provider_libctx(loader->prov); |
c4fc564d RL |
408 | OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); |
409 | ||
410 | return ossl_namemap_name2num(namemap, name) == loader->scheme_id; | |
411 | } | |
412 | return 0; | |
413 | } | |
414 | ||
415 | struct loader_do_all_data_st { | |
416 | void (*user_fn)(void *method, void *arg); | |
417 | void *user_arg; | |
418 | }; | |
419 | ||
420 | static void loader_do_one(OSSL_PROVIDER *provider, | |
421 | const OSSL_ALGORITHM *algodef, | |
422 | int no_store, void *vdata) | |
423 | { | |
424 | struct loader_do_all_data_st *data = vdata; | |
a829b735 | 425 | OSSL_LIB_CTX *libctx = ossl_provider_libctx(provider); |
c4fc564d RL |
426 | OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); |
427 | const char *name = algodef->algorithm_names; | |
428 | int id = ossl_namemap_add_name(namemap, 0, name); | |
429 | void *method = NULL; | |
430 | ||
431 | if (id != 0) | |
432 | method = | |
433 | loader_from_dispatch(id, algodef, provider); | |
434 | ||
435 | if (method != NULL) { | |
436 | data->user_fn(method, data->user_arg); | |
437 | OSSL_STORE_LOADER_free(method); | |
438 | } | |
439 | } | |
440 | ||
b4250010 | 441 | void OSSL_STORE_LOADER_do_all_provided(OSSL_LIB_CTX *libctx, |
c4fc564d RL |
442 | void (*fn)(OSSL_STORE_LOADER *loader, |
443 | void *arg), | |
444 | void *arg) | |
445 | { | |
446 | struct loader_do_all_data_st data; | |
447 | ||
448 | data.user_fn = (void (*)(void *, void *))fn; | |
449 | data.user_arg = arg; | |
450 | ossl_algorithm_do_all(libctx, OSSL_OP_STORE, NULL, | |
451 | NULL, loader_do_one, NULL, | |
452 | &data); | |
453 | } | |
454 | ||
455 | void OSSL_STORE_LOADER_names_do_all(const OSSL_STORE_LOADER *loader, | |
456 | void (*fn)(const char *name, void *data), | |
457 | void *data) | |
458 | { | |
459 | if (loader == NULL) | |
460 | return; | |
461 | ||
462 | if (loader->prov != NULL) { | |
a829b735 | 463 | OSSL_LIB_CTX *libctx = ossl_provider_libctx(loader->prov); |
c4fc564d RL |
464 | OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); |
465 | ||
466 | ossl_namemap_doall_names(namemap, loader->scheme_id, fn, data); | |
467 | } | |
468 | } |