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/core.h>
11 #include <openssl/core_dispatch.h>
12 #include <openssl/deserializer.h>
13 #include <openssl/ui.h>
14 #include "internal/core.h"
15 #include "internal/namemap.h"
16 #include "internal/property.h"
17 #include "internal/provider.h"
18 #include "crypto/serializer.h"
19 #include "serializer_local.h"
21 static void OSSL_DESERIALIZER_INSTANCE_free(OSSL_DESERIALIZER_INSTANCE
*instance
);
24 * Deserializer can have multiple names, separated with colons in a name string
26 #define NAME_SEPARATOR ':'
28 /* Simple method structure constructor and destructor */
29 static OSSL_DESERIALIZER
*ossl_deserializer_new(void)
31 OSSL_DESERIALIZER
*deser
= NULL
;
33 if ((deser
= OPENSSL_zalloc(sizeof(*deser
))) == NULL
34 || (deser
->base
.lock
= CRYPTO_THREAD_lock_new()) == NULL
) {
35 OSSL_DESERIALIZER_free(deser
);
36 ERR_raise(ERR_LIB_OSSL_DESERIALIZER
, ERR_R_MALLOC_FAILURE
);
40 deser
->base
.refcnt
= 1;
45 int OSSL_DESERIALIZER_up_ref(OSSL_DESERIALIZER
*deser
)
49 CRYPTO_UP_REF(&deser
->base
.refcnt
, &ref
, deser
->base
.lock
);
53 void OSSL_DESERIALIZER_free(OSSL_DESERIALIZER
*deser
)
60 CRYPTO_DOWN_REF(&deser
->base
.refcnt
, &ref
, deser
->base
.lock
);
63 ossl_provider_free(deser
->base
.prov
);
64 CRYPTO_THREAD_lock_free(deser
->base
.lock
);
68 /* Permanent deserializer method store, constructor and destructor */
69 static void deserializer_store_free(void *vstore
)
71 ossl_method_store_free(vstore
);
74 static void *deserializer_store_new(OPENSSL_CTX
*ctx
)
76 return ossl_method_store_new(ctx
);
80 static const OPENSSL_CTX_METHOD deserializer_store_method
= {
81 deserializer_store_new
,
82 deserializer_store_free
,
85 /* Data to be passed through ossl_method_construct() */
86 struct deserializer_data_st
{
88 OSSL_METHOD_CONSTRUCT_METHOD
*mcm
;
89 int id
; /* For get_deserializer_from_store() */
90 const char *names
; /* For get_deserializer_from_store() */
91 const char *propquery
; /* For get_deserializer_from_store() */
95 * Generic routines to fetch / create DESERIALIZER methods with
96 * ossl_method_construct()
99 /* Temporary deserializer method store, constructor and destructor */
100 static void *alloc_tmp_deserializer_store(OPENSSL_CTX
*ctx
)
102 return ossl_method_store_new(ctx
);
105 static void dealloc_tmp_deserializer_store(void *store
)
108 ossl_method_store_free(store
);
111 /* Get the permanent deserializer store */
112 static OSSL_METHOD_STORE
*get_deserializer_store(OPENSSL_CTX
*libctx
)
114 return openssl_ctx_get_data(libctx
, OPENSSL_CTX_DESERIALIZER_STORE_INDEX
,
115 &deserializer_store_method
);
118 /* Get deserializer methods from a store, or put one in */
119 static void *get_deserializer_from_store(OPENSSL_CTX
*libctx
, void *store
,
122 struct deserializer_data_st
*methdata
= data
;
126 if ((id
= methdata
->id
) == 0) {
127 OSSL_NAMEMAP
*namemap
= ossl_namemap_stored(libctx
);
129 id
= ossl_namemap_name2num(namemap
, methdata
->names
);
133 && (store
= get_deserializer_store(libctx
)) == NULL
)
136 if (!ossl_method_store_fetch(store
, id
, methdata
->propquery
, &method
))
141 static int put_deserializer_in_store(OPENSSL_CTX
*libctx
, void *store
,
142 void *method
, const OSSL_PROVIDER
*prov
,
143 int operation_id
, const char *names
,
144 const char *propdef
, void *unused
)
146 OSSL_NAMEMAP
*namemap
;
149 if ((namemap
= ossl_namemap_stored(libctx
)) == NULL
150 || (id
= ossl_namemap_name2num(namemap
, names
)) == 0)
153 if (store
== NULL
&& (store
= get_deserializer_store(libctx
)) == NULL
)
156 return ossl_method_store_add(store
, prov
, id
, propdef
, method
,
157 (int (*)(void *))OSSL_DESERIALIZER_up_ref
,
158 (void (*)(void *))OSSL_DESERIALIZER_free
);
161 /* Create and populate a deserializer method */
162 static void *deserializer_from_dispatch(int id
, const OSSL_ALGORITHM
*algodef
,
165 OSSL_DESERIALIZER
*deser
= NULL
;
166 const OSSL_DISPATCH
*fns
= algodef
->implementation
;
168 if ((deser
= ossl_deserializer_new()) == NULL
)
171 deser
->base
.propdef
= algodef
->property_definition
;
173 for (; fns
->function_id
!= 0; fns
++) {
174 switch (fns
->function_id
) {
175 case OSSL_FUNC_DESERIALIZER_NEWCTX
:
176 if (deser
->newctx
== NULL
)
177 deser
->newctx
= OSSL_FUNC_deserializer_newctx(fns
);
179 case OSSL_FUNC_DESERIALIZER_FREECTX
:
180 if (deser
->freectx
== NULL
)
181 deser
->freectx
= OSSL_FUNC_deserializer_freectx(fns
);
183 case OSSL_FUNC_DESERIALIZER_GET_PARAMS
:
184 if (deser
->get_params
== NULL
)
186 OSSL_FUNC_deserializer_get_params(fns
);
188 case OSSL_FUNC_DESERIALIZER_GETTABLE_PARAMS
:
189 if (deser
->gettable_params
== NULL
)
190 deser
->gettable_params
=
191 OSSL_FUNC_deserializer_gettable_params(fns
);
193 case OSSL_FUNC_DESERIALIZER_SET_CTX_PARAMS
:
194 if (deser
->set_ctx_params
== NULL
)
195 deser
->set_ctx_params
=
196 OSSL_FUNC_deserializer_set_ctx_params(fns
);
198 case OSSL_FUNC_DESERIALIZER_SETTABLE_CTX_PARAMS
:
199 if (deser
->settable_ctx_params
== NULL
)
200 deser
->settable_ctx_params
=
201 OSSL_FUNC_deserializer_settable_ctx_params(fns
);
203 case OSSL_FUNC_DESERIALIZER_DESERIALIZE
:
204 if (deser
->deserialize
== NULL
)
205 deser
->deserialize
= OSSL_FUNC_deserializer_deserialize(fns
);
207 case OSSL_FUNC_DESERIALIZER_EXPORT_OBJECT
:
208 if (deser
->export_object
== NULL
)
209 deser
->export_object
= OSSL_FUNC_deserializer_export_object(fns
);
214 * Try to check that the method is sensible.
215 * If you have a constructor, you must have a destructor and vice versa.
216 * You must have at least one of the serializing driver functions.
218 if (!((deser
->newctx
== NULL
&& deser
->freectx
== NULL
)
219 || (deser
->newctx
!= NULL
&& deser
->freectx
!= NULL
))
220 || (deser
->deserialize
== NULL
&& deser
->export_object
== NULL
)) {
221 OSSL_DESERIALIZER_free(deser
);
222 ERR_raise(ERR_LIB_OSSL_DESERIALIZER
, ERR_R_INVALID_PROVIDER_FUNCTIONS
);
226 if (prov
!= NULL
&& !ossl_provider_up_ref(prov
)) {
227 OSSL_DESERIALIZER_free(deser
);
231 deser
->base
.prov
= prov
;
237 * The core fetching functionality passes the names of the implementation.
238 * This function is responsible to getting an identity number for them,
239 * then call deserializer_from_dispatch() with that identity number.
241 static void *construct_deserializer(const OSSL_ALGORITHM
*algodef
,
242 OSSL_PROVIDER
*prov
, void *unused
)
245 * This function is only called if get_deserializer_from_store() returned
246 * NULL, so it's safe to say that of all the spots to create a new
247 * namemap entry, this is it. Should the name already exist there, we
248 * know that ossl_namemap_add() will return its corresponding number.
250 OPENSSL_CTX
*libctx
= ossl_provider_library_context(prov
);
251 OSSL_NAMEMAP
*namemap
= ossl_namemap_stored(libctx
);
252 const char *names
= algodef
->algorithm_names
;
253 int id
= ossl_namemap_add_names(namemap
, 0, names
, NAME_SEPARATOR
);
257 method
= deserializer_from_dispatch(id
, algodef
, prov
);
262 /* Intermediary function to avoid ugly casts, used below */
263 static void destruct_deserializer(void *method
, void *data
)
265 OSSL_DESERIALIZER_free(method
);
268 static int up_ref_deserializer(void *method
)
270 return OSSL_DESERIALIZER_up_ref(method
);
273 static void free_deserializer(void *method
)
275 OSSL_DESERIALIZER_free(method
);
278 /* Fetching support. Can fetch by numeric identity or by name */
279 static OSSL_DESERIALIZER
*inner_ossl_deserializer_fetch(OPENSSL_CTX
*libctx
,
282 const char *properties
)
284 OSSL_METHOD_STORE
*store
= get_deserializer_store(libctx
);
285 OSSL_NAMEMAP
*namemap
= ossl_namemap_stored(libctx
);
288 if (store
== NULL
|| namemap
== NULL
)
292 * If we have been passed neither a name_id or a name, we have an
293 * internal programming error.
295 if (!ossl_assert(id
!= 0 || name
!= NULL
))
299 id
= ossl_namemap_name2num(namemap
, name
);
302 || !ossl_method_store_cache_get(store
, id
, properties
, &method
)) {
303 OSSL_METHOD_CONSTRUCT_METHOD mcm
= {
304 alloc_tmp_deserializer_store
,
305 dealloc_tmp_deserializer_store
,
306 get_deserializer_from_store
,
307 put_deserializer_in_store
,
308 construct_deserializer
,
309 destruct_deserializer
311 struct deserializer_data_st mcmdata
;
313 mcmdata
.libctx
= libctx
;
316 mcmdata
.names
= name
;
317 mcmdata
.propquery
= properties
;
318 if ((method
= ossl_method_construct(libctx
, OSSL_OP_DESERIALIZER
,
319 0 /* !force_cache */,
320 &mcm
, &mcmdata
)) != NULL
) {
322 * If construction did create a method for us, we know that
323 * there is a correct name_id and meth_id, since those have
324 * already been calculated in get_deserializer_from_store() and
325 * put_deserializer_in_store() above.
328 id
= ossl_namemap_name2num(namemap
, name
);
329 ossl_method_store_cache_set(store
, id
, properties
, method
,
330 up_ref_deserializer
, free_deserializer
);
337 OSSL_DESERIALIZER
*OSSL_DESERIALIZER_fetch(OPENSSL_CTX
*libctx
,
339 const char *properties
)
341 return inner_ossl_deserializer_fetch(libctx
, 0, name
, properties
);
344 OSSL_DESERIALIZER
*ossl_deserializer_fetch_by_number(OPENSSL_CTX
*libctx
,
346 const char *properties
)
348 return inner_ossl_deserializer_fetch(libctx
, id
, NULL
, properties
);
352 * Library of basic method functions
355 const OSSL_PROVIDER
*OSSL_DESERIALIZER_provider(const OSSL_DESERIALIZER
*deser
)
357 if (!ossl_assert(deser
!= NULL
)) {
358 ERR_raise(ERR_LIB_OSSL_DESERIALIZER
, ERR_R_PASSED_NULL_PARAMETER
);
362 return deser
->base
.prov
;
365 const char *OSSL_DESERIALIZER_properties(const OSSL_DESERIALIZER
*deser
)
367 if (!ossl_assert(deser
!= NULL
)) {
368 ERR_raise(ERR_LIB_OSSL_DESERIALIZER
, ERR_R_PASSED_NULL_PARAMETER
);
372 return deser
->base
.propdef
;
375 int OSSL_DESERIALIZER_number(const OSSL_DESERIALIZER
*deser
)
377 if (!ossl_assert(deser
!= NULL
)) {
378 ERR_raise(ERR_LIB_OSSL_DESERIALIZER
, ERR_R_PASSED_NULL_PARAMETER
);
382 return deser
->base
.id
;
385 int OSSL_DESERIALIZER_is_a(const OSSL_DESERIALIZER
*deser
, const char *name
)
387 if (deser
->base
.prov
!= NULL
) {
388 OPENSSL_CTX
*libctx
= ossl_provider_library_context(deser
->base
.prov
);
389 OSSL_NAMEMAP
*namemap
= ossl_namemap_stored(libctx
);
391 return ossl_namemap_name2num(namemap
, name
) == deser
->base
.id
;
396 struct deserializer_do_all_data_st
{
397 void (*user_fn
)(void *method
, void *arg
);
401 static void deserializer_do_one(OSSL_PROVIDER
*provider
,
402 const OSSL_ALGORITHM
*algodef
,
403 int no_store
, void *vdata
)
405 struct deserializer_do_all_data_st
*data
= vdata
;
406 OPENSSL_CTX
*libctx
= ossl_provider_library_context(provider
);
407 OSSL_NAMEMAP
*namemap
= ossl_namemap_stored(libctx
);
408 const char *names
= algodef
->algorithm_names
;
409 int id
= ossl_namemap_add_names(namemap
, 0, names
, NAME_SEPARATOR
);
414 deserializer_from_dispatch(id
, algodef
, provider
);
416 if (method
!= NULL
) {
417 data
->user_fn(method
, data
->user_arg
);
418 OSSL_DESERIALIZER_free(method
);
422 void OSSL_DESERIALIZER_do_all_provided(OPENSSL_CTX
*libctx
,
423 void (*fn
)(OSSL_DESERIALIZER
*deser
,
427 struct deserializer_do_all_data_st data
;
429 data
.user_fn
= (void (*)(void *, void *))fn
;
431 ossl_algorithm_do_all(libctx
, OSSL_OP_DESERIALIZER
, NULL
,
432 NULL
, deserializer_do_one
, NULL
,
436 void OSSL_DESERIALIZER_names_do_all(const OSSL_DESERIALIZER
*deser
,
437 void (*fn
)(const char *name
, void *data
),
443 if (deser
->base
.prov
!= NULL
) {
444 OPENSSL_CTX
*libctx
= ossl_provider_library_context(deser
->base
.prov
);
445 OSSL_NAMEMAP
*namemap
= ossl_namemap_stored(libctx
);
447 ossl_namemap_doall_names(namemap
, deser
->base
.id
, fn
, data
);
452 OSSL_DESERIALIZER_gettable_params(OSSL_DESERIALIZER
*deser
)
454 if (deser
!= NULL
&& deser
->gettable_params
!= NULL
)
455 return deser
->gettable_params(
456 ossl_provider_ctx(OSSL_DESERIALIZER_provider(deser
)));
460 int OSSL_DESERIALIZER_get_params(OSSL_DESERIALIZER
*deser
, OSSL_PARAM params
[])
462 if (deser
!= NULL
&& deser
->get_params
!= NULL
)
463 return deser
->get_params(params
);
468 OSSL_DESERIALIZER_settable_ctx_params(OSSL_DESERIALIZER
*deser
)
470 if (deser
!= NULL
&& deser
->settable_ctx_params
!= NULL
)
471 return deser
->settable_ctx_params(
472 ossl_provider_ctx(OSSL_DESERIALIZER_provider(deser
)));
477 * Deserializer context support
481 * |ser| value NULL is valid, and signifies that there is no deserializer.
482 * This is useful to provide fallback mechanisms.
483 * Functions that want to verify if there is a deserializer can do so with
484 * OSSL_DESERIALIZER_CTX_get_deserializer()
486 OSSL_DESERIALIZER_CTX
*OSSL_DESERIALIZER_CTX_new(void)
488 OSSL_DESERIALIZER_CTX
*ctx
;
490 if ((ctx
= OPENSSL_zalloc(sizeof(*ctx
))) == NULL
) {
491 ERR_raise(ERR_LIB_OSSL_DESERIALIZER
, ERR_R_MALLOC_FAILURE
);
495 ctx
->passphrase_cb
= ossl_deserializer_passphrase_in_cb
;
499 int OSSL_DESERIALIZER_CTX_set_params(OSSL_DESERIALIZER_CTX
*ctx
,
500 const OSSL_PARAM params
[])
505 if (!ossl_assert(ctx
!= NULL
)) {
506 ERR_raise(ERR_LIB_OSSL_DESERIALIZER
, ERR_R_PASSED_NULL_PARAMETER
);
510 if (ctx
->deser_insts
== NULL
)
513 l
= (size_t)sk_OSSL_DESERIALIZER_INSTANCE_num(ctx
->deser_insts
);
514 for (i
= 0; i
< l
; i
++) {
515 OSSL_DESERIALIZER_INSTANCE
*deser_inst
=
516 sk_OSSL_DESERIALIZER_INSTANCE_value(ctx
->deser_insts
, i
);
518 if (deser_inst
->deserctx
== NULL
519 || deser_inst
->deser
->set_ctx_params
== NULL
)
521 if (!deser_inst
->deser
->set_ctx_params(deser_inst
->deserctx
, params
))
528 OSSL_DESERIALIZER_INSTANCE_free(OSSL_DESERIALIZER_INSTANCE
*deser_inst
)
530 if (deser_inst
!= NULL
) {
531 if (deser_inst
->deser
->freectx
!= NULL
)
532 deser_inst
->deser
->freectx(deser_inst
->deserctx
);
533 deser_inst
->deserctx
= NULL
;
534 OSSL_DESERIALIZER_free(deser_inst
->deser
);
535 deser_inst
->deser
= NULL
;
536 OPENSSL_free(deser_inst
);
541 void OSSL_DESERIALIZER_CTX_free(OSSL_DESERIALIZER_CTX
*ctx
)
544 if (ctx
->cleanup
!= NULL
)
545 ctx
->cleanup(ctx
->construct_data
);
546 sk_OSSL_DESERIALIZER_INSTANCE_pop_free(ctx
->deser_insts
,
547 OSSL_DESERIALIZER_INSTANCE_free
);
548 OSSL_DESERIALIZER_CTX_set_passphrase_ui(ctx
, NULL
, NULL
);
549 OSSL_DESERIALIZER_CTX_set_passphrase(ctx
, NULL
, 0);