Update copyright year
[openssl.git] / crypto / store / store_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/store.h>
11 #include <openssl/crypto.h>
12 #include "internal/core.h"
13 #include "internal/namemap.h"
14 #include "internal/property.h"
15 #include "internal/provider.h"
16 #include "store_local.h"
17
18 int OSSL_STORE_LOADER_up_ref(OSSL_STORE_LOADER *loader)
19 {
20     int ref = 0;
21
22     if (loader->prov != NULL)
23         CRYPTO_UP_REF(&loader->refcnt, &ref, loader->lock);
24     return 1;
25 }
26
27 void OSSL_STORE_LOADER_free(OSSL_STORE_LOADER *loader)
28 {
29     if (loader != NULL && loader->prov != NULL) {
30         int i;
31
32         CRYPTO_DOWN_REF(&loader->refcnt, &i, loader->lock);
33         if (i > 0)
34             return;
35         ossl_provider_free(loader->prov);
36         CRYPTO_THREAD_lock_free(loader->lock);
37     }
38     OPENSSL_free(loader);
39 }
40
41 /*
42  * OSSL_STORE_LOADER_new() expects the scheme as a constant string,
43  * which we currently don't have, so we need an alternative allocator.
44  */
45 static OSSL_STORE_LOADER *new_loader(OSSL_PROVIDER *prov)
46 {
47     OSSL_STORE_LOADER *loader;
48
49     if ((loader = OPENSSL_zalloc(sizeof(*loader))) == NULL
50         || (loader->lock = CRYPTO_THREAD_lock_new()) == NULL) {
51         OPENSSL_free(loader);
52         return NULL;
53     }
54     loader->prov = prov;
55     ossl_provider_up_ref(prov);
56     loader->refcnt = 1;
57
58     return loader;
59 }
60
61 static int up_ref_loader(void *method)
62 {
63     return OSSL_STORE_LOADER_up_ref(method);
64 }
65
66 static void free_loader(void *method)
67 {
68     OSSL_STORE_LOADER_free(method);
69 }
70
71 /* Permanent loader method store, constructor and destructor */
72 static void loader_store_free(void *vstore)
73 {
74     ossl_method_store_free(vstore);
75 }
76
77 static void *loader_store_new(OSSL_LIB_CTX *ctx)
78 {
79     return ossl_method_store_new(ctx);
80 }
81
82
83 static const OSSL_LIB_CTX_METHOD loader_store_method = {
84     loader_store_new,
85     loader_store_free,
86 };
87
88 /* Data to be passed through ossl_method_construct() */
89 struct loader_data_st {
90     OSSL_LIB_CTX *libctx;
91     OSSL_METHOD_CONSTRUCT_METHOD *mcm;
92     int scheme_id;               /* For get_loader_from_store() */
93     const char *scheme;          /* For get_loader_from_store() */
94     const char *propquery;       /* For get_loader_from_store() */
95 };
96
97 /*
98  * Generic routines to fetch / create OSSL_STORE methods with
99  * ossl_method_construct()
100  */
101
102 /* Temporary loader method store, constructor and destructor */
103 static void *alloc_tmp_loader_store(OSSL_LIB_CTX *ctx)
104 {
105     return ossl_method_store_new(ctx);
106 }
107
108  static void dealloc_tmp_loader_store(void *store)
109 {
110     if (store != NULL)
111         ossl_method_store_free(store);
112 }
113
114 /* Get the permanent loader store */
115 static OSSL_METHOD_STORE *get_loader_store(OSSL_LIB_CTX *libctx)
116 {
117     return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_STORE_LOADER_STORE_INDEX,
118                                 &loader_store_method);
119 }
120
121 /* Get loader methods from a store, or put one in */
122 static void *get_loader_from_store(OSSL_LIB_CTX *libctx, void *store,
123                                    void *data)
124 {
125     struct loader_data_st *methdata = data;
126     void *method = NULL;
127     int id;
128
129     if ((id = methdata->scheme_id) == 0) {
130         OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
131
132         id = ossl_namemap_name2num(namemap, methdata->scheme);
133     }
134
135     if (store == NULL
136         && (store = get_loader_store(libctx)) == NULL)
137         return NULL;
138
139     if (!ossl_method_store_fetch(store, id, methdata->propquery, &method))
140         return NULL;
141     return method;
142 }
143
144 static int put_loader_in_store(OSSL_LIB_CTX *libctx, void *store,
145                                void *method, const OSSL_PROVIDER *prov,
146                                int operation_id, const char *scheme,
147                                const char *propdef, void *unused)
148 {
149     OSSL_NAMEMAP *namemap;
150     int id;
151
152     if ((namemap = ossl_namemap_stored(libctx)) == NULL
153         || (id = ossl_namemap_name2num(namemap, scheme)) == 0)
154         return 0;
155
156     if (store == NULL && (store = get_loader_store(libctx)) == NULL)
157         return 0;
158
159     return ossl_method_store_add(store, prov, id, propdef, method,
160                                  up_ref_loader, free_loader);
161 }
162
163 static void *loader_from_dispatch(int scheme_id, const OSSL_ALGORITHM *algodef,
164                                   OSSL_PROVIDER *prov)
165 {
166     OSSL_STORE_LOADER *loader = NULL;
167     const OSSL_DISPATCH *fns = algodef->implementation;
168
169     if ((loader = new_loader(prov)) == NULL)
170         return NULL;
171     loader->scheme_id = scheme_id;
172     loader->propdef = algodef->property_definition;
173
174     for (; fns->function_id != 0; fns++) {
175         switch (fns->function_id) {
176         case OSSL_FUNC_STORE_OPEN:
177             if (loader->p_open == NULL)
178                 loader->p_open = OSSL_FUNC_store_open(fns);
179             break;
180         case OSSL_FUNC_STORE_ATTACH:
181             if (loader->p_attach == NULL)
182                 loader->p_attach = OSSL_FUNC_store_attach(fns);
183             break;
184         case OSSL_FUNC_STORE_SETTABLE_CTX_PARAMS:
185             if (loader->p_settable_ctx_params == NULL)
186                 loader->p_settable_ctx_params =
187                     OSSL_FUNC_store_settable_ctx_params(fns);
188             break;
189         case OSSL_FUNC_STORE_SET_CTX_PARAMS:
190             if (loader->p_set_ctx_params == NULL)
191                 loader->p_set_ctx_params = OSSL_FUNC_store_set_ctx_params(fns);
192             break;
193         case OSSL_FUNC_STORE_LOAD:
194             if (loader->p_load == NULL)
195                 loader->p_load = OSSL_FUNC_store_load(fns);
196             break;
197         case OSSL_FUNC_STORE_EOF:
198             if (loader->p_eof == NULL)
199                 loader->p_eof = OSSL_FUNC_store_eof(fns);
200             break;
201         case OSSL_FUNC_STORE_CLOSE:
202             if (loader->p_close == NULL)
203                 loader->p_close = OSSL_FUNC_store_close(fns);
204             break;
205         case OSSL_FUNC_STORE_EXPORT_OBJECT:
206             if (loader->p_export_object == NULL)
207                 loader->p_export_object = OSSL_FUNC_store_export_object(fns);
208             break;
209         }
210     }
211
212     if ((loader->p_open == NULL && loader->p_attach == NULL)
213         || loader->p_load == NULL
214         || loader->p_eof == NULL
215         || loader->p_close == NULL) {
216         /* Only set_ctx_params is optionaal */
217         OSSL_STORE_LOADER_free(loader);
218         ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADER_INCOMPLETE);
219         return NULL;
220     }
221     return loader;
222 }
223
224 /*
225  * The core fetching functionality passes the scheme of the implementation.
226  * This function is responsible to getting an identity number for them,
227  * then call loader_from_dispatch() with that identity number.
228  */
229 static void *construct_loader(const OSSL_ALGORITHM *algodef,
230                               OSSL_PROVIDER *prov, void *unused)
231 {
232     /*
233      * This function is only called if get_loader_from_store() returned
234      * NULL, so it's safe to say that of all the spots to create a new
235      * namemap entry, this is it.  Should the scheme already exist there, we
236      * know that ossl_namemap_add() will return its corresponding number.
237      */
238     OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
239     OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
240     const char *scheme = algodef->algorithm_names;
241     int id = ossl_namemap_add_name(namemap, 0, scheme);
242     void *method = NULL;
243
244     if (id != 0)
245         method = loader_from_dispatch(id, algodef, prov);
246
247     return method;
248 }
249
250 /* Intermediary function to avoid ugly casts, used below */
251 static void destruct_loader(void *method, void *data)
252 {
253     OSSL_STORE_LOADER_free(method);
254 }
255
256 /* Fetching support.  Can fetch by numeric identity or by scheme */
257 static OSSL_STORE_LOADER *inner_loader_fetch(OSSL_LIB_CTX *libctx,
258                                              int id, const char *scheme,
259                                              const char *properties)
260 {
261     OSSL_METHOD_STORE *store = get_loader_store(libctx);
262     OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
263     void *method = NULL;
264
265     if (store == NULL || namemap == NULL)
266         return NULL;
267
268     /*
269      * If we have been passed neither a scheme_id or a scheme, we have an
270      * internal programming error.
271      */
272     if (!ossl_assert(id != 0 || scheme != NULL))
273         return NULL;
274
275     if (id == 0)
276         id = ossl_namemap_name2num(namemap, scheme);
277
278     if (id == 0
279         || !ossl_method_store_cache_get(store, id, properties, &method)) {
280         OSSL_METHOD_CONSTRUCT_METHOD mcm = {
281             alloc_tmp_loader_store,
282             dealloc_tmp_loader_store,
283             get_loader_from_store,
284             put_loader_in_store,
285             construct_loader,
286             destruct_loader
287         };
288         struct loader_data_st mcmdata;
289
290         mcmdata.libctx = libctx;
291         mcmdata.mcm = &mcm;
292         mcmdata.scheme_id = id;
293         mcmdata.scheme = scheme;
294         mcmdata.propquery = properties;
295         if ((method = ossl_method_construct(libctx, OSSL_OP_STORE,
296                                             0 /* !force_cache */,
297                                             &mcm, &mcmdata)) != NULL) {
298             /*
299              * If construction did create a method for us, we know that there
300              * is a correct scheme_id, since those have already been calculated
301              * in get_loader_from_store() and put_loader_in_store() above.
302              */
303             if (id == 0)
304                 id = ossl_namemap_name2num(namemap, scheme);
305             ossl_method_store_cache_set(store, id, properties, method,
306                                         up_ref_loader, free_loader);
307         }
308     }
309
310     return method;
311 }
312
313 OSSL_STORE_LOADER *OSSL_STORE_LOADER_fetch(const char *scheme,
314                                            OSSL_LIB_CTX *libctx,
315                                            const char *properties)
316 {
317     return inner_loader_fetch(libctx, 0, scheme, properties);
318 }
319
320 OSSL_STORE_LOADER *ossl_store_loader_fetch_by_number(OSSL_LIB_CTX *libctx,
321                                                      int scheme_id,
322                                                      const char *properties)
323 {
324     return inner_loader_fetch(libctx, scheme_id, NULL, properties);
325 }
326
327 /*
328  * Library of basic method functions
329  */
330
331 const OSSL_PROVIDER *OSSL_STORE_LOADER_provider(const OSSL_STORE_LOADER *loader)
332 {
333     if (!ossl_assert(loader != NULL)) {
334         ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER);
335         return 0;
336     }
337
338     return loader->prov;
339 }
340
341 const char *OSSL_STORE_LOADER_properties(const OSSL_STORE_LOADER *loader)
342 {
343     if (!ossl_assert(loader != NULL)) {
344         ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER);
345         return 0;
346     }
347
348     return loader->propdef;
349 }
350
351 int OSSL_STORE_LOADER_number(const OSSL_STORE_LOADER *loader)
352 {
353     if (!ossl_assert(loader != NULL)) {
354         ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER);
355         return 0;
356     }
357
358     return loader->scheme_id;
359 }
360
361 int OSSL_STORE_LOADER_is_a(const OSSL_STORE_LOADER *loader, const char *name)
362 {
363     if (loader->prov != NULL) {
364         OSSL_LIB_CTX *libctx = ossl_provider_libctx(loader->prov);
365         OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
366
367         return ossl_namemap_name2num(namemap, name) == loader->scheme_id;
368     }
369     return 0;
370 }
371
372 struct loader_do_all_data_st {
373     void (*user_fn)(void *method, void *arg);
374     void *user_arg;
375 };
376
377 static void loader_do_one(OSSL_PROVIDER *provider,
378                           const OSSL_ALGORITHM *algodef,
379                           int no_store, void *vdata)
380 {
381     struct loader_do_all_data_st *data = vdata;
382     OSSL_LIB_CTX *libctx = ossl_provider_libctx(provider);
383     OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
384     const char *name = algodef->algorithm_names;
385     int id = ossl_namemap_add_name(namemap, 0, name);
386     void *method = NULL;
387
388     if (id != 0)
389         method =
390             loader_from_dispatch(id, algodef, provider);
391
392     if (method != NULL) {
393         data->user_fn(method, data->user_arg);
394         OSSL_STORE_LOADER_free(method);
395     }
396 }
397
398 void OSSL_STORE_LOADER_do_all_provided(OSSL_LIB_CTX *libctx,
399                                        void (*fn)(OSSL_STORE_LOADER *loader,
400                                                   void *arg),
401                                        void *arg)
402 {
403     struct loader_do_all_data_st data;
404
405     data.user_fn = (void (*)(void *, void *))fn;
406     data.user_arg = arg;
407     ossl_algorithm_do_all(libctx, OSSL_OP_STORE, NULL,
408                           NULL, loader_do_one, NULL,
409                           &data);
410 }
411
412 void OSSL_STORE_LOADER_names_do_all(const OSSL_STORE_LOADER *loader,
413                                     void (*fn)(const char *name, void *data),
414                                     void *data)
415 {
416     if (loader == NULL)
417         return;
418
419     if (loader->prov != NULL) {
420         OSSL_LIB_CTX *libctx = ossl_provider_libctx(loader->prov);
421         OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
422
423         ossl_namemap_doall_names(namemap, loader->scheme_id, fn, data);
424     }
425 }