ENCODER & DECODER: Allow en/decoders to have multiple names
[openssl.git] / crypto / encode_decode / encoder_meth.c
1 /*
2  * Copyright 2019-2021 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/encoder.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/encoder.h"
19 #include "encoder_local.h"
20
21 /*
22  * Encoder can have multiple names, separated with colons in a name string
23  */
24 #define NAME_SEPARATOR ':'
25
26 /* Simple method structure constructor and destructor */
27 static OSSL_ENCODER *ossl_encoder_new(void)
28 {
29     OSSL_ENCODER *encoder = NULL;
30
31     if ((encoder = OPENSSL_zalloc(sizeof(*encoder))) == NULL
32         || (encoder->base.lock = CRYPTO_THREAD_lock_new()) == NULL) {
33         OSSL_ENCODER_free(encoder);
34         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
35         return NULL;
36     }
37
38     encoder->base.refcnt = 1;
39
40     return encoder;
41 }
42
43 int OSSL_ENCODER_up_ref(OSSL_ENCODER *encoder)
44 {
45     int ref = 0;
46
47     CRYPTO_UP_REF(&encoder->base.refcnt, &ref, encoder->base.lock);
48     return 1;
49 }
50
51 void OSSL_ENCODER_free(OSSL_ENCODER *encoder)
52 {
53     int ref = 0;
54
55     if (encoder == NULL)
56         return;
57
58     CRYPTO_DOWN_REF(&encoder->base.refcnt, &ref, encoder->base.lock);
59     if (ref > 0)
60         return;
61     OPENSSL_free(encoder->base.name);
62     ossl_property_free(encoder->base.parsed_propdef);
63     ossl_provider_free(encoder->base.prov);
64     CRYPTO_THREAD_lock_free(encoder->base.lock);
65     OPENSSL_free(encoder);
66 }
67
68 /* Permanent encoder method store, constructor and destructor */
69 static void encoder_store_free(void *vstore)
70 {
71     ossl_method_store_free(vstore);
72 }
73
74 static void *encoder_store_new(OSSL_LIB_CTX *ctx)
75 {
76     return ossl_method_store_new(ctx);
77 }
78
79
80 static const OSSL_LIB_CTX_METHOD encoder_store_method = {
81     /* We want encoder_store to be cleaned up before the provider store */
82     OSSL_LIB_CTX_METHOD_PRIORITY_2,
83     encoder_store_new,
84     encoder_store_free,
85 };
86
87 /* Data to be passed through ossl_method_construct() */
88 struct encoder_data_st {
89     OSSL_LIB_CTX *libctx;
90     int id;                      /* For get_encoder_from_store() */
91     const char *names;           /* For get_encoder_from_store() */
92     const char *propquery;       /* For get_encoder_from_store() */
93
94     OSSL_METHOD_STORE *tmp_store; /* For get_tmp_encoder_store() */
95
96     unsigned int flag_construct_error_occurred : 1;
97 };
98
99 /*
100  * Generic routines to fetch / create ENCODER methods with
101  * ossl_method_construct()
102  */
103
104 /* Temporary encoder method store, constructor and destructor */
105 static void *get_tmp_encoder_store(void *data)
106 {
107     struct encoder_data_st *methdata = data;
108
109     if (methdata->tmp_store == NULL)
110         methdata->tmp_store = ossl_method_store_new(methdata->libctx);
111     return methdata->tmp_store;
112 }
113
114 static void dealloc_tmp_encoder_store(void *store)
115 {
116     if (store != NULL)
117         ossl_method_store_free(store);
118 }
119
120 /* Get the permanent encoder store */
121 static OSSL_METHOD_STORE *get_encoder_store(OSSL_LIB_CTX *libctx)
122 {
123     return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_ENCODER_STORE_INDEX,
124                                  &encoder_store_method);
125 }
126
127 /* Get encoder methods from a store, or put one in */
128 static void *get_encoder_from_store(void *store, void *data)
129 {
130     struct encoder_data_st *methdata = data;
131     void *method = NULL;
132     int id;
133
134     /*
135      * get_encoder_from_store() is only called to try and get the method
136      * that OSSL_ENCODER_fetch() is asking for, and the name or name id are
137      * passed via methdata.
138      */
139     if ((id = methdata->id) == 0 && methdata->names != NULL) {
140         OSSL_NAMEMAP *namemap = ossl_namemap_stored(methdata->libctx);
141         const char *names = methdata->names;
142         const char *q = strchr(names, NAME_SEPARATOR);
143         size_t l = (q == NULL ? strlen(names) : (size_t)(q - names));
144
145         if (namemap == 0)
146             return NULL;
147         id = ossl_namemap_name2num_n(namemap, methdata->names, l);
148     }
149
150     if (id == 0)
151         return NULL;
152
153     if (store == NULL
154         && (store = get_encoder_store(methdata->libctx)) == NULL)
155         return NULL;
156
157     if (!ossl_method_store_fetch(store, id, methdata->propquery, &method))
158         return NULL;
159     return method;
160 }
161
162 static int put_encoder_in_store(void *store, void *method,
163                                 const OSSL_PROVIDER *prov,
164                                 const char *names, const char *propdef,
165                                 void *data)
166 {
167     struct encoder_data_st *methdata = data;
168     OSSL_NAMEMAP *namemap;
169     int id;
170     size_t l = 0;
171
172     /*
173      * put_encoder_in_store() is only called with an OSSL_ENCODER method that
174      * was successfully created by construct_encoder() below, which means that
175      * all the names should already be stored in the namemap with the same
176      * numeric identity, so just use the first to get that identity.
177      */
178     if (names != NULL) {
179         const char *q = strchr(names, NAME_SEPARATOR);
180
181         l = (q == NULL ? strlen(names) : (size_t)(q - names));
182     }
183
184     if ((namemap = ossl_namemap_stored(methdata->libctx)) == NULL
185         || (id = ossl_namemap_name2num_n(namemap, names, l)) == 0)
186         return 0;
187
188     if (store == NULL && (store = get_encoder_store(methdata->libctx)) == NULL)
189         return 0;
190
191     return ossl_method_store_add(store, prov, id, propdef, method,
192                                  (int (*)(void *))OSSL_ENCODER_up_ref,
193                                  (void (*)(void *))OSSL_ENCODER_free);
194 }
195
196 /* Create and populate a encoder method */
197 static void *encoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
198                                     OSSL_PROVIDER *prov)
199 {
200     OSSL_ENCODER *encoder = NULL;
201     const OSSL_DISPATCH *fns = algodef->implementation;
202     OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
203
204     if ((encoder = ossl_encoder_new()) == NULL)
205         return NULL;
206     encoder->base.id = id;
207     if ((encoder->base.name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
208         OSSL_ENCODER_free(encoder);
209         return NULL;
210     }
211     encoder->base.algodef = algodef;
212     encoder->base.parsed_propdef
213         = ossl_parse_property(libctx, algodef->property_definition);
214
215     for (; fns->function_id != 0; fns++) {
216         switch (fns->function_id) {
217         case OSSL_FUNC_ENCODER_NEWCTX:
218             if (encoder->newctx == NULL)
219                 encoder->newctx =
220                     OSSL_FUNC_encoder_newctx(fns);
221             break;
222         case OSSL_FUNC_ENCODER_FREECTX:
223             if (encoder->freectx == NULL)
224                 encoder->freectx =
225                     OSSL_FUNC_encoder_freectx(fns);
226             break;
227         case OSSL_FUNC_ENCODER_GET_PARAMS:
228             if (encoder->get_params == NULL)
229                 encoder->get_params =
230                     OSSL_FUNC_encoder_get_params(fns);
231             break;
232         case OSSL_FUNC_ENCODER_GETTABLE_PARAMS:
233             if (encoder->gettable_params == NULL)
234                 encoder->gettable_params =
235                     OSSL_FUNC_encoder_gettable_params(fns);
236             break;
237         case OSSL_FUNC_ENCODER_SET_CTX_PARAMS:
238             if (encoder->set_ctx_params == NULL)
239                 encoder->set_ctx_params =
240                     OSSL_FUNC_encoder_set_ctx_params(fns);
241             break;
242         case OSSL_FUNC_ENCODER_SETTABLE_CTX_PARAMS:
243             if (encoder->settable_ctx_params == NULL)
244                 encoder->settable_ctx_params =
245                     OSSL_FUNC_encoder_settable_ctx_params(fns);
246             break;
247         case OSSL_FUNC_ENCODER_DOES_SELECTION:
248             if (encoder->does_selection == NULL)
249                 encoder->does_selection =
250                     OSSL_FUNC_encoder_does_selection(fns);
251             break;
252         case OSSL_FUNC_ENCODER_ENCODE:
253             if (encoder->encode == NULL)
254                 encoder->encode = OSSL_FUNC_encoder_encode(fns);
255             break;
256         case OSSL_FUNC_ENCODER_IMPORT_OBJECT:
257             if (encoder->import_object == NULL)
258                 encoder->import_object =
259                     OSSL_FUNC_encoder_import_object(fns);
260             break;
261         case OSSL_FUNC_ENCODER_FREE_OBJECT:
262             if (encoder->free_object == NULL)
263                 encoder->free_object =
264                     OSSL_FUNC_encoder_free_object(fns);
265             break;
266         }
267     }
268     /*
269      * Try to check that the method is sensible.
270      * If you have a constructor, you must have a destructor and vice versa.
271      * You must have the encoding driver functions.
272      */
273     if (!((encoder->newctx == NULL && encoder->freectx == NULL)
274           || (encoder->newctx != NULL && encoder->freectx != NULL)
275           || (encoder->import_object != NULL && encoder->free_object != NULL)
276           || (encoder->import_object == NULL && encoder->free_object == NULL))
277         || encoder->encode == NULL) {
278         OSSL_ENCODER_free(encoder);
279         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INVALID_PROVIDER_FUNCTIONS);
280         return NULL;
281     }
282
283     if (prov != NULL && !ossl_provider_up_ref(prov)) {
284         OSSL_ENCODER_free(encoder);
285         return NULL;
286     }
287
288     encoder->base.prov = prov;
289     return encoder;
290 }
291
292
293 /*
294  * The core fetching functionality passes the names of the implementation.
295  * This function is responsible to getting an identity number for them,
296  * then call encoder_from_algorithm() with that identity number.
297  */
298 static void *construct_encoder(const OSSL_ALGORITHM *algodef,
299                                OSSL_PROVIDER *prov, void *data)
300 {
301     /*
302      * This function is only called if get_encoder_from_store() returned
303      * NULL, so it's safe to say that of all the spots to create a new
304      * namemap entry, this is it.  Should the name already exist there, we
305      * know that ossl_namemap_add() will return its corresponding number.
306      */
307     struct encoder_data_st *methdata = data;
308     OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
309     OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
310     const char *names = algodef->algorithm_names;
311     int id = ossl_namemap_add_names(namemap, 0, names, NAME_SEPARATOR);
312     void *method = NULL;
313
314     if (id != 0)
315         method = encoder_from_algorithm(id, algodef, prov);
316
317     /*
318      * Flag to indicate that there was actual construction errors.  This
319      * helps inner_evp_generic_fetch() determine what error it should
320      * record on inaccessible algorithms.
321      */
322     if (method == NULL)
323         methdata->flag_construct_error_occurred = 1;
324
325     return method;
326 }
327
328 /* Intermediary function to avoid ugly casts, used below */
329 static void destruct_encoder(void *method, void *data)
330 {
331     OSSL_ENCODER_free(method);
332 }
333
334 static int up_ref_encoder(void *method)
335 {
336     return OSSL_ENCODER_up_ref(method);
337 }
338
339 static void free_encoder(void *method)
340 {
341     OSSL_ENCODER_free(method);
342 }
343
344 /* Fetching support.  Can fetch by numeric identity or by name */
345 static OSSL_ENCODER *
346 inner_ossl_encoder_fetch(struct encoder_data_st *methdata, int id,
347                          const char *name, const char *properties)
348 {
349     OSSL_METHOD_STORE *store = get_encoder_store(methdata->libctx);
350     OSSL_NAMEMAP *namemap = ossl_namemap_stored(methdata->libctx);
351     void *method = NULL;
352     int unsupported = 0;
353
354     if (store == NULL || namemap == NULL) {
355         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT);
356         return NULL;
357     }
358
359     /*
360      * If we have been passed both an id and a name, we have an
361      * internal programming error.
362      */
363     if (!ossl_assert(id == 0 || name == NULL)) {
364         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
365         return NULL;
366     }
367
368     if (id == 0)
369         id = ossl_namemap_name2num(namemap, name);
370
371     /*
372      * If we haven't found the name yet, chances are that the algorithm to
373      * be fetched is unsupported.
374      */
375     if (id == 0)
376         unsupported = 1;
377
378     if (id == 0
379         || !ossl_method_store_cache_get(store, id, properties, &method)) {
380         OSSL_METHOD_CONSTRUCT_METHOD mcm = {
381             get_tmp_encoder_store,
382             get_encoder_from_store,
383             put_encoder_in_store,
384             construct_encoder,
385             destruct_encoder
386         };
387
388         methdata->id = id;
389         methdata->names = name;
390         methdata->propquery = properties;
391         methdata->flag_construct_error_occurred = 0;
392         if ((method = ossl_method_construct(methdata->libctx, OSSL_OP_ENCODER,
393                                             0 /* !force_cache */,
394                                             &mcm, methdata)) != NULL) {
395             /*
396              * If construction did create a method for us, we know that
397              * there is a correct name_id and meth_id, since those have
398              * already been calculated in get_encoder_from_store() and
399              * put_encoder_in_store() above.
400              */
401             if (id == 0)
402                 id = ossl_namemap_name2num(namemap, name);
403             ossl_method_store_cache_set(store, id, properties, method,
404                                         up_ref_encoder, free_encoder);
405         }
406
407         /*
408          * If we never were in the constructor, the algorithm to be fetched
409          * is unsupported.
410          */
411         unsupported = !methdata->flag_construct_error_occurred;
412     }
413
414     if ((id != 0 || name != NULL) && method == NULL) {
415         int code = unsupported ? ERR_R_UNSUPPORTED : ERR_R_FETCH_FAILED;
416
417         if (name == NULL)
418             name = ossl_namemap_num2name(namemap, id, 0);
419         ERR_raise_data(ERR_LIB_OSSL_ENCODER, code,
420                        "%s, Name (%s : %d), Properties (%s)",
421                        ossl_lib_ctx_get_descriptor(methdata->libctx),
422                        name = NULL ? "<null>" : name, id,
423                        properties == NULL ? "<null>" : properties);
424     }
425
426     return method;
427 }
428
429 OSSL_ENCODER *OSSL_ENCODER_fetch(OSSL_LIB_CTX *libctx, const char *name,
430                                  const char *properties)
431 {
432     struct encoder_data_st methdata;
433     void *method;
434
435     methdata.libctx = libctx;
436     methdata.tmp_store = NULL;
437     method = inner_ossl_encoder_fetch(&methdata, 0, name, properties);
438     dealloc_tmp_encoder_store(methdata.tmp_store);
439     return method;
440 }
441
442 OSSL_ENCODER *ossl_encoder_fetch_by_number(OSSL_LIB_CTX *libctx, int id,
443                                            const char *properties)
444 {
445     struct encoder_data_st methdata;
446     void *method;
447
448     methdata.libctx = libctx;
449     methdata.tmp_store = NULL;
450     method = inner_ossl_encoder_fetch(&methdata, id, NULL, properties);
451     dealloc_tmp_encoder_store(methdata.tmp_store);
452     return method;
453 }
454
455 /*
456  * Library of basic method functions
457  */
458
459 const OSSL_PROVIDER *OSSL_ENCODER_get0_provider(const OSSL_ENCODER *encoder)
460 {
461     if (!ossl_assert(encoder != NULL)) {
462         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
463         return 0;
464     }
465
466     return encoder->base.prov;
467 }
468
469 const char *OSSL_ENCODER_get0_properties(const OSSL_ENCODER *encoder)
470 {
471     if (!ossl_assert(encoder != NULL)) {
472         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
473         return 0;
474     }
475
476     return encoder->base.algodef->property_definition;
477 }
478
479 const OSSL_PROPERTY_LIST *
480 ossl_encoder_parsed_properties(const OSSL_ENCODER *encoder)
481 {
482     if (!ossl_assert(encoder != NULL)) {
483         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
484         return 0;
485     }
486
487     return encoder->base.parsed_propdef;
488 }
489
490 int ossl_encoder_get_number(const OSSL_ENCODER *encoder)
491 {
492     if (!ossl_assert(encoder != NULL)) {
493         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
494         return 0;
495     }
496
497     return encoder->base.id;
498 }
499
500 const char *OSSL_ENCODER_get0_name(const OSSL_ENCODER *encoder)
501 {
502     return encoder->base.name;
503 }
504
505 const char *OSSL_ENCODER_get0_description(const OSSL_ENCODER *encoder)
506 {
507     return encoder->base.algodef->algorithm_description;
508 }
509
510 int OSSL_ENCODER_is_a(const OSSL_ENCODER *encoder, const char *name)
511 {
512     if (encoder->base.prov != NULL) {
513         OSSL_LIB_CTX *libctx = ossl_provider_libctx(encoder->base.prov);
514         OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
515
516         return ossl_namemap_name2num(namemap, name) == encoder->base.id;
517     }
518     return 0;
519 }
520
521 struct do_one_data_st {
522     void (*user_fn)(OSSL_ENCODER *encoder, void *arg);
523     void *user_arg;
524 };
525
526 static void do_one(ossl_unused int id, void *method, void *arg)
527 {
528     struct do_one_data_st *data = arg;
529
530     data->user_fn(method, data->user_arg);
531 }
532
533 void OSSL_ENCODER_do_all_provided(OSSL_LIB_CTX *libctx,
534                                   void (*user_fn)(OSSL_ENCODER *encoder,
535                                                   void *arg),
536                                   void *user_arg)
537 {
538     struct encoder_data_st methdata;
539     struct do_one_data_st data;
540
541     methdata.libctx = libctx;
542     methdata.tmp_store = NULL;
543     (void)inner_ossl_encoder_fetch(&methdata, 0, NULL, NULL /* properties */);
544
545     data.user_fn = user_fn;
546     data.user_arg = user_arg;
547     if (methdata.tmp_store != NULL)
548         ossl_method_store_do_all(methdata.tmp_store, &do_one, &data);
549     ossl_method_store_do_all(get_encoder_store(libctx), &do_one, &data);
550     dealloc_tmp_encoder_store(methdata.tmp_store);
551 }
552
553 int OSSL_ENCODER_names_do_all(const OSSL_ENCODER *encoder,
554                               void (*fn)(const char *name, void *data),
555                               void *data)
556 {
557     if (encoder == NULL)
558         return 0;
559
560     if (encoder->base.prov != NULL) {
561         OSSL_LIB_CTX *libctx = ossl_provider_libctx(encoder->base.prov);
562         OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
563
564         return ossl_namemap_doall_names(namemap, encoder->base.id, fn, data);
565     }
566
567     return 1;
568 }
569
570 const OSSL_PARAM *
571 OSSL_ENCODER_gettable_params(OSSL_ENCODER *encoder)
572 {
573     if (encoder != NULL && encoder->gettable_params != NULL) {
574         void *provctx = ossl_provider_ctx(OSSL_ENCODER_get0_provider(encoder));
575
576         return encoder->gettable_params(provctx);
577     }
578     return NULL;
579 }
580
581 int OSSL_ENCODER_get_params(OSSL_ENCODER *encoder, OSSL_PARAM params[])
582 {
583     if (encoder != NULL && encoder->get_params != NULL)
584         return encoder->get_params(params);
585     return 0;
586 }
587
588 const OSSL_PARAM *OSSL_ENCODER_settable_ctx_params(OSSL_ENCODER *encoder)
589 {
590     if (encoder != NULL && encoder->settable_ctx_params != NULL) {
591         void *provctx = ossl_provider_ctx(OSSL_ENCODER_get0_provider(encoder));
592
593         return encoder->settable_ctx_params(provctx);
594     }
595     return NULL;
596 }
597
598 /*
599  * Encoder context support
600  */
601
602 OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new(void)
603 {
604     OSSL_ENCODER_CTX *ctx;
605
606     if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
607         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
608
609     return ctx;
610 }
611
612 int OSSL_ENCODER_CTX_set_params(OSSL_ENCODER_CTX *ctx,
613                                 const OSSL_PARAM params[])
614 {
615     int ok = 1;
616     size_t i;
617     size_t l;
618
619     if (!ossl_assert(ctx != NULL)) {
620         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
621         return 0;
622     }
623
624     if (ctx->encoder_insts == NULL)
625         return 1;
626
627     l = OSSL_ENCODER_CTX_get_num_encoders(ctx);
628     for (i = 0; i < l; i++) {
629         OSSL_ENCODER_INSTANCE *encoder_inst =
630             sk_OSSL_ENCODER_INSTANCE_value(ctx->encoder_insts, i);
631         OSSL_ENCODER *encoder = OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst);
632         void *encoderctx = OSSL_ENCODER_INSTANCE_get_encoder_ctx(encoder_inst);
633
634         if (encoderctx == NULL || encoder->set_ctx_params == NULL)
635             continue;
636         if (!encoder->set_ctx_params(encoderctx, params))
637             ok = 0;
638     }
639     return ok;
640 }
641
642 void OSSL_ENCODER_CTX_free(OSSL_ENCODER_CTX *ctx)
643 {
644     if (ctx != NULL) {
645         sk_OSSL_ENCODER_INSTANCE_pop_free(ctx->encoder_insts,
646                                           ossl_encoder_instance_free);
647         OPENSSL_free(ctx->construct_data);
648         ossl_pw_clear_passphrase_data(&ctx->pwdata);
649         OPENSSL_free(ctx);
650     }
651 }