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