ENCODER: Add support for OSSL_FUNC_encoder_does_selection()
[openssl.git] / crypto / encode_decode / encoder_meth.c
1 /*
2  * Copyright 2019-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/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
92 /*
93  * Generic routines to fetch / create ENCODER methods with
94  * ossl_method_construct()
95  */
96
97 /* Temporary encoder method store, constructor and destructor */
98 static void *alloc_tmp_encoder_store(OSSL_LIB_CTX *ctx)
99 {
100     return ossl_method_store_new(ctx);
101 }
102
103 static void dealloc_tmp_encoder_store(void *store)
104 {
105     if (store != NULL)
106         ossl_method_store_free(store);
107 }
108
109 /* Get the permanent encoder store */
110 static OSSL_METHOD_STORE *get_encoder_store(OSSL_LIB_CTX *libctx)
111 {
112     return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_ENCODER_STORE_INDEX,
113                                  &encoder_store_method);
114 }
115
116 /* Get encoder methods from a store, or put one in */
117 static void *get_encoder_from_store(OSSL_LIB_CTX *libctx, void *store,
118                                     void *data)
119 {
120     struct encoder_data_st *methdata = data;
121     void *method = NULL;
122     int id;
123
124     if ((id = methdata->id) == 0) {
125         OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
126
127         id = ossl_namemap_name2num(namemap, methdata->names);
128     }
129
130     if (store == NULL
131         && (store = get_encoder_store(libctx)) == NULL)
132         return NULL;
133
134     if (!ossl_method_store_fetch(store, id, methdata->propquery, &method))
135         return NULL;
136     return method;
137 }
138
139 static int put_encoder_in_store(OSSL_LIB_CTX *libctx, void *store,
140                                 void *method, const OSSL_PROVIDER *prov,
141                                 int operation_id, const char *names,
142                                 const char *propdef, void *unused)
143 {
144     OSSL_NAMEMAP *namemap;
145     int id;
146
147     if ((namemap = ossl_namemap_stored(libctx)) == NULL
148         || (id = ossl_namemap_name2num(namemap, names)) == 0)
149         return 0;
150
151     if (store == NULL && (store = get_encoder_store(libctx)) == NULL)
152         return 0;
153
154     return ossl_method_store_add(store, prov, id, propdef, method,
155                                  (int (*)(void *))OSSL_ENCODER_up_ref,
156                                  (void (*)(void *))OSSL_ENCODER_free);
157 }
158
159 /* Create and populate a encoder method */
160 static void *encoder_from_dispatch(int id, const OSSL_ALGORITHM *algodef,
161                                    OSSL_PROVIDER *prov)
162 {
163     OSSL_ENCODER *encoder = NULL;
164     const OSSL_DISPATCH *fns = algodef->implementation;
165
166     if ((encoder = ossl_encoder_new()) == NULL)
167         return NULL;
168     encoder->base.id = id;
169     encoder->base.propdef = algodef->property_definition;
170
171     for (; fns->function_id != 0; fns++) {
172         switch (fns->function_id) {
173         case OSSL_FUNC_ENCODER_NEWCTX:
174             if (encoder->newctx == NULL)
175                 encoder->newctx =
176                     OSSL_FUNC_encoder_newctx(fns);
177             break;
178         case OSSL_FUNC_ENCODER_FREECTX:
179             if (encoder->freectx == NULL)
180                 encoder->freectx =
181                     OSSL_FUNC_encoder_freectx(fns);
182             break;
183         case OSSL_FUNC_ENCODER_GET_PARAMS:
184             if (encoder->get_params == NULL)
185                 encoder->get_params =
186                     OSSL_FUNC_encoder_get_params(fns);
187             break;
188         case OSSL_FUNC_ENCODER_GETTABLE_PARAMS:
189             if (encoder->gettable_params == NULL)
190                 encoder->gettable_params =
191                     OSSL_FUNC_encoder_gettable_params(fns);
192             break;
193         case OSSL_FUNC_ENCODER_SET_CTX_PARAMS:
194             if (encoder->set_ctx_params == NULL)
195                 encoder->set_ctx_params =
196                     OSSL_FUNC_encoder_set_ctx_params(fns);
197             break;
198         case OSSL_FUNC_ENCODER_SETTABLE_CTX_PARAMS:
199             if (encoder->settable_ctx_params == NULL)
200                 encoder->settable_ctx_params =
201                     OSSL_FUNC_encoder_settable_ctx_params(fns);
202             break;
203         case OSSL_FUNC_ENCODER_DOES_SELECTION:
204             if (encoder->does_selection == NULL)
205                 encoder->does_selection =
206                     OSSL_FUNC_encoder_does_selection(fns);
207             break;
208         case OSSL_FUNC_ENCODER_ENCODE:
209             if (encoder->encode == NULL)
210                 encoder->encode = OSSL_FUNC_encoder_encode(fns);
211             break;
212         case OSSL_FUNC_ENCODER_IMPORT_OBJECT:
213             if (encoder->import_object == NULL)
214                 encoder->import_object =
215                     OSSL_FUNC_encoder_import_object(fns);
216             break;
217         case OSSL_FUNC_ENCODER_FREE_OBJECT:
218             if (encoder->free_object == NULL)
219                 encoder->free_object =
220                     OSSL_FUNC_encoder_free_object(fns);
221             break;
222         }
223     }
224     /*
225      * Try to check that the method is sensible.
226      * If you have a constructor, you must have a destructor and vice versa.
227      * You must have the encoding driver functions.
228      */
229     if (!((encoder->newctx == NULL && encoder->freectx == NULL)
230           || (encoder->newctx != NULL && encoder->freectx != NULL)
231           || (encoder->import_object != NULL && encoder->free_object != NULL)
232           || (encoder->import_object == NULL && encoder->free_object == NULL))
233         || encoder->encode == NULL
234         || encoder->gettable_params == NULL
235         || encoder->get_params == NULL) {
236         OSSL_ENCODER_free(encoder);
237         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INVALID_PROVIDER_FUNCTIONS);
238         return NULL;
239     }
240
241     if (prov != NULL && !ossl_provider_up_ref(prov)) {
242         OSSL_ENCODER_free(encoder);
243         return NULL;
244     }
245
246     encoder->base.prov = prov;
247     return encoder;
248 }
249
250
251 /*
252  * The core fetching functionality passes the names of the implementation.
253  * This function is responsible to getting an identity number for them,
254  * then call encoder_from_dispatch() with that identity number.
255  */
256 static void *construct_encoder(const OSSL_ALGORITHM *algodef,
257                                OSSL_PROVIDER *prov, void *unused)
258 {
259     /*
260      * This function is only called if get_encoder_from_store() returned
261      * NULL, so it's safe to say that of all the spots to create a new
262      * namemap entry, this is it.  Should the name already exist there, we
263      * know that ossl_namemap_add() will return its corresponding number.
264      */
265     OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
266     OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
267     const char *names = algodef->algorithm_names;
268     int id = ossl_namemap_add_names(namemap, 0, names, NAME_SEPARATOR);
269     void *method = NULL;
270
271     if (id != 0)
272         method = encoder_from_dispatch(id, algodef, prov);
273
274     return method;
275 }
276
277 /* Intermediary function to avoid ugly casts, used below */
278 static void destruct_encoder(void *method, void *data)
279 {
280     OSSL_ENCODER_free(method);
281 }
282
283 static int up_ref_encoder(void *method)
284 {
285     return OSSL_ENCODER_up_ref(method);
286 }
287
288 static void free_encoder(void *method)
289 {
290     OSSL_ENCODER_free(method);
291 }
292
293 /* Fetching support.  Can fetch by numeric identity or by name */
294 static OSSL_ENCODER *inner_ossl_encoder_fetch(OSSL_LIB_CTX *libctx,
295                                               int id, const char *name,
296                                               const char *properties)
297 {
298     OSSL_METHOD_STORE *store = get_encoder_store(libctx);
299     OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
300     void *method = NULL;
301
302     if (store == NULL || namemap == NULL)
303         return NULL;
304
305     /*
306      * If we have been passed neither a name_id or a name, we have an
307      * internal programming error.
308      */
309     if (!ossl_assert(id != 0 || name != NULL))
310         return NULL;
311
312     if (id == 0)
313         id = ossl_namemap_name2num(namemap, name);
314
315     if (id == 0
316         || !ossl_method_store_cache_get(store, id, properties, &method)) {
317         OSSL_METHOD_CONSTRUCT_METHOD mcm = {
318             alloc_tmp_encoder_store,
319             dealloc_tmp_encoder_store,
320             get_encoder_from_store,
321             put_encoder_in_store,
322             construct_encoder,
323             destruct_encoder
324         };
325         struct encoder_data_st mcmdata;
326
327         mcmdata.libctx = libctx;
328         mcmdata.mcm = &mcm;
329         mcmdata.id = id;
330         mcmdata.names = name;
331         mcmdata.propquery = properties;
332         if ((method = ossl_method_construct(libctx, OSSL_OP_ENCODER,
333                                             0 /* !force_cache */,
334                                             &mcm, &mcmdata)) != NULL) {
335             /*
336              * If construction did create a method for us, we know that
337              * there is a correct name_id and meth_id, since those have
338              * already been calculated in get_encoder_from_store() and
339              * put_encoder_in_store() above.
340              */
341             if (id == 0)
342                 id = ossl_namemap_name2num(namemap, name);
343             ossl_method_store_cache_set(store, id, properties, method,
344                                         up_ref_encoder, free_encoder);
345         }
346     }
347
348     return method;
349 }
350
351 OSSL_ENCODER *OSSL_ENCODER_fetch(OSSL_LIB_CTX *libctx, const char *name,
352                                  const char *properties)
353 {
354     return inner_ossl_encoder_fetch(libctx, 0, name, properties);
355 }
356
357 OSSL_ENCODER *ossl_encoder_fetch_by_number(OSSL_LIB_CTX *libctx, int id,
358                                            const char *properties)
359 {
360     return inner_ossl_encoder_fetch(libctx, id, NULL, properties);
361 }
362
363 /*
364  * Library of basic method functions
365  */
366
367 const OSSL_PROVIDER *OSSL_ENCODER_provider(const OSSL_ENCODER *encoder)
368 {
369     if (!ossl_assert(encoder != NULL)) {
370         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
371         return 0;
372     }
373
374     return encoder->base.prov;
375 }
376
377 const char *OSSL_ENCODER_properties(const OSSL_ENCODER *encoder)
378 {
379     if (!ossl_assert(encoder != NULL)) {
380         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
381         return 0;
382     }
383
384     return encoder->base.propdef;
385 }
386
387 int OSSL_ENCODER_number(const OSSL_ENCODER *encoder)
388 {
389     if (!ossl_assert(encoder != NULL)) {
390         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
391         return 0;
392     }
393
394     return encoder->base.id;
395 }
396
397 int OSSL_ENCODER_is_a(const OSSL_ENCODER *encoder, const char *name)
398 {
399     if (encoder->base.prov != NULL) {
400         OSSL_LIB_CTX *libctx = ossl_provider_libctx(encoder->base.prov);
401         OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
402
403         return ossl_namemap_name2num(namemap, name) == encoder->base.id;
404     }
405     return 0;
406 }
407
408 struct encoder_do_all_data_st {
409     void (*user_fn)(void *method, void *arg);
410     void *user_arg;
411 };
412
413 static void encoder_do_one(OSSL_PROVIDER *provider,
414                            const OSSL_ALGORITHM *algodef,
415                            int no_store, void *vdata)
416 {
417     struct encoder_do_all_data_st *data = vdata;
418     OSSL_LIB_CTX *libctx = ossl_provider_libctx(provider);
419     OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
420     const char *names = algodef->algorithm_names;
421     int id = ossl_namemap_add_names(namemap, 0, names, NAME_SEPARATOR);
422     void *method = NULL;
423
424     if (id != 0)
425         method =
426             encoder_from_dispatch(id, algodef, provider);
427
428     if (method != NULL) {
429         data->user_fn(method, data->user_arg);
430         OSSL_ENCODER_free(method);
431     }
432 }
433
434 void OSSL_ENCODER_do_all_provided(OSSL_LIB_CTX *libctx,
435                                   void (*fn)(OSSL_ENCODER *encoder, void *arg),
436                                   void *arg)
437 {
438     struct encoder_do_all_data_st data;
439
440     data.user_fn = (void (*)(void *, void *))fn;
441     data.user_arg = arg;
442
443     /*
444      * No pre- or post-condition for this call, as this only creates methods
445      * temporarly and then promptly destroys them.
446      */
447     ossl_algorithm_do_all(libctx, OSSL_OP_ENCODER, NULL, NULL,
448                           encoder_do_one, NULL, &data);
449 }
450
451 void OSSL_ENCODER_names_do_all(const OSSL_ENCODER *encoder,
452                                void (*fn)(const char *name, void *data),
453                                void *data)
454 {
455     if (encoder == NULL)
456         return;
457
458     if (encoder->base.prov != NULL) {
459         OSSL_LIB_CTX *libctx = ossl_provider_libctx(encoder->base.prov);
460         OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
461
462         ossl_namemap_doall_names(namemap, encoder->base.id, fn, data);
463     }
464 }
465
466 const OSSL_PARAM *
467 OSSL_ENCODER_gettable_params(OSSL_ENCODER *encoder)
468 {
469     if (encoder != NULL && encoder->gettable_params != NULL) {
470         void *provctx = ossl_provider_ctx(OSSL_ENCODER_provider(encoder));
471
472         return encoder->gettable_params(provctx);
473     }
474     return NULL;
475 }
476
477 int OSSL_ENCODER_get_params(OSSL_ENCODER *encoder, OSSL_PARAM params[])
478 {
479     if (encoder != NULL && encoder->get_params != NULL)
480         return encoder->get_params(params);
481     return 0;
482 }
483
484 const OSSL_PARAM *OSSL_ENCODER_settable_ctx_params(OSSL_ENCODER *encoder)
485 {
486     if (encoder != NULL && encoder->settable_ctx_params != NULL) {
487         void *provctx = ossl_provider_ctx(OSSL_ENCODER_provider(encoder));
488
489         return encoder->settable_ctx_params(provctx);
490     }
491     return NULL;
492 }
493
494 /*
495  * Encoder context support
496  */
497
498 OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new(void)
499 {
500     OSSL_ENCODER_CTX *ctx;
501
502     if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
503         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
504
505     return ctx;
506 }
507
508 int OSSL_ENCODER_CTX_set_params(OSSL_ENCODER_CTX *ctx,
509                                 const OSSL_PARAM params[])
510 {
511     int ok = 1;
512     size_t i;
513     size_t l;
514
515     if (!ossl_assert(ctx != NULL)) {
516         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
517         return 0;
518     }
519
520     if (ctx->encoder_insts == NULL)
521         return 1;
522
523     l = OSSL_ENCODER_CTX_get_num_encoders(ctx);
524     for (i = 0; i < l; i++) {
525         OSSL_ENCODER_INSTANCE *encoder_inst =
526             sk_OSSL_ENCODER_INSTANCE_value(ctx->encoder_insts, i);
527         OSSL_ENCODER *encoder = OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst);
528         void *encoderctx = OSSL_ENCODER_INSTANCE_get_encoder_ctx(encoder_inst);
529
530         if (encoderctx == NULL || encoder->set_ctx_params == NULL)
531             continue;
532         if (!encoder->set_ctx_params(encoderctx, params))
533             ok = 0;
534     }
535     return ok;
536 }
537
538 void OSSL_ENCODER_CTX_free(OSSL_ENCODER_CTX *ctx)
539 {
540     if (ctx != NULL) {
541         sk_OSSL_ENCODER_INSTANCE_pop_free(ctx->encoder_insts,
542                                           ossl_encoder_instance_free);
543         OPENSSL_free(ctx->construct_data);
544         ossl_pw_clear_passphrase_data(&ctx->pwdata);
545         OPENSSL_free(ctx);
546     }
547 }