2 * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
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
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"
18 int OSSL_STORE_LOADER_up_ref(OSSL_STORE_LOADER
*loader
)
22 if (loader
->prov
!= NULL
)
23 CRYPTO_UP_REF(&loader
->refcnt
, &ref
, loader
->lock
);
27 void OSSL_STORE_LOADER_free(OSSL_STORE_LOADER
*loader
)
29 if (loader
!= NULL
&& loader
->prov
!= NULL
) {
32 CRYPTO_DOWN_REF(&loader
->refcnt
, &i
, loader
->lock
);
35 ossl_provider_free(loader
->prov
);
36 CRYPTO_THREAD_lock_free(loader
->lock
);
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.
45 static OSSL_STORE_LOADER
*new_loader(OSSL_PROVIDER
*prov
)
47 OSSL_STORE_LOADER
*loader
;
49 if ((loader
= OPENSSL_zalloc(sizeof(*loader
))) == NULL
50 || (loader
->lock
= CRYPTO_THREAD_lock_new()) == NULL
) {
55 ossl_provider_up_ref(prov
);
61 static int up_ref_loader(void *method
)
63 return OSSL_STORE_LOADER_up_ref(method
);
66 static void free_loader(void *method
)
68 OSSL_STORE_LOADER_free(method
);
71 /* Permanent loader method store, constructor and destructor */
72 static void loader_store_free(void *vstore
)
74 ossl_method_store_free(vstore
);
77 static void *loader_store_new(OSSL_LIB_CTX
*ctx
)
79 return ossl_method_store_new(ctx
);
83 static const OSSL_LIB_CTX_METHOD loader_store_method
= {
88 /* Data to be passed through ossl_method_construct() */
89 struct loader_data_st
{
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() */
98 * Generic routines to fetch / create OSSL_STORE methods with
99 * ossl_method_construct()
102 /* Temporary loader method store, constructor and destructor */
103 static void *alloc_tmp_loader_store(OSSL_LIB_CTX
*ctx
)
105 return ossl_method_store_new(ctx
);
108 static void dealloc_tmp_loader_store(void *store
)
111 ossl_method_store_free(store
);
114 /* Get the permanent loader store */
115 static OSSL_METHOD_STORE
*get_loader_store(OSSL_LIB_CTX
*libctx
)
117 return ossl_lib_ctx_get_data(libctx
, OSSL_LIB_CTX_STORE_LOADER_STORE_INDEX
,
118 &loader_store_method
);
121 /* Get loader methods from a store, or put one in */
122 static void *get_loader_from_store(OSSL_LIB_CTX
*libctx
, void *store
,
125 struct loader_data_st
*methdata
= data
;
129 if ((id
= methdata
->scheme_id
) == 0) {
130 OSSL_NAMEMAP
*namemap
= ossl_namemap_stored(libctx
);
132 id
= ossl_namemap_name2num(namemap
, methdata
->scheme
);
136 && (store
= get_loader_store(libctx
)) == NULL
)
139 if (!ossl_method_store_fetch(store
, id
, methdata
->propquery
, &method
))
144 static int put_loader_in_store(OSSL_LIB_CTX
*libctx
, void *store
,
145 void *method
, const OSSL_PROVIDER
*prov
,
146 int operation_id
, const char *scheme
,
147 const char *propdef
, void *unused
)
149 OSSL_NAMEMAP
*namemap
;
152 if ((namemap
= ossl_namemap_stored(libctx
)) == NULL
153 || (id
= ossl_namemap_name2num(namemap
, scheme
)) == 0)
156 if (store
== NULL
&& (store
= get_loader_store(libctx
)) == NULL
)
159 return ossl_method_store_add(store
, prov
, id
, propdef
, method
,
160 up_ref_loader
, free_loader
);
163 static void *loader_from_dispatch(int scheme_id
, const OSSL_ALGORITHM
*algodef
,
166 OSSL_STORE_LOADER
*loader
= NULL
;
167 const OSSL_DISPATCH
*fns
= algodef
->implementation
;
169 if ((loader
= new_loader(prov
)) == NULL
)
171 loader
->scheme_id
= scheme_id
;
172 loader
->propdef
= algodef
->property_definition
;
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
);
180 case OSSL_FUNC_STORE_ATTACH
:
181 if (loader
->p_attach
== NULL
)
182 loader
->p_attach
= OSSL_FUNC_store_attach(fns
);
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
);
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
);
193 case OSSL_FUNC_STORE_LOAD
:
194 if (loader
->p_load
== NULL
)
195 loader
->p_load
= OSSL_FUNC_store_load(fns
);
197 case OSSL_FUNC_STORE_EOF
:
198 if (loader
->p_eof
== NULL
)
199 loader
->p_eof
= OSSL_FUNC_store_eof(fns
);
201 case OSSL_FUNC_STORE_CLOSE
:
202 if (loader
->p_close
== NULL
)
203 loader
->p_close
= OSSL_FUNC_store_close(fns
);
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
);
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
);
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.
229 static void *construct_loader(const OSSL_ALGORITHM
*algodef
,
230 OSSL_PROVIDER
*prov
, void *unused
)
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.
238 OSSL_LIB_CTX
*libctx
= ossl_provider_library_context(prov
);
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
);
245 method
= loader_from_dispatch(id
, algodef
, prov
);
250 /* Intermediary function to avoid ugly casts, used below */
251 static void destruct_loader(void *method
, void *data
)
253 OSSL_STORE_LOADER_free(method
);
256 /* Fetching support. Can fetch by numeric identity or by scheme */
257 static OSSL_STORE_LOADER
*inner_loader_fetch(OSSL_LIB_CTX
*libctx
,
258 int id
, const char *scheme
,
259 const char *properties
)
261 OSSL_METHOD_STORE
*store
= get_loader_store(libctx
);
262 OSSL_NAMEMAP
*namemap
= ossl_namemap_stored(libctx
);
265 if (store
== NULL
|| namemap
== NULL
)
269 * If we have been passed neither a scheme_id or a scheme, we have an
270 * internal programming error.
272 if (!ossl_assert(id
!= 0 || scheme
!= NULL
))
276 id
= ossl_namemap_name2num(namemap
, scheme
);
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
,
288 struct loader_data_st mcmdata
;
290 mcmdata
.libctx
= libctx
;
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
) {
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.
304 id
= ossl_namemap_name2num(namemap
, scheme
);
305 ossl_method_store_cache_set(store
, id
, properties
, method
,
306 up_ref_loader
, free_loader
);
313 OSSL_STORE_LOADER
*OSSL_STORE_LOADER_fetch(const char *scheme
,
314 OSSL_LIB_CTX
*libctx
,
315 const char *properties
)
317 return inner_loader_fetch(libctx
, 0, scheme
, properties
);
320 OSSL_STORE_LOADER
*ossl_store_loader_fetch_by_number(OSSL_LIB_CTX
*libctx
,
322 const char *properties
)
324 return inner_loader_fetch(libctx
, scheme_id
, NULL
, properties
);
328 * Library of basic method functions
331 const OSSL_PROVIDER
*OSSL_STORE_LOADER_provider(const OSSL_STORE_LOADER
*loader
)
333 if (!ossl_assert(loader
!= NULL
)) {
334 ERR_raise(ERR_LIB_OSSL_STORE
, ERR_R_PASSED_NULL_PARAMETER
);
341 const char *OSSL_STORE_LOADER_properties(const OSSL_STORE_LOADER
*loader
)
343 if (!ossl_assert(loader
!= NULL
)) {
344 ERR_raise(ERR_LIB_OSSL_STORE
, ERR_R_PASSED_NULL_PARAMETER
);
348 return loader
->propdef
;
351 int OSSL_STORE_LOADER_number(const OSSL_STORE_LOADER
*loader
)
353 if (!ossl_assert(loader
!= NULL
)) {
354 ERR_raise(ERR_LIB_OSSL_STORE
, ERR_R_PASSED_NULL_PARAMETER
);
358 return loader
->scheme_id
;
361 int OSSL_STORE_LOADER_is_a(const OSSL_STORE_LOADER
*loader
, const char *name
)
363 if (loader
->prov
!= NULL
) {
364 OSSL_LIB_CTX
*libctx
= ossl_provider_library_context(loader
->prov
);
365 OSSL_NAMEMAP
*namemap
= ossl_namemap_stored(libctx
);
367 return ossl_namemap_name2num(namemap
, name
) == loader
->scheme_id
;
372 struct loader_do_all_data_st
{
373 void (*user_fn
)(void *method
, void *arg
);
377 static void loader_do_one(OSSL_PROVIDER
*provider
,
378 const OSSL_ALGORITHM
*algodef
,
379 int no_store
, void *vdata
)
381 struct loader_do_all_data_st
*data
= vdata
;
382 OSSL_LIB_CTX
*libctx
= ossl_provider_library_context(provider
);
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
);
390 loader_from_dispatch(id
, algodef
, provider
);
392 if (method
!= NULL
) {
393 data
->user_fn(method
, data
->user_arg
);
394 OSSL_STORE_LOADER_free(method
);
398 void OSSL_STORE_LOADER_do_all_provided(OSSL_LIB_CTX
*libctx
,
399 void (*fn
)(OSSL_STORE_LOADER
*loader
,
403 struct loader_do_all_data_st data
;
405 data
.user_fn
= (void (*)(void *, void *))fn
;
407 ossl_algorithm_do_all(libctx
, OSSL_OP_STORE
, NULL
,
408 NULL
, loader_do_one
, NULL
,
412 void OSSL_STORE_LOADER_names_do_all(const OSSL_STORE_LOADER
*loader
,
413 void (*fn
)(const char *name
, void *data
),
419 if (loader
->prov
!= NULL
) {
420 OSSL_LIB_CTX
*libctx
= ossl_provider_library_context(loader
->prov
);
421 OSSL_NAMEMAP
*namemap
= ossl_namemap_stored(libctx
);
423 ossl_namemap_doall_names(namemap
, loader
->scheme_id
, fn
, data
);