]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/serializer/deserializer_meth.c
Rename OSSL_SERIALIZER / OSSL_DESERIALIZER to OSSL_ENCODE / OSSL_DECODE
[thirdparty/openssl.git] / crypto / serializer / deserializer_meth.c
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/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"
20
21 static void OSSL_DESERIALIZER_INSTANCE_free(OSSL_DESERIALIZER_INSTANCE *instance);
22
23 /*
24 * Deserializer can have multiple names, separated with colons in a name string
25 */
26 #define NAME_SEPARATOR ':'
27
28 /* Simple method structure constructor and destructor */
29 static OSSL_DESERIALIZER *ossl_deserializer_new(void)
30 {
31 OSSL_DESERIALIZER *deser = NULL;
32
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);
37 return NULL;
38 }
39
40 deser->base.refcnt = 1;
41
42 return deser;
43 }
44
45 int OSSL_DESERIALIZER_up_ref(OSSL_DESERIALIZER *deser)
46 {
47 int ref = 0;
48
49 CRYPTO_UP_REF(&deser->base.refcnt, &ref, deser->base.lock);
50 return 1;
51 }
52
53 void OSSL_DESERIALIZER_free(OSSL_DESERIALIZER *deser)
54 {
55 int ref = 0;
56
57 if (deser == NULL)
58 return;
59
60 CRYPTO_DOWN_REF(&deser->base.refcnt, &ref, deser->base.lock);
61 if (ref > 0)
62 return;
63 ossl_provider_free(deser->base.prov);
64 CRYPTO_THREAD_lock_free(deser->base.lock);
65 OPENSSL_free(deser);
66 }
67
68 /* Permanent deserializer method store, constructor and destructor */
69 static void deserializer_store_free(void *vstore)
70 {
71 ossl_method_store_free(vstore);
72 }
73
74 static void *deserializer_store_new(OPENSSL_CTX *ctx)
75 {
76 return ossl_method_store_new(ctx);
77 }
78
79
80 static const OPENSSL_CTX_METHOD deserializer_store_method = {
81 deserializer_store_new,
82 deserializer_store_free,
83 };
84
85 /* Data to be passed through ossl_method_construct() */
86 struct deserializer_data_st {
87 OPENSSL_CTX *libctx;
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() */
92 };
93
94 /*
95 * Generic routines to fetch / create DESERIALIZER methods with
96 * ossl_method_construct()
97 */
98
99 /* Temporary deserializer method store, constructor and destructor */
100 static void *alloc_tmp_deserializer_store(OPENSSL_CTX *ctx)
101 {
102 return ossl_method_store_new(ctx);
103 }
104
105 static void dealloc_tmp_deserializer_store(void *store)
106 {
107 if (store != NULL)
108 ossl_method_store_free(store);
109 }
110
111 /* Get the permanent deserializer store */
112 static OSSL_METHOD_STORE *get_deserializer_store(OPENSSL_CTX *libctx)
113 {
114 return openssl_ctx_get_data(libctx, OPENSSL_CTX_DESERIALIZER_STORE_INDEX,
115 &deserializer_store_method);
116 }
117
118 /* Get deserializer methods from a store, or put one in */
119 static void *get_deserializer_from_store(OPENSSL_CTX *libctx, void *store,
120 void *data)
121 {
122 struct deserializer_data_st *methdata = data;
123 void *method = NULL;
124 int id;
125
126 if ((id = methdata->id) == 0) {
127 OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
128
129 id = ossl_namemap_name2num(namemap, methdata->names);
130 }
131
132 if (store == NULL
133 && (store = get_deserializer_store(libctx)) == NULL)
134 return NULL;
135
136 if (!ossl_method_store_fetch(store, id, methdata->propquery, &method))
137 return NULL;
138 return method;
139 }
140
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)
145 {
146 OSSL_NAMEMAP *namemap;
147 int id;
148
149 if ((namemap = ossl_namemap_stored(libctx)) == NULL
150 || (id = ossl_namemap_name2num(namemap, names)) == 0)
151 return 0;
152
153 if (store == NULL && (store = get_deserializer_store(libctx)) == NULL)
154 return 0;
155
156 return ossl_method_store_add(store, prov, id, propdef, method,
157 (int (*)(void *))OSSL_DESERIALIZER_up_ref,
158 (void (*)(void *))OSSL_DESERIALIZER_free);
159 }
160
161 /* Create and populate a deserializer method */
162 static void *deserializer_from_dispatch(int id, const OSSL_ALGORITHM *algodef,
163 OSSL_PROVIDER *prov)
164 {
165 OSSL_DESERIALIZER *deser = NULL;
166 const OSSL_DISPATCH *fns = algodef->implementation;
167
168 if ((deser = ossl_deserializer_new()) == NULL)
169 return NULL;
170 deser->base.id = id;
171 deser->base.propdef = algodef->property_definition;
172
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);
178 break;
179 case OSSL_FUNC_DESERIALIZER_FREECTX:
180 if (deser->freectx == NULL)
181 deser->freectx = OSSL_FUNC_deserializer_freectx(fns);
182 break;
183 case OSSL_FUNC_DESERIALIZER_GET_PARAMS:
184 if (deser->get_params == NULL)
185 deser->get_params =
186 OSSL_FUNC_deserializer_get_params(fns);
187 break;
188 case OSSL_FUNC_DESERIALIZER_GETTABLE_PARAMS:
189 if (deser->gettable_params == NULL)
190 deser->gettable_params =
191 OSSL_FUNC_deserializer_gettable_params(fns);
192 break;
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);
197 break;
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);
202 break;
203 case OSSL_FUNC_DESERIALIZER_DESERIALIZE:
204 if (deser->deserialize == NULL)
205 deser->deserialize = OSSL_FUNC_deserializer_deserialize(fns);
206 break;
207 case OSSL_FUNC_DESERIALIZER_EXPORT_OBJECT:
208 if (deser->export_object == NULL)
209 deser->export_object = OSSL_FUNC_deserializer_export_object(fns);
210 break;
211 }
212 }
213 /*
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.
217 */
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);
223 return NULL;
224 }
225
226 if (prov != NULL && !ossl_provider_up_ref(prov)) {
227 OSSL_DESERIALIZER_free(deser);
228 return NULL;
229 }
230
231 deser->base.prov = prov;
232 return deser;
233 }
234
235
236 /*
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.
240 */
241 static void *construct_deserializer(const OSSL_ALGORITHM *algodef,
242 OSSL_PROVIDER *prov, void *unused)
243 {
244 /*
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.
249 */
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);
254 void *method = NULL;
255
256 if (id != 0)
257 method = deserializer_from_dispatch(id, algodef, prov);
258
259 return method;
260 }
261
262 /* Intermediary function to avoid ugly casts, used below */
263 static void destruct_deserializer(void *method, void *data)
264 {
265 OSSL_DESERIALIZER_free(method);
266 }
267
268 static int up_ref_deserializer(void *method)
269 {
270 return OSSL_DESERIALIZER_up_ref(method);
271 }
272
273 static void free_deserializer(void *method)
274 {
275 OSSL_DESERIALIZER_free(method);
276 }
277
278 /* Fetching support. Can fetch by numeric identity or by name */
279 static OSSL_DESERIALIZER *inner_ossl_deserializer_fetch(OPENSSL_CTX *libctx,
280 int id,
281 const char *name,
282 const char *properties)
283 {
284 OSSL_METHOD_STORE *store = get_deserializer_store(libctx);
285 OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
286 void *method = NULL;
287
288 if (store == NULL || namemap == NULL)
289 return NULL;
290
291 /*
292 * If we have been passed neither a name_id or a name, we have an
293 * internal programming error.
294 */
295 if (!ossl_assert(id != 0 || name != NULL))
296 return NULL;
297
298 if (id == 0)
299 id = ossl_namemap_name2num(namemap, name);
300
301 if (id == 0
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
310 };
311 struct deserializer_data_st mcmdata;
312
313 mcmdata.libctx = libctx;
314 mcmdata.mcm = &mcm;
315 mcmdata.id = id;
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) {
321 /*
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.
326 */
327 if (id == 0)
328 id = ossl_namemap_name2num(namemap, name);
329 ossl_method_store_cache_set(store, id, properties, method,
330 up_ref_deserializer, free_deserializer);
331 }
332 }
333
334 return method;
335 }
336
337 OSSL_DESERIALIZER *OSSL_DESERIALIZER_fetch(OPENSSL_CTX *libctx,
338 const char *name,
339 const char *properties)
340 {
341 return inner_ossl_deserializer_fetch(libctx, 0, name, properties);
342 }
343
344 OSSL_DESERIALIZER *ossl_deserializer_fetch_by_number(OPENSSL_CTX *libctx,
345 int id,
346 const char *properties)
347 {
348 return inner_ossl_deserializer_fetch(libctx, id, NULL, properties);
349 }
350
351 /*
352 * Library of basic method functions
353 */
354
355 const OSSL_PROVIDER *OSSL_DESERIALIZER_provider(const OSSL_DESERIALIZER *deser)
356 {
357 if (!ossl_assert(deser != NULL)) {
358 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
359 return 0;
360 }
361
362 return deser->base.prov;
363 }
364
365 const char *OSSL_DESERIALIZER_properties(const OSSL_DESERIALIZER *deser)
366 {
367 if (!ossl_assert(deser != NULL)) {
368 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
369 return 0;
370 }
371
372 return deser->base.propdef;
373 }
374
375 int OSSL_DESERIALIZER_number(const OSSL_DESERIALIZER *deser)
376 {
377 if (!ossl_assert(deser != NULL)) {
378 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
379 return 0;
380 }
381
382 return deser->base.id;
383 }
384
385 int OSSL_DESERIALIZER_is_a(const OSSL_DESERIALIZER *deser, const char *name)
386 {
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);
390
391 return ossl_namemap_name2num(namemap, name) == deser->base.id;
392 }
393 return 0;
394 }
395
396 struct deserializer_do_all_data_st {
397 void (*user_fn)(void *method, void *arg);
398 void *user_arg;
399 };
400
401 static void deserializer_do_one(OSSL_PROVIDER *provider,
402 const OSSL_ALGORITHM *algodef,
403 int no_store, void *vdata)
404 {
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);
410 void *method = NULL;
411
412 if (id != 0)
413 method =
414 deserializer_from_dispatch(id, algodef, provider);
415
416 if (method != NULL) {
417 data->user_fn(method, data->user_arg);
418 OSSL_DESERIALIZER_free(method);
419 }
420 }
421
422 void OSSL_DESERIALIZER_do_all_provided(OPENSSL_CTX *libctx,
423 void (*fn)(OSSL_DESERIALIZER *deser,
424 void *arg),
425 void *arg)
426 {
427 struct deserializer_do_all_data_st data;
428
429 data.user_fn = (void (*)(void *, void *))fn;
430 data.user_arg = arg;
431 ossl_algorithm_do_all(libctx, OSSL_OP_DESERIALIZER, NULL,
432 NULL, deserializer_do_one, NULL,
433 &data);
434 }
435
436 void OSSL_DESERIALIZER_names_do_all(const OSSL_DESERIALIZER *deser,
437 void (*fn)(const char *name, void *data),
438 void *data)
439 {
440 if (deser == NULL)
441 return;
442
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);
446
447 ossl_namemap_doall_names(namemap, deser->base.id, fn, data);
448 }
449 }
450
451 const OSSL_PARAM *
452 OSSL_DESERIALIZER_gettable_params(OSSL_DESERIALIZER *deser)
453 {
454 if (deser != NULL && deser->gettable_params != NULL)
455 return deser->gettable_params(
456 ossl_provider_ctx(OSSL_DESERIALIZER_provider(deser)));
457 return NULL;
458 }
459
460 int OSSL_DESERIALIZER_get_params(OSSL_DESERIALIZER *deser, OSSL_PARAM params[])
461 {
462 if (deser != NULL && deser->get_params != NULL)
463 return deser->get_params(params);
464 return 0;
465 }
466
467 const OSSL_PARAM *
468 OSSL_DESERIALIZER_settable_ctx_params(OSSL_DESERIALIZER *deser)
469 {
470 if (deser != NULL && deser->settable_ctx_params != NULL)
471 return deser->settable_ctx_params(
472 ossl_provider_ctx(OSSL_DESERIALIZER_provider(deser)));
473 return NULL;
474 }
475
476 /*
477 * Deserializer context support
478 */
479
480 /*
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()
485 */
486 OSSL_DESERIALIZER_CTX *OSSL_DESERIALIZER_CTX_new(void)
487 {
488 OSSL_DESERIALIZER_CTX *ctx;
489
490 if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
491 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_MALLOC_FAILURE);
492 return NULL;
493 }
494
495 ctx->passphrase_cb = ossl_deserializer_passphrase_in_cb;
496 return ctx;
497 }
498
499 int OSSL_DESERIALIZER_CTX_set_params(OSSL_DESERIALIZER_CTX *ctx,
500 const OSSL_PARAM params[])
501 {
502 size_t i;
503 size_t l;
504
505 if (!ossl_assert(ctx != NULL)) {
506 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
507 return 0;
508 }
509
510 if (ctx->deser_insts == NULL)
511 return 1;
512
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);
517
518 if (deser_inst->deserctx == NULL
519 || deser_inst->deser->set_ctx_params == NULL)
520 continue;
521 if (!deser_inst->deser->set_ctx_params(deser_inst->deserctx, params))
522 return 0;
523 }
524 return 1;
525 }
526
527 static void
528 OSSL_DESERIALIZER_INSTANCE_free(OSSL_DESERIALIZER_INSTANCE *deser_inst)
529 {
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);
537 deser_inst = NULL;
538 }
539 }
540
541 void OSSL_DESERIALIZER_CTX_free(OSSL_DESERIALIZER_CTX *ctx)
542 {
543 if (ctx != NULL) {
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);
550 OPENSSL_free(ctx);
551 }
552 }