Instead of global data store it in an OPENSSL_CTX
[openssl.git] / crypto / evp / evp_fetch.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 <stddef.h>
11 #include <openssl/ossl_typ.h>
12 #include <openssl/evp.h>
13 #include <openssl/core.h>
14 #include "internal/cryptlib.h"
15 #include "internal/thread_once.h"
16 #include "internal/asn1_int.h"
17 #include "internal/property.h"
18 #include "internal/core.h"
19 #include "internal/evp_int.h"    /* evp_locl.h needs it */
20 #include "evp_locl.h"
21
22 static void default_method_store_free(void *vstore)
23 {
24     ossl_method_store_free(vstore);
25 }
26
27 static void *default_method_store_new(OPENSSL_CTX *ctx)
28 {
29     return ossl_method_store_new(ctx);
30 }
31
32
33 static const OPENSSL_CTX_METHOD default_method_store_method = {
34     default_method_store_new,
35     default_method_store_free,
36 };
37
38 /* Data to be passed through ossl_method_construct() */
39 struct method_data_st {
40     const char *name;
41     int nid;
42     OSSL_METHOD_CONSTRUCT_METHOD *mcm;
43     void *(*method_from_dispatch)(int nid, const OSSL_DISPATCH *,
44                                   OSSL_PROVIDER *);
45     int (*refcnt_up_method)(void *method);
46     void (*destruct_method)(void *method);
47     int (*nid_method)(void *method);
48 };
49
50 /*
51  * Generic routines to fetch / create EVP methods with ossl_method_construct()
52  */
53 static void *alloc_tmp_method_store(OPENSSL_CTX *ctx)
54 {
55     return ossl_method_store_new(ctx);
56 }
57
58  static void dealloc_tmp_method_store(void *store)
59 {
60     if (store != NULL)
61         ossl_method_store_free(store);
62 }
63
64 static OSSL_METHOD_STORE *get_default_method_store(OPENSSL_CTX *libctx)
65 {
66     return openssl_ctx_get_data(libctx, OPENSSL_CTX_DEFAULT_METHOD_STORE_INDEX,
67                                 &default_method_store_method);
68 }
69
70 static void *get_method_from_store(OPENSSL_CTX *libctx, void *store,
71                                    const char *propquery, void *data)
72 {
73     struct method_data_st *methdata = data;
74     void *method = NULL;
75
76     if (store == NULL
77         && (store = get_default_method_store(libctx)) == NULL)
78         return NULL;
79
80     (void)ossl_method_store_fetch(store, methdata->nid, propquery, &method);
81
82     if (method != NULL
83         && !methdata->refcnt_up_method(method)) {
84         method = NULL;
85     }
86     return method;
87 }
88
89 static int put_method_in_store(OPENSSL_CTX *libctx, void *store,
90                                const char *propdef,
91                                void *method, void *data)
92 {
93     struct method_data_st *methdata = data;
94     int nid = methdata->nid_method(method);
95
96     if (nid == NID_undef)
97         return 0;
98
99     if (store == NULL
100         && (store = get_default_method_store(libctx)) == NULL)
101         return 0;
102
103     if (methdata->refcnt_up_method(method)
104         && ossl_method_store_add(store, nid, propdef, method,
105                                  methdata->destruct_method))
106         return 1;
107     return 0;
108 }
109
110 static void *construct_method(const char *algorithm_name,
111                               const OSSL_DISPATCH *fns, OSSL_PROVIDER *prov,
112                               void *data)
113 {
114     struct method_data_st *methdata = data;
115     void *method = NULL;
116     int nid = OBJ_sn2nid(algorithm_name);
117
118     if (nid == NID_undef) {
119         /* Create a new NID for that name on the fly */
120         ASN1_OBJECT tmpobj;
121
122         /* This is the same as OBJ_create() but without requiring a OID */
123         tmpobj.nid = OBJ_new_nid(1);
124         tmpobj.sn = tmpobj.ln = methdata->name;
125         tmpobj.flags = ASN1_OBJECT_FLAG_DYNAMIC;
126         tmpobj.length = 0;
127         tmpobj.data = NULL;
128
129         nid = OBJ_add_object(&tmpobj);
130     }
131
132     if (nid == NID_undef)
133         return NULL;
134
135     method = methdata->method_from_dispatch(nid, fns, prov);
136     if (method == NULL)
137         return NULL;
138     return method;
139 }
140
141 static void destruct_method(void *method, void *data)
142 {
143     struct method_data_st *methdata = data;
144
145     methdata->destruct_method(method);
146 }
147
148 void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id,
149                         const char *algorithm, const char *properties,
150                         void *(*new_method)(int nid, const OSSL_DISPATCH *fns,
151                                             OSSL_PROVIDER *prov),
152                         int (*upref_method)(void *),
153                         void (*free_method)(void *),
154                         int (*nid_method)(void *))
155 {
156     OSSL_METHOD_STORE *store = get_default_method_store(libctx);
157     int nid = OBJ_sn2nid(algorithm);
158     void *method = NULL;
159
160     if (store == NULL)
161         return NULL;
162
163     if (nid == NID_undef
164         || !ossl_method_store_cache_get(store, nid, properties, &method)) {
165         OSSL_METHOD_CONSTRUCT_METHOD mcm = {
166             alloc_tmp_method_store,
167             dealloc_tmp_method_store,
168             get_method_from_store,
169             put_method_in_store,
170             construct_method,
171             destruct_method
172         };
173         struct method_data_st mcmdata;
174
175         mcmdata.nid = nid;
176         mcmdata.mcm = &mcm;
177         mcmdata.method_from_dispatch = new_method;
178         mcmdata.destruct_method = free_method;
179         mcmdata.refcnt_up_method = upref_method;
180         mcmdata.destruct_method = free_method;
181         mcmdata.nid_method = nid_method;
182         method = ossl_method_construct(libctx, operation_id, algorithm,
183                                        properties, 0 /* !force_cache */,
184                                        &mcm, &mcmdata);
185         ossl_method_store_cache_set(store, nid, properties, method);
186     } else {
187         upref_method(method);
188     }
189
190     return method;
191 }
192
193 int EVP_set_default_properties(OPENSSL_CTX *libctx, const char *propq)
194 {
195     OSSL_METHOD_STORE *store = get_default_method_store(libctx);
196
197     if (store != NULL)
198         return ossl_method_store_set_global_properties(store, propq);
199     EVPerr(EVP_F_EVP_SET_DEFAULT_PROPERTIES, ERR_R_INTERNAL_ERROR);
200     return 0;
201 }