103188f93a85f462dc2aa136745f63c573c2d4e0
[openssl.git] / crypto / serializer / serializer_meth.c
1 /*
2  * Copyright 2019 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_numbers.h>
12 #include <openssl/serializer.h>
13 #include "internal/core.h"
14 #include "internal/namemap.h"
15 #include "internal/property.h"
16 #include "internal/provider.h"
17 #include "crypto/serializer.h"
18 #include "serializer_local.h"
19
20 /*
21  * Serializer can have multiple names, separated with colons in a name string
22  */
23 #define NAME_SEPARATOR ':'
24
25 /* Simple method structure constructor and destructor */
26 static OSSL_SERIALIZER *ossl_serializer_new(void)
27 {
28     OSSL_SERIALIZER *ser = NULL;
29
30     if ((ser = OPENSSL_zalloc(sizeof(*ser))) == NULL
31         || (ser->lock = CRYPTO_THREAD_lock_new()) == NULL) {
32         OSSL_SERIALIZER_free(ser);
33         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE);
34         return NULL;
35     }
36
37     ser->refcnt = 1;
38
39     return ser;
40 }
41
42 int OSSL_SERIALIZER_up_ref(OSSL_SERIALIZER *ser)
43 {
44     int ref = 0;
45
46     CRYPTO_UP_REF(&ser->refcnt, &ref, ser->lock);
47     return 1;
48 }
49
50 void OSSL_SERIALIZER_free(OSSL_SERIALIZER *ser)
51 {
52     int ref = 0;
53
54     if (ser == NULL)
55         return;
56
57     CRYPTO_DOWN_REF(&ser->refcnt, &ref, ser->lock);
58     if (ref > 0)
59         return;
60     ossl_provider_free(ser->prov);
61     CRYPTO_THREAD_lock_free(ser->lock);
62     OPENSSL_free(ser);
63 }
64
65 /* Permanent serializer method store, constructor and destructor */
66 static void serializer_store_free(void *vstore)
67 {
68     ossl_method_store_free(vstore);
69 }
70
71 static void *serializer_store_new(OPENSSL_CTX *ctx)
72 {
73     return ossl_method_store_new(ctx);
74 }
75
76
77 static const OPENSSL_CTX_METHOD serializer_store_method = {
78     serializer_store_new,
79     serializer_store_free,
80 };
81
82 /* Data to be passed through ossl_method_construct() */
83 struct serializer_data_st {
84     OPENSSL_CTX *libctx;
85     OSSL_METHOD_CONSTRUCT_METHOD *mcm;
86     int id;                      /* For get_serializer_from_store() */
87     const char *names;           /* For get_serializer_from_store() */
88     const char *propquery;       /* For get_serializer_from_store() */
89 };
90
91 /*
92  * Generic routines to fetch / create SERIALIZER methods with
93  * ossl_method_construct()
94  */
95
96 /* Temporary serializer method store, constructor and destructor */
97 static void *alloc_tmp_serializer_store(OPENSSL_CTX *ctx)
98 {
99     return ossl_method_store_new(ctx);
100 }
101
102  static void dealloc_tmp_serializer_store(void *store)
103 {
104     if (store != NULL)
105         ossl_method_store_free(store);
106 }
107
108 /* Get the permanent serializer store */
109 static OSSL_METHOD_STORE *get_serializer_store(OPENSSL_CTX *libctx)
110 {
111     return openssl_ctx_get_data(libctx, OPENSSL_CTX_SERIALIZER_STORE_INDEX,
112                                 &serializer_store_method);
113 }
114
115 /* Get serializer methods from a store, or put one in */
116 static void *get_serializer_from_store(OPENSSL_CTX *libctx, void *store,
117                                        void *data)
118 {
119     struct serializer_data_st *methdata = data;
120     void *method = NULL;
121     int id;
122
123     if ((id = methdata->id) == 0) {
124         OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
125
126         id = ossl_namemap_name2num(namemap, methdata->names);
127     }
128
129     if (store == NULL
130         && (store = get_serializer_store(libctx)) == NULL)
131         return NULL;
132
133     if (!ossl_method_store_fetch(store, id, methdata->propquery, &method))
134         return NULL;
135     return method;
136 }
137
138 static int put_serializer_in_store(OPENSSL_CTX *libctx, void *store,
139                                    void *method, const OSSL_PROVIDER *prov,
140                                    int operation_id, const char *names,
141                                    const char *propdef, void *unused)
142 {
143     OSSL_NAMEMAP *namemap;
144     int id;
145
146     if ((namemap = ossl_namemap_stored(libctx)) == NULL
147         || (id = ossl_namemap_name2num(namemap, names)) == 0)
148         return 0;
149
150     if (store == NULL && (store = get_serializer_store(libctx)) == NULL)
151         return 0;
152
153     return ossl_method_store_add(store, prov, id, propdef, method,
154                                  (int (*)(void *))OSSL_SERIALIZER_up_ref,
155                                  (void (*)(void *))OSSL_SERIALIZER_free);
156 }
157
158 /* Create and populate a serializer method */
159 static void *serializer_from_dispatch(int id, const OSSL_ALGORITHM *algodef,
160                                       OSSL_PROVIDER *prov)
161 {
162     OSSL_SERIALIZER *ser = NULL;
163     const OSSL_DISPATCH *fns = algodef->implementation;
164
165     if ((ser = ossl_serializer_new()) == NULL)
166         return NULL;
167     ser->id = id;
168     ser->propdef = algodef->property_definition;
169
170     for (; fns->function_id != 0; fns++) {
171         switch (fns->function_id) {
172         case OSSL_FUNC_SERIALIZER_NEWCTX:
173             if (ser->newctx == NULL)
174                 ser->newctx =
175                     OSSL_get_OP_serializer_newctx(fns);
176             break;
177         case OSSL_FUNC_SERIALIZER_FREECTX:
178             if (ser->freectx == NULL)
179                 ser->freectx =
180                     OSSL_get_OP_serializer_freectx(fns);
181             break;
182         case OSSL_FUNC_SERIALIZER_SET_CTX_PARAMS:
183             if (ser->set_ctx_params == NULL)
184                 ser->set_ctx_params =
185                     OSSL_get_OP_serializer_set_ctx_params(fns);
186             break;
187         case OSSL_FUNC_SERIALIZER_SETTABLE_CTX_PARAMS:
188             if (ser->settable_ctx_params == NULL)
189                 ser->settable_ctx_params =
190                     OSSL_get_OP_serializer_settable_ctx_params(fns);
191             break;
192         case OSSL_FUNC_SERIALIZER_SERIALIZE_DATA:
193             if (ser->serialize_data == NULL)
194                 ser->serialize_data =
195                     OSSL_get_OP_serializer_serialize_data(fns);
196             break;
197         case OSSL_FUNC_SERIALIZER_SERIALIZE_OBJECT:
198             if (ser->serialize_object == NULL)
199                 ser->serialize_object =
200                     OSSL_get_OP_serializer_serialize_object(fns);
201             break;
202         }
203     }
204     /*
205      * Try to check that the method is sensible.
206      * If you have a constructor, you must have a destructor and vice versa.
207      * You must have at least one of the serializing driver functions.
208      */
209     if (!((ser->newctx == NULL && ser->freectx == NULL)
210           || (ser->newctx != NULL && ser->freectx != NULL))
211         || (ser->serialize_data == NULL && ser->serialize_object == NULL)) {
212         OSSL_SERIALIZER_free(ser);
213         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_INVALID_PROVIDER_FUNCTIONS);
214         return NULL;
215     }
216
217     if (prov != NULL && !ossl_provider_up_ref(prov)) {
218         OSSL_SERIALIZER_free(ser);
219         return NULL;
220     }
221
222     ser->prov = prov;
223     return ser;
224 }
225
226
227 /*
228  * The core fetching functionality passes the names of the implementation.
229  * This function is responsible to getting an identity number for them,
230  * then call serializer_from_dispatch() with that identity number.
231  */
232 static void *construct_serializer(const OSSL_ALGORITHM *algodef,
233                                   OSSL_PROVIDER *prov, void *unused)
234 {
235     /*
236      * This function is only called if get_serializer_from_store() returned
237      * NULL, so it's safe to say that of all the spots to create a new
238      * namemap entry, this is it.  Should the name already exist there, we
239      * know that ossl_namemap_add() will return its corresponding number.
240      */
241     OPENSSL_CTX *libctx = ossl_provider_library_context(prov);
242     OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
243     const char *names = algodef->algorithm_names;
244     int id = ossl_namemap_add_names(namemap, 0, names, NAME_SEPARATOR);
245     void *method = NULL;
246
247     if (id != 0)
248         method = serializer_from_dispatch(id, algodef, prov);
249
250     return method;
251 }
252
253 /* Intermediary function to avoid ugly casts, used below */
254 static void destruct_serializer(void *method, void *data)
255 {
256     OSSL_SERIALIZER_free(method);
257 }
258
259 static int up_ref_serializer(void *method)
260 {
261     return OSSL_SERIALIZER_up_ref(method);
262 }
263
264 static void free_serializer(void *method)
265 {
266     OSSL_SERIALIZER_free(method);
267 }
268
269 /* Fetching support.  Can fetch by numeric identity or by name */
270 static OSSL_SERIALIZER *inner_ossl_serializer_fetch(OPENSSL_CTX *libctx,
271                                                     int id, const char *name,
272                                                     const char *properties)
273 {
274     OSSL_METHOD_STORE *store = get_serializer_store(libctx);
275     OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
276     void *method = NULL;
277
278     if (store == NULL || namemap == NULL)
279         return NULL;
280
281     /*
282      * If we have been passed neither a name_id or a name, we have an
283      * internal programming error.
284      */
285     if (!ossl_assert(id != 0 || name != NULL))
286         return NULL;
287
288     if (id == 0)
289         id = ossl_namemap_name2num(namemap, name);
290
291     if (id == 0
292         || !ossl_method_store_cache_get(store, id, properties, &method)) {
293         OSSL_METHOD_CONSTRUCT_METHOD mcm = {
294             alloc_tmp_serializer_store,
295             dealloc_tmp_serializer_store,
296             get_serializer_from_store,
297             put_serializer_in_store,
298             construct_serializer,
299             destruct_serializer
300         };
301         struct serializer_data_st mcmdata;
302
303         mcmdata.libctx = libctx;
304         mcmdata.mcm = &mcm;
305         mcmdata.id = id;
306         mcmdata.names = name;
307         mcmdata.propquery = properties;
308         if ((method = ossl_method_construct(libctx, OSSL_OP_SERIALIZER,
309                                             0 /* !force_cache */,
310                                             &mcm, &mcmdata)) != NULL) {
311             /*
312              * If construction did create a method for us, we know that
313              * there is a correct name_id and meth_id, since those have
314              * already been calculated in get_serializer_from_store() and
315              * put_serializer_in_store() above.
316              */
317             if (id == 0)
318                 id = ossl_namemap_name2num(namemap, name);
319             ossl_method_store_cache_set(store, id, properties, method,
320                                         up_ref_serializer, free_serializer);
321         }
322     }
323
324     return method;
325 }
326
327 OSSL_SERIALIZER *OSSL_SERIALIZER_fetch(OPENSSL_CTX *libctx, const char *name,
328                                        const char *properties)
329 {
330     return inner_ossl_serializer_fetch(libctx, 0, name, properties);
331 }
332
333 OSSL_SERIALIZER *ossl_serializer_fetch_by_number(OPENSSL_CTX *libctx, int id,
334                                                  const char *properties)
335 {
336     return inner_ossl_serializer_fetch(libctx, id, NULL, properties);
337 }
338
339 /*
340  * Library of basic method functions
341  */
342
343 const OSSL_PROVIDER *OSSL_SERIALIZER_provider(const OSSL_SERIALIZER *ser)
344 {
345     if (!ossl_assert(ser != NULL)) {
346         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
347         return 0;
348     }
349
350     return ser->prov;
351 }
352
353 const char *OSSL_SERIALIZER_properties(const OSSL_SERIALIZER *ser)
354 {
355     if (!ossl_assert(ser != NULL)) {
356         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
357         return 0;
358     }
359
360     return ser->propdef;
361 }
362
363 int OSSL_SERIALIZER_number(const OSSL_SERIALIZER *ser)
364 {
365     if (!ossl_assert(ser != NULL)) {
366         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
367         return 0;
368     }
369
370     return ser->id;
371 }
372
373 int OSSL_SERIALIZER_is_a(const OSSL_SERIALIZER *ser, const char *name)
374 {
375     if (ser->prov != NULL) {
376         OPENSSL_CTX *libctx = ossl_provider_library_context(ser->prov);
377         OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
378
379         return ossl_namemap_name2num(namemap, name) == ser->id;
380     }
381     return 0;
382 }
383
384 struct serializer_do_all_data_st {
385     void (*user_fn)(void *method, void *arg);
386     void *user_arg;
387 };
388
389 static void serializer_do_one(OSSL_PROVIDER *provider,
390                               const OSSL_ALGORITHM *algodef,
391                               int no_store, void *vdata)
392 {
393     struct serializer_do_all_data_st *data = vdata;
394     OPENSSL_CTX *libctx = ossl_provider_library_context(provider);
395     OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
396     const char *names = algodef->algorithm_names;
397     int id = ossl_namemap_add_names(namemap, 0, names, NAME_SEPARATOR);
398     void *method = NULL;
399
400     if (id != 0)
401         method =
402             serializer_from_dispatch(id, algodef, provider);
403
404     if (method != NULL) {
405         data->user_fn(method, data->user_arg);
406         OSSL_SERIALIZER_free(method);
407     }
408 }
409
410 void OSSL_SERIALIZER_do_all_provided(OPENSSL_CTX *libctx,
411                                      void (*fn)(OSSL_SERIALIZER *ser,
412                                                 void *arg),
413                                      void *arg)
414 {
415     struct serializer_do_all_data_st data;
416
417     data.user_fn = (void (*)(void *, void *))fn;
418     data.user_arg = arg;
419     ossl_algorithm_do_all(libctx, OSSL_OP_SERIALIZER, NULL,
420                           serializer_do_one, &data);
421 }
422
423 void OSSL_SERIALIZER_names_do_all(const OSSL_SERIALIZER *ser,
424                                   void (*fn)(const char *name, void *data),
425                                   void *data)
426 {
427     if (ser == NULL)
428         return;
429
430     if (ser->prov != NULL) {
431         OPENSSL_CTX *libctx = ossl_provider_library_context(ser->prov);
432         OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
433
434         ossl_namemap_doall_names(namemap, ser->id, fn, data);
435     }
436 }
437
438 const OSSL_PARAM *OSSL_SERIALIZER_settable_ctx_params(OSSL_SERIALIZER *ser)
439 {
440     if (ser != NULL && ser->settable_ctx_params != NULL)
441         return ser->settable_ctx_params();
442     return NULL;
443 }
444
445 /*
446  * Serializer context support
447  */
448
449 /*
450  * |ser| value NULL is valid, and signifies that there is no serializer.
451  * This is useful to provide fallback mechanisms.
452  *  Funtions that want to verify if there is a serializer can do so with
453  * OSSL_SERIALIZER_CTX_get_serializer()
454  */
455 OSSL_SERIALIZER_CTX *OSSL_SERIALIZER_CTX_new(OSSL_SERIALIZER *ser)
456 {
457     OSSL_SERIALIZER_CTX *ctx;
458
459     if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
460         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE);
461         return NULL;
462     }
463
464     ctx->ser = ser;
465     if (ser != NULL && ser->newctx != NULL) {
466         const OSSL_PROVIDER *prov = OSSL_SERIALIZER_provider(ser);
467         void *provctx = ossl_provider_ctx(prov);
468
469         if (OSSL_SERIALIZER_up_ref(ser)) {
470             ctx->serctx = ser->newctx(provctx);
471         } else {
472             OSSL_SERIALIZER_free(ser);
473             OPENSSL_free(ctx);
474             ctx = NULL;
475         }
476     }
477
478     return ctx;
479 }
480
481 const OSSL_SERIALIZER *
482 OSSL_SERIALIZER_CTX_get_serializer(OSSL_SERIALIZER_CTX *ctx)
483 {
484     if (!ossl_assert(ctx != NULL)) {
485         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
486         return 0;
487     }
488
489     return ctx->ser;
490 }
491
492
493 int OSSL_SERIALIZER_CTX_set_params(OSSL_SERIALIZER_CTX *ctx,
494                                    const OSSL_PARAM params[])
495 {
496     if (!ossl_assert(ctx != NULL)) {
497         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
498         return 0;
499     }
500
501     if (ctx->ser != NULL && ctx->ser->set_ctx_params != NULL)
502         return ctx->ser->set_ctx_params(ctx->serctx, params);
503     return 0;
504 }
505
506 void OSSL_SERIALIZER_CTX_free(OSSL_SERIALIZER_CTX *ctx)
507 {
508     if (ctx != NULL) {
509         if (ctx->ser != NULL && ctx->ser->freectx != NULL)
510             ctx->ser->freectx(ctx->serctx);
511         OSSL_SERIALIZER_free(ctx->ser);
512         OPENSSL_free(ctx);
513     }
514 }