Add OSSL_DECODER_description() and OSSL_ENCODER_description()
[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     ossl_provider_free(encoder->base.prov);
62     CRYPTO_THREAD_lock_free(encoder->base.lock);
63     OPENSSL_free(encoder);
64 }
65
66 /* Permanent encoder method store, constructor and destructor */
67 static void encoder_store_free(void *vstore)
68 {
69     ossl_method_store_free(vstore);
70 }
71
72 static void *encoder_store_new(OSSL_LIB_CTX *ctx)
73 {
74     return ossl_method_store_new(ctx);
75 }
76
77
78 static const OSSL_LIB_CTX_METHOD encoder_store_method = {
79     encoder_store_new,
80     encoder_store_free,
81 };
82
83 /* Data to be passed through ossl_method_construct() */
84 struct encoder_data_st {
85     OSSL_LIB_CTX *libctx;
86     OSSL_METHOD_CONSTRUCT_METHOD *mcm;
87     int id;                      /* For get_encoder_from_store() */
88     const char *names;           /* For get_encoder_from_store() */
89     const char *propquery;       /* For get_encoder_from_store() */
90
91     unsigned int flag_construct_error_occurred : 1;
92 };
93
94 /*
95  * Generic routines to fetch / create ENCODER methods with
96  * ossl_method_construct()
97  */
98
99 /* Temporary encoder method store, constructor and destructor */
100 static void *alloc_tmp_encoder_store(OSSL_LIB_CTX *ctx)
101 {
102     return ossl_method_store_new(ctx);
103 }
104
105 static void dealloc_tmp_encoder_store(void *store)
106 {
107     if (store != NULL)
108         ossl_method_store_free(store);
109 }
110
111 /* Get the permanent encoder store */
112 static OSSL_METHOD_STORE *get_encoder_store(OSSL_LIB_CTX *libctx)
113 {
114     return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_ENCODER_STORE_INDEX,
115                                  &encoder_store_method);
116 }
117
118 /* Get encoder methods from a store, or put one in */
119 static void *get_encoder_from_store(OSSL_LIB_CTX *libctx, void *store,
120                                     void *data)
121 {
122     struct encoder_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_encoder_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_encoder_in_store(OSSL_LIB_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_encoder_store(libctx)) == NULL)
154         return 0;
155
156     return ossl_method_store_add(store, prov, id, propdef, method,
157                                  (int (*)(void *))OSSL_ENCODER_up_ref,
158                                  (void (*)(void *))OSSL_ENCODER_free);
159 }
160
161 /* Create and populate a encoder method */
162 static void *encoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
163                                     OSSL_PROVIDER *prov)
164 {
165     OSSL_ENCODER *encoder = NULL;
166     const OSSL_DISPATCH *fns = algodef->implementation;
167
168     if ((encoder = ossl_encoder_new()) == NULL)
169         return NULL;
170     encoder->base.id = id;
171     encoder->base.propdef = algodef->property_definition;
172     encoder->base.description = algodef->algorithm_description;
173
174     for (; fns->function_id != 0; fns++) {
175         switch (fns->function_id) {
176         case OSSL_FUNC_ENCODER_NEWCTX:
177             if (encoder->newctx == NULL)
178                 encoder->newctx =
179                     OSSL_FUNC_encoder_newctx(fns);
180             break;
181         case OSSL_FUNC_ENCODER_FREECTX:
182             if (encoder->freectx == NULL)
183                 encoder->freectx =
184                     OSSL_FUNC_encoder_freectx(fns);
185             break;
186         case OSSL_FUNC_ENCODER_GET_PARAMS:
187             if (encoder->get_params == NULL)
188                 encoder->get_params =
189                     OSSL_FUNC_encoder_get_params(fns);
190             break;
191         case OSSL_FUNC_ENCODER_GETTABLE_PARAMS:
192             if (encoder->gettable_params == NULL)
193                 encoder->gettable_params =
194                     OSSL_FUNC_encoder_gettable_params(fns);
195             break;
196         case OSSL_FUNC_ENCODER_SET_CTX_PARAMS:
197             if (encoder->set_ctx_params == NULL)
198                 encoder->set_ctx_params =
199                     OSSL_FUNC_encoder_set_ctx_params(fns);
200             break;
201         case OSSL_FUNC_ENCODER_SETTABLE_CTX_PARAMS:
202             if (encoder->settable_ctx_params == NULL)
203                 encoder->settable_ctx_params =
204                     OSSL_FUNC_encoder_settable_ctx_params(fns);
205             break;
206         case OSSL_FUNC_ENCODER_DOES_SELECTION:
207             if (encoder->does_selection == NULL)
208                 encoder->does_selection =
209                     OSSL_FUNC_encoder_does_selection(fns);
210             break;
211         case OSSL_FUNC_ENCODER_ENCODE:
212             if (encoder->encode == NULL)
213                 encoder->encode = OSSL_FUNC_encoder_encode(fns);
214             break;
215         case OSSL_FUNC_ENCODER_IMPORT_OBJECT:
216             if (encoder->import_object == NULL)
217                 encoder->import_object =
218                     OSSL_FUNC_encoder_import_object(fns);
219             break;
220         case OSSL_FUNC_ENCODER_FREE_OBJECT:
221             if (encoder->free_object == NULL)
222                 encoder->free_object =
223                     OSSL_FUNC_encoder_free_object(fns);
224             break;
225         }
226     }
227     /*
228      * Try to check that the method is sensible.
229      * If you have a constructor, you must have a destructor and vice versa.
230      * You must have the encoding driver functions.
231      */
232     if (!((encoder->newctx == NULL && encoder->freectx == NULL)
233           || (encoder->newctx != NULL && encoder->freectx != NULL)
234           || (encoder->import_object != NULL && encoder->free_object != NULL)
235           || (encoder->import_object == NULL && encoder->free_object == NULL))
236         || encoder->encode == NULL
237         || encoder->gettable_params == NULL
238         || encoder->get_params == NULL) {
239         OSSL_ENCODER_free(encoder);
240         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INVALID_PROVIDER_FUNCTIONS);
241         return NULL;
242     }
243
244     if (prov != NULL && !ossl_provider_up_ref(prov)) {
245         OSSL_ENCODER_free(encoder);
246         return NULL;
247     }
248
249     encoder->base.prov = prov;
250     return encoder;
251 }
252
253
254 /*
255  * The core fetching functionality passes the names of the implementation.
256  * This function is responsible to getting an identity number for them,
257  * then call encoder_from_algorithm() with that identity number.
258  */
259 static void *construct_encoder(const OSSL_ALGORITHM *algodef,
260                                OSSL_PROVIDER *prov, void *data)
261 {
262     /*
263      * This function is only called if get_encoder_from_store() returned
264      * NULL, so it's safe to say that of all the spots to create a new
265      * namemap entry, this is it.  Should the name already exist there, we
266      * know that ossl_namemap_add() will return its corresponding number.
267      */
268     struct encoder_data_st *methdata = data;
269     OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
270     OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
271     const char *names = algodef->algorithm_names;
272     int id = ossl_namemap_add_names(namemap, 0, names, NAME_SEPARATOR);
273     void *method = NULL;
274
275     if (id != 0)
276         method = encoder_from_algorithm(id, algodef, prov);
277
278     /*
279      * Flag to indicate that there was actual construction errors.  This
280      * helps inner_evp_generic_fetch() determine what error it should
281      * record on inaccessible algorithms.
282      */
283     if (method == NULL)
284         methdata->flag_construct_error_occurred = 1;
285
286     return method;
287 }
288
289 /* Intermediary function to avoid ugly casts, used below */
290 static void destruct_encoder(void *method, void *data)
291 {
292     OSSL_ENCODER_free(method);
293 }
294
295 static int up_ref_encoder(void *method)
296 {
297     return OSSL_ENCODER_up_ref(method);
298 }
299
300 static void free_encoder(void *method)
301 {
302     OSSL_ENCODER_free(method);
303 }
304
305 /* Fetching support.  Can fetch by numeric identity or by name */
306 static OSSL_ENCODER *inner_ossl_encoder_fetch(OSSL_LIB_CTX *libctx,
307                                               int id, const char *name,
308                                               const char *properties)
309 {
310     OSSL_METHOD_STORE *store = get_encoder_store(libctx);
311     OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
312     void *method = NULL;
313     int unsupported = 0;
314
315     if (store == NULL || namemap == NULL) {
316         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT);
317         return NULL;
318     }
319
320     /*
321      * If we have been passed neither a name_id or a name, we have an
322      * internal programming error.
323      */
324     if (!ossl_assert(id != 0 || name != NULL)) {
325         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
326         return NULL;
327     }
328
329     if (id == 0)
330         id = ossl_namemap_name2num(namemap, name);
331
332     /*
333      * If we haven't found the name yet, chances are that the algorithm to
334      * be fetched is unsupported.
335      */
336     if (id == 0)
337         unsupported = 1;
338
339     if (id == 0
340         || !ossl_method_store_cache_get(store, id, properties, &method)) {
341         OSSL_METHOD_CONSTRUCT_METHOD mcm = {
342             alloc_tmp_encoder_store,
343             dealloc_tmp_encoder_store,
344             get_encoder_from_store,
345             put_encoder_in_store,
346             construct_encoder,
347             destruct_encoder
348         };
349         struct encoder_data_st mcmdata;
350
351         mcmdata.libctx = libctx;
352         mcmdata.mcm = &mcm;
353         mcmdata.id = id;
354         mcmdata.names = name;
355         mcmdata.propquery = properties;
356         mcmdata.flag_construct_error_occurred = 0;
357         if ((method = ossl_method_construct(libctx, OSSL_OP_ENCODER,
358                                             0 /* !force_cache */,
359                                             &mcm, &mcmdata)) != NULL) {
360             /*
361              * If construction did create a method for us, we know that
362              * there is a correct name_id and meth_id, since those have
363              * already been calculated in get_encoder_from_store() and
364              * put_encoder_in_store() above.
365              */
366             if (id == 0)
367                 id = ossl_namemap_name2num(namemap, name);
368             ossl_method_store_cache_set(store, id, properties, method,
369                                         up_ref_encoder, free_encoder);
370         }
371
372         /*
373          * If we never were in the constructor, the algorithm to be fetched
374          * is unsupported.
375          */
376         unsupported = !mcmdata.flag_construct_error_occurred;
377     }
378
379     if (method == NULL) {
380         int code = unsupported ? ERR_R_UNSUPPORTED : ERR_R_FETCH_FAILED;
381
382         if (name == NULL)
383             name = ossl_namemap_num2name(namemap, id, 0);
384         ERR_raise_data(ERR_LIB_OSSL_ENCODER, code,
385                        "%s, Name (%s : %d), Properties (%s)",
386                        ossl_lib_ctx_get_descriptor(libctx),
387                        name = NULL ? "<null>" : name, id,
388                        properties == NULL ? "<null>" : properties);
389     }
390
391     return method;
392 }
393
394 OSSL_ENCODER *OSSL_ENCODER_fetch(OSSL_LIB_CTX *libctx, const char *name,
395                                  const char *properties)
396 {
397     return inner_ossl_encoder_fetch(libctx, 0, name, properties);
398 }
399
400 OSSL_ENCODER *ossl_encoder_fetch_by_number(OSSL_LIB_CTX *libctx, int id,
401                                            const char *properties)
402 {
403     return inner_ossl_encoder_fetch(libctx, id, NULL, properties);
404 }
405
406 /*
407  * Library of basic method functions
408  */
409
410 const OSSL_PROVIDER *OSSL_ENCODER_provider(const OSSL_ENCODER *encoder)
411 {
412     if (!ossl_assert(encoder != NULL)) {
413         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
414         return 0;
415     }
416
417     return encoder->base.prov;
418 }
419
420 const char *OSSL_ENCODER_properties(const OSSL_ENCODER *encoder)
421 {
422     if (!ossl_assert(encoder != NULL)) {
423         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
424         return 0;
425     }
426
427     return encoder->base.propdef;
428 }
429
430 int OSSL_ENCODER_number(const OSSL_ENCODER *encoder)
431 {
432     if (!ossl_assert(encoder != NULL)) {
433         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
434         return 0;
435     }
436
437     return encoder->base.id;
438 }
439
440 const char *OSSL_ENCODER_description(const OSSL_ENCODER *encoder)
441 {
442     return encoder->base.description;
443 }
444
445 int OSSL_ENCODER_is_a(const OSSL_ENCODER *encoder, const char *name)
446 {
447     if (encoder->base.prov != NULL) {
448         OSSL_LIB_CTX *libctx = ossl_provider_libctx(encoder->base.prov);
449         OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
450
451         return ossl_namemap_name2num(namemap, name) == encoder->base.id;
452     }
453     return 0;
454 }
455
456 struct encoder_do_all_data_st {
457     void (*user_fn)(void *method, void *arg);
458     void *user_arg;
459 };
460
461 static void encoder_do_one(OSSL_PROVIDER *provider,
462                            const OSSL_ALGORITHM *algodef,
463                            int no_store, void *vdata)
464 {
465     struct encoder_do_all_data_st *data = vdata;
466     OSSL_LIB_CTX *libctx = ossl_provider_libctx(provider);
467     OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
468     const char *names = algodef->algorithm_names;
469     int id = ossl_namemap_add_names(namemap, 0, names, NAME_SEPARATOR);
470     void *method = NULL;
471
472     if (id != 0)
473         method =
474             encoder_from_algorithm(id, algodef, provider);
475
476     if (method != NULL) {
477         data->user_fn(method, data->user_arg);
478         OSSL_ENCODER_free(method);
479     }
480 }
481
482 void OSSL_ENCODER_do_all_provided(OSSL_LIB_CTX *libctx,
483                                   void (*fn)(OSSL_ENCODER *encoder, void *arg),
484                                   void *arg)
485 {
486     struct encoder_do_all_data_st data;
487
488     data.user_fn = (void (*)(void *, void *))fn;
489     data.user_arg = arg;
490
491     /*
492      * No pre- or post-condition for this call, as this only creates methods
493      * temporarly and then promptly destroys them.
494      */
495     ossl_algorithm_do_all(libctx, OSSL_OP_ENCODER, NULL, NULL,
496                           encoder_do_one, NULL, &data);
497 }
498
499 int OSSL_ENCODER_names_do_all(const OSSL_ENCODER *encoder,
500                               void (*fn)(const char *name, void *data),
501                               void *data)
502 {
503     if (encoder == NULL)
504         return 0;
505
506     if (encoder->base.prov != NULL) {
507         OSSL_LIB_CTX *libctx = ossl_provider_libctx(encoder->base.prov);
508         OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
509
510         return ossl_namemap_doall_names(namemap, encoder->base.id, fn, data);
511     }
512
513     return 1;
514 }
515
516 const OSSL_PARAM *
517 OSSL_ENCODER_gettable_params(OSSL_ENCODER *encoder)
518 {
519     if (encoder != NULL && encoder->gettable_params != NULL) {
520         void *provctx = ossl_provider_ctx(OSSL_ENCODER_provider(encoder));
521
522         return encoder->gettable_params(provctx);
523     }
524     return NULL;
525 }
526
527 int OSSL_ENCODER_get_params(OSSL_ENCODER *encoder, OSSL_PARAM params[])
528 {
529     if (encoder != NULL && encoder->get_params != NULL)
530         return encoder->get_params(params);
531     return 0;
532 }
533
534 const OSSL_PARAM *OSSL_ENCODER_settable_ctx_params(OSSL_ENCODER *encoder)
535 {
536     if (encoder != NULL && encoder->settable_ctx_params != NULL) {
537         void *provctx = ossl_provider_ctx(OSSL_ENCODER_provider(encoder));
538
539         return encoder->settable_ctx_params(provctx);
540     }
541     return NULL;
542 }
543
544 /*
545  * Encoder context support
546  */
547
548 OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new(void)
549 {
550     OSSL_ENCODER_CTX *ctx;
551
552     if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
553         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
554
555     return ctx;
556 }
557
558 int OSSL_ENCODER_CTX_set_params(OSSL_ENCODER_CTX *ctx,
559                                 const OSSL_PARAM params[])
560 {
561     int ok = 1;
562     size_t i;
563     size_t l;
564
565     if (!ossl_assert(ctx != NULL)) {
566         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
567         return 0;
568     }
569
570     if (ctx->encoder_insts == NULL)
571         return 1;
572
573     l = OSSL_ENCODER_CTX_get_num_encoders(ctx);
574     for (i = 0; i < l; i++) {
575         OSSL_ENCODER_INSTANCE *encoder_inst =
576             sk_OSSL_ENCODER_INSTANCE_value(ctx->encoder_insts, i);
577         OSSL_ENCODER *encoder = OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst);
578         void *encoderctx = OSSL_ENCODER_INSTANCE_get_encoder_ctx(encoder_inst);
579
580         if (encoderctx == NULL || encoder->set_ctx_params == NULL)
581             continue;
582         if (!encoder->set_ctx_params(encoderctx, params))
583             ok = 0;
584     }
585     return ok;
586 }
587
588 void OSSL_ENCODER_CTX_free(OSSL_ENCODER_CTX *ctx)
589 {
590     if (ctx != NULL) {
591         sk_OSSL_ENCODER_INSTANCE_pop_free(ctx->encoder_insts,
592                                           ossl_encoder_instance_free);
593         OPENSSL_free(ctx->construct_data);
594         ossl_pw_clear_passphrase_data(&ctx->pwdata);
595         OPENSSL_free(ctx);
596     }
597 }