]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/store/store_meth.c
Rename OPENSSL_CTX prefix to OSSL_LIB_CTX
[thirdparty/openssl.git] / crypto / store / store_meth.c
CommitLineData
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
18int 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
27void 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 */
45static 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
61static int up_ref_loader(void *method)
62{
63 return OSSL_STORE_LOADER_up_ref(method);
64}
65
66static void free_loader(void *method)
67{
68 OSSL_STORE_LOADER_free(method);
69}
70
71/* Permanent loader method store, constructor and destructor */
72static void loader_store_free(void *vstore)
73{
74 ossl_method_store_free(vstore);
75}
76
b4250010 77static void *loader_store_new(OSSL_LIB_CTX *ctx)
c4fc564d
RL
78{
79 return ossl_method_store_new(ctx);
80}
81
82
b4250010 83static 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() */
89struct 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 103static 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 115static 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 122static 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 144static 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
163static 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 */
229static 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 */
251static 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 257static 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
313OSSL_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 320OSSL_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
331const 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
341const 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
351int 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
361int 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
372struct loader_do_all_data_st {
373 void (*user_fn)(void *method, void *arg);
374 void *user_arg;
375};
376
377static 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 398void 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
412void 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}