]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/store/store_meth.c
fc9f1e60e44e7720d131c97289f7c6b71407a901
[thirdparty/openssl.git] / crypto / store / store_meth.c
1 /*
2 * Copyright 2020-2022 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/crypto.h>
11 #include "crypto/store.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 #include "crypto/context.h"
18
19 int OSSL_STORE_LOADER_up_ref(OSSL_STORE_LOADER *loader)
20 {
21 int ref = 0;
22
23 if (loader->prov != NULL)
24 CRYPTO_UP_REF(&loader->refcnt, &ref, loader->lock);
25 return 1;
26 }
27
28 void OSSL_STORE_LOADER_free(OSSL_STORE_LOADER *loader)
29 {
30 if (loader != NULL && loader->prov != NULL) {
31 int i;
32
33 CRYPTO_DOWN_REF(&loader->refcnt, &i, loader->lock);
34 if (i > 0)
35 return;
36 ossl_provider_free(loader->prov);
37 CRYPTO_THREAD_lock_free(loader->lock);
38 }
39 OPENSSL_free(loader);
40 }
41
42 /*
43 * OSSL_STORE_LOADER_new() expects the scheme as a constant string,
44 * which we currently don't have, so we need an alternative allocator.
45 */
46 static OSSL_STORE_LOADER *new_loader(OSSL_PROVIDER *prov)
47 {
48 OSSL_STORE_LOADER *loader;
49
50 if ((loader = OPENSSL_zalloc(sizeof(*loader))) == NULL
51 || (loader->lock = CRYPTO_THREAD_lock_new()) == NULL) {
52 OPENSSL_free(loader);
53 return NULL;
54 }
55 loader->prov = prov;
56 ossl_provider_up_ref(prov);
57 loader->refcnt = 1;
58
59 return loader;
60 }
61
62 static int up_ref_loader(void *method)
63 {
64 return OSSL_STORE_LOADER_up_ref(method);
65 }
66
67 static void free_loader(void *method)
68 {
69 OSSL_STORE_LOADER_free(method);
70 }
71
72 /* Data to be passed through ossl_method_construct() */
73 struct loader_data_st {
74 OSSL_LIB_CTX *libctx;
75 int scheme_id; /* For get_loader_from_store() */
76 const char *scheme; /* For get_loader_from_store() */
77 const char *propquery; /* For get_loader_from_store() */
78
79 OSSL_METHOD_STORE *tmp_store; /* For get_tmp_loader_store() */
80
81 unsigned int flag_construct_error_occurred : 1;
82 };
83
84 /*
85 * Generic routines to fetch / create OSSL_STORE methods with
86 * ossl_method_construct()
87 */
88
89 /* Temporary loader method store, constructor and destructor */
90 static void *get_tmp_loader_store(void *data)
91 {
92 struct loader_data_st *methdata = data;
93
94 if (methdata->tmp_store == NULL)
95 methdata->tmp_store = ossl_method_store_new(methdata->libctx);
96 return methdata->tmp_store;
97 }
98
99 static void dealloc_tmp_loader_store(void *store)
100 {
101 if (store != NULL)
102 ossl_method_store_free(store);
103 }
104
105 /* Get the permanent loader store */
106 static OSSL_METHOD_STORE *get_loader_store(OSSL_LIB_CTX *libctx)
107 {
108 return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_STORE_LOADER_STORE_INDEX);
109 }
110
111 /* Get loader methods from a store, or put one in */
112 static void *get_loader_from_store(void *store, const OSSL_PROVIDER **prov,
113 void *data)
114 {
115 struct loader_data_st *methdata = data;
116 void *method = NULL;
117 int id;
118
119 if ((id = methdata->scheme_id) == 0) {
120 OSSL_NAMEMAP *namemap = ossl_namemap_stored(methdata->libctx);
121
122 id = ossl_namemap_name2num(namemap, methdata->scheme);
123 }
124
125 if (store == NULL
126 && (store = get_loader_store(methdata->libctx)) == NULL)
127 return NULL;
128
129 if (!ossl_method_store_fetch(store, id, methdata->propquery, prov, &method))
130 return NULL;
131 return method;
132 }
133
134 static int put_loader_in_store(void *store, void *method,
135 const OSSL_PROVIDER *prov,
136 const char *scheme, const char *propdef,
137 void *data)
138 {
139 struct loader_data_st *methdata = data;
140 OSSL_NAMEMAP *namemap;
141 int id;
142
143 if ((namemap = ossl_namemap_stored(methdata->libctx)) == NULL
144 || (id = ossl_namemap_name2num(namemap, scheme)) == 0)
145 return 0;
146
147 if (store == NULL && (store = get_loader_store(methdata->libctx)) == NULL)
148 return 0;
149
150 return ossl_method_store_add(store, prov, id, propdef, method,
151 up_ref_loader, free_loader);
152 }
153
154 static void *loader_from_algorithm(int scheme_id, const OSSL_ALGORITHM *algodef,
155 OSSL_PROVIDER *prov)
156 {
157 OSSL_STORE_LOADER *loader = NULL;
158 const OSSL_DISPATCH *fns = algodef->implementation;
159
160 if ((loader = new_loader(prov)) == NULL)
161 return NULL;
162 loader->scheme_id = scheme_id;
163 loader->propdef = algodef->property_definition;
164 loader->description = algodef->algorithm_description;
165
166 for (; fns->function_id != 0; fns++) {
167 switch (fns->function_id) {
168 case OSSL_FUNC_STORE_OPEN:
169 if (loader->p_open == NULL)
170 loader->p_open = OSSL_FUNC_store_open(fns);
171 break;
172 case OSSL_FUNC_STORE_ATTACH:
173 if (loader->p_attach == NULL)
174 loader->p_attach = OSSL_FUNC_store_attach(fns);
175 break;
176 case OSSL_FUNC_STORE_SETTABLE_CTX_PARAMS:
177 if (loader->p_settable_ctx_params == NULL)
178 loader->p_settable_ctx_params =
179 OSSL_FUNC_store_settable_ctx_params(fns);
180 break;
181 case OSSL_FUNC_STORE_SET_CTX_PARAMS:
182 if (loader->p_set_ctx_params == NULL)
183 loader->p_set_ctx_params = OSSL_FUNC_store_set_ctx_params(fns);
184 break;
185 case OSSL_FUNC_STORE_LOAD:
186 if (loader->p_load == NULL)
187 loader->p_load = OSSL_FUNC_store_load(fns);
188 break;
189 case OSSL_FUNC_STORE_EOF:
190 if (loader->p_eof == NULL)
191 loader->p_eof = OSSL_FUNC_store_eof(fns);
192 break;
193 case OSSL_FUNC_STORE_CLOSE:
194 if (loader->p_close == NULL)
195 loader->p_close = OSSL_FUNC_store_close(fns);
196 break;
197 case OSSL_FUNC_STORE_EXPORT_OBJECT:
198 if (loader->p_export_object == NULL)
199 loader->p_export_object = OSSL_FUNC_store_export_object(fns);
200 break;
201 }
202 }
203
204 if ((loader->p_open == NULL && loader->p_attach == NULL)
205 || loader->p_load == NULL
206 || loader->p_eof == NULL
207 || loader->p_close == NULL) {
208 /* Only set_ctx_params is optionaal */
209 OSSL_STORE_LOADER_free(loader);
210 ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADER_INCOMPLETE);
211 return NULL;
212 }
213 return loader;
214 }
215
216 /*
217 * The core fetching functionality passes the scheme of the implementation.
218 * This function is responsible to getting an identity number for them,
219 * then call loader_from_algorithm() with that identity number.
220 */
221 static void *construct_loader(const OSSL_ALGORITHM *algodef,
222 OSSL_PROVIDER *prov, void *data)
223 {
224 /*
225 * This function is only called if get_loader_from_store() returned
226 * NULL, so it's safe to say that of all the spots to create a new
227 * namemap entry, this is it. Should the scheme already exist there, we
228 * know that ossl_namemap_add() will return its corresponding number.
229 */
230 struct loader_data_st *methdata = data;
231 OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
232 OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
233 const char *scheme = algodef->algorithm_names;
234 int id = ossl_namemap_add_name(namemap, 0, scheme);
235 void *method = NULL;
236
237 if (id != 0)
238 method = loader_from_algorithm(id, algodef, prov);
239
240 /*
241 * Flag to indicate that there was actual construction errors. This
242 * helps inner_loader_fetch() determine what error it should
243 * record on inaccessible algorithms.
244 */
245 if (method == NULL)
246 methdata->flag_construct_error_occurred = 1;
247
248 return method;
249 }
250
251 /* Intermediary function to avoid ugly casts, used below */
252 static void destruct_loader(void *method, void *data)
253 {
254 OSSL_STORE_LOADER_free(method);
255 }
256
257 /* Fetching support. Can fetch by numeric identity or by scheme */
258 static OSSL_STORE_LOADER *
259 inner_loader_fetch(struct loader_data_st *methdata, int id,
260 const char *scheme, const char *properties)
261 {
262 OSSL_METHOD_STORE *store = get_loader_store(methdata->libctx);
263 OSSL_NAMEMAP *namemap = ossl_namemap_stored(methdata->libctx);
264 const char *const propq = properties != NULL ? properties : "";
265 void *method = NULL;
266 int unsupported = 0;
267
268 if (store == NULL || namemap == NULL) {
269 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_INVALID_ARGUMENT);
270 return NULL;
271 }
272
273 /*
274 * If we have been passed both an id and a scheme, we have an
275 * internal programming error.
276 */
277 if (!ossl_assert(id == 0 || scheme == NULL)) {
278 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_INTERNAL_ERROR);
279 return NULL;
280 }
281
282 /* If we haven't received a name id yet, try to get one for the name */
283 if (id == 0 && scheme != NULL)
284 id = ossl_namemap_name2num(namemap, scheme);
285
286 /*
287 * If we haven't found the name yet, chances are that the algorithm to
288 * be fetched is unsupported.
289 */
290 if (id == 0)
291 unsupported = 1;
292
293 if (id == 0
294 || !ossl_method_store_cache_get(store, NULL, id, propq, &method)) {
295 OSSL_METHOD_CONSTRUCT_METHOD mcm = {
296 get_tmp_loader_store,
297 get_loader_from_store,
298 put_loader_in_store,
299 construct_loader,
300 destruct_loader
301 };
302 OSSL_PROVIDER *prov = NULL;
303
304 methdata->scheme_id = id;
305 methdata->scheme = scheme;
306 methdata->propquery = propq;
307 methdata->flag_construct_error_occurred = 0;
308 if ((method = ossl_method_construct(methdata->libctx, OSSL_OP_STORE,
309 &prov, 0 /* !force_cache */,
310 &mcm, methdata)) != NULL) {
311 /*
312 * If construction did create a method for us, we know that there
313 * is a correct scheme_id, since those have already been calculated
314 * in get_loader_from_store() and put_loader_in_store() above.
315 */
316 if (id == 0)
317 id = ossl_namemap_name2num(namemap, scheme);
318 ossl_method_store_cache_set(store, prov, id, propq, method,
319 up_ref_loader, free_loader);
320 }
321
322 /*
323 * If we never were in the constructor, the algorithm to be fetched
324 * is unsupported.
325 */
326 unsupported = !methdata->flag_construct_error_occurred;
327 }
328
329 if ((id != 0 || scheme != NULL) && method == NULL) {
330 int code = unsupported ? ERR_R_UNSUPPORTED : ERR_R_FETCH_FAILED;
331 const char *helpful_msg =
332 unsupported
333 ? ( "No store loader found. For standard store loaders you need "
334 "at least one of the default or base providers available. "
335 "Did you forget to load them? Info: " )
336 : "";
337
338 if (scheme == NULL)
339 scheme = ossl_namemap_num2name(namemap, id, 0);
340 ERR_raise_data(ERR_LIB_OSSL_STORE, code,
341 "%s%s, Scheme (%s : %d), Properties (%s)",
342 helpful_msg,
343 ossl_lib_ctx_get_descriptor(methdata->libctx),
344 scheme = NULL ? "<null>" : scheme, id,
345 properties == NULL ? "<null>" : properties);
346 }
347
348 return method;
349 }
350
351 OSSL_STORE_LOADER *OSSL_STORE_LOADER_fetch(OSSL_LIB_CTX *libctx,
352 const char *scheme,
353 const char *properties)
354 {
355 struct loader_data_st methdata;
356 void *method;
357
358 methdata.libctx = libctx;
359 methdata.tmp_store = NULL;
360 method = inner_loader_fetch(&methdata, 0, scheme, properties);
361 dealloc_tmp_loader_store(methdata.tmp_store);
362 return method;
363 }
364
365 OSSL_STORE_LOADER *ossl_store_loader_fetch_by_number(OSSL_LIB_CTX *libctx,
366 int scheme_id,
367 const char *properties)
368 {
369 struct loader_data_st methdata;
370 void *method;
371
372 methdata.libctx = libctx;
373 methdata.tmp_store = NULL;
374 method = inner_loader_fetch(&methdata, scheme_id, NULL, properties);
375 dealloc_tmp_loader_store(methdata.tmp_store);
376 return method;
377 }
378
379 int ossl_store_loader_store_cache_flush(OSSL_LIB_CTX *libctx)
380 {
381 OSSL_METHOD_STORE *store = get_loader_store(libctx);
382
383 if (store != NULL)
384 return ossl_method_store_cache_flush_all(store);
385 return 1;
386 }
387
388 int ossl_store_loader_store_remove_all_provided(const OSSL_PROVIDER *prov)
389 {
390 OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
391 OSSL_METHOD_STORE *store = get_loader_store(libctx);
392
393 if (store != NULL)
394 return ossl_method_store_remove_all_provided(store, prov);
395 return 1;
396 }
397
398 /*
399 * Library of basic method functions
400 */
401
402 const OSSL_PROVIDER *OSSL_STORE_LOADER_get0_provider(const OSSL_STORE_LOADER *loader)
403 {
404 if (!ossl_assert(loader != NULL)) {
405 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER);
406 return 0;
407 }
408
409 return loader->prov;
410 }
411
412 const char *OSSL_STORE_LOADER_get0_properties(const OSSL_STORE_LOADER *loader)
413 {
414 if (!ossl_assert(loader != NULL)) {
415 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER);
416 return 0;
417 }
418
419 return loader->propdef;
420 }
421
422 int ossl_store_loader_get_number(const OSSL_STORE_LOADER *loader)
423 {
424 if (!ossl_assert(loader != NULL)) {
425 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER);
426 return 0;
427 }
428
429 return loader->scheme_id;
430 }
431
432 const char *OSSL_STORE_LOADER_get0_description(const OSSL_STORE_LOADER *loader)
433 {
434 return loader->description;
435 }
436
437 int OSSL_STORE_LOADER_is_a(const OSSL_STORE_LOADER *loader, const char *name)
438 {
439 if (loader->prov != NULL) {
440 OSSL_LIB_CTX *libctx = ossl_provider_libctx(loader->prov);
441 OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
442
443 return ossl_namemap_name2num(namemap, name) == loader->scheme_id;
444 }
445 return 0;
446 }
447
448 struct do_one_data_st {
449 void (*user_fn)(OSSL_STORE_LOADER *loader, void *arg);
450 void *user_arg;
451 };
452
453 static void do_one(ossl_unused int id, void *method, void *arg)
454 {
455 struct do_one_data_st *data = arg;
456
457 data->user_fn(method, data->user_arg);
458 }
459
460 void OSSL_STORE_LOADER_do_all_provided(OSSL_LIB_CTX *libctx,
461 void (*user_fn)(OSSL_STORE_LOADER *loader,
462 void *arg),
463 void *user_arg)
464 {
465 struct loader_data_st methdata;
466 struct do_one_data_st data;
467
468 methdata.libctx = libctx;
469 methdata.tmp_store = NULL;
470 (void)inner_loader_fetch(&methdata, 0, NULL, NULL /* properties */);
471
472 data.user_fn = user_fn;
473 data.user_arg = user_arg;
474 if (methdata.tmp_store != NULL)
475 ossl_method_store_do_all(methdata.tmp_store, &do_one, &data);
476 ossl_method_store_do_all(get_loader_store(libctx), &do_one, &data);
477 dealloc_tmp_loader_store(methdata.tmp_store);
478 }
479
480 int OSSL_STORE_LOADER_names_do_all(const OSSL_STORE_LOADER *loader,
481 void (*fn)(const char *name, void *data),
482 void *data)
483 {
484 if (loader == NULL)
485 return 0;
486
487 if (loader->prov != NULL) {
488 OSSL_LIB_CTX *libctx = ossl_provider_libctx(loader->prov);
489 OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
490
491 return ossl_namemap_doall_names(namemap, loader->scheme_id, fn, data);
492 }
493
494 return 1;
495 }