1 /*
2 * Copyright 2016-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 <string.h>
11 #include "crypto/ctype.h"
12 #include <assert.h>
13
14 #include <openssl/err.h>
15 #include <openssl/lhash.h>
16 #include "store_local.h"
17
18 static CRYPTO_RWLOCK *registry_lock;
19 static CRYPTO_ONCE registry_init = CRYPTO_ONCE_STATIC_INIT;
20
DEFINE_RUN_ONCE_STATIC(do_registry_init)21 DEFINE_RUN_ONCE_STATIC(do_registry_init)
22 {
23 registry_lock = CRYPTO_THREAD_lock_new();
24 return registry_lock != NULL;
25 }
26
27 /*
28 * Functions for manipulating OSSL_STORE_LOADERs
29 */
30
OSSL_STORE_LOADER_new(ENGINE * e,const char * scheme)31 OSSL_STORE_LOADER *OSSL_STORE_LOADER_new(ENGINE *e, const char *scheme)
32 {
33 OSSL_STORE_LOADER *res = NULL;
34
35 /*
36 * We usually don't check NULL arguments. For loaders, though, the
37 * scheme is crucial and must never be NULL, or the user will get
38 * mysterious errors when trying to register the created loader
39 * later on.
40 */
41 if (scheme == NULL) {
42 ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_INVALID_SCHEME);
43 return NULL;
44 }
45
46 if ((res = OPENSSL_zalloc(sizeof(*res))) == NULL)
47 return NULL;
48
49 res->engine = e;
50 res->scheme = scheme;
51 return res;
52 }
53
OSSL_STORE_LOADER_get0_engine(const OSSL_STORE_LOADER * loader)54 const ENGINE *OSSL_STORE_LOADER_get0_engine(const OSSL_STORE_LOADER *loader)
55 {
56 return loader->engine;
57 }
58
OSSL_STORE_LOADER_get0_scheme(const OSSL_STORE_LOADER * loader)59 const char *OSSL_STORE_LOADER_get0_scheme(const OSSL_STORE_LOADER *loader)
60 {
61 return loader->scheme;
62 }
63
OSSL_STORE_LOADER_set_open(OSSL_STORE_LOADER * loader,OSSL_STORE_open_fn open_function)64 int OSSL_STORE_LOADER_set_open(OSSL_STORE_LOADER *loader,
65 OSSL_STORE_open_fn open_function)
66 {
67 loader->open = open_function;
68 return 1;
69 }
70
OSSL_STORE_LOADER_set_open_ex(OSSL_STORE_LOADER * loader,OSSL_STORE_open_ex_fn open_ex_function)71 int OSSL_STORE_LOADER_set_open_ex
72 (OSSL_STORE_LOADER *loader,
73 OSSL_STORE_open_ex_fn open_ex_function)
74 {
75 loader->open_ex = open_ex_function;
76 return 1;
77 }
78
OSSL_STORE_LOADER_set_attach(OSSL_STORE_LOADER * loader,OSSL_STORE_attach_fn attach_function)79 int OSSL_STORE_LOADER_set_attach(OSSL_STORE_LOADER *loader,
80 OSSL_STORE_attach_fn attach_function)
81 {
82 loader->attach = attach_function;
83 return 1;
84 }
85
OSSL_STORE_LOADER_set_ctrl(OSSL_STORE_LOADER * loader,OSSL_STORE_ctrl_fn ctrl_function)86 int OSSL_STORE_LOADER_set_ctrl(OSSL_STORE_LOADER *loader,
87 OSSL_STORE_ctrl_fn ctrl_function)
88 {
89 loader->ctrl = ctrl_function;
90 return 1;
91 }
92
OSSL_STORE_LOADER_set_expect(OSSL_STORE_LOADER * loader,OSSL_STORE_expect_fn expect_function)93 int OSSL_STORE_LOADER_set_expect(OSSL_STORE_LOADER *loader,
94 OSSL_STORE_expect_fn expect_function)
95 {
96 loader->expect = expect_function;
97 return 1;
98 }
99
OSSL_STORE_LOADER_set_find(OSSL_STORE_LOADER * loader,OSSL_STORE_find_fn find_function)100 int OSSL_STORE_LOADER_set_find(OSSL_STORE_LOADER *loader,
101 OSSL_STORE_find_fn find_function)
102 {
103 loader->find = find_function;
104 return 1;
105 }
106
OSSL_STORE_LOADER_set_load(OSSL_STORE_LOADER * loader,OSSL_STORE_load_fn load_function)107 int OSSL_STORE_LOADER_set_load(OSSL_STORE_LOADER *loader,
108 OSSL_STORE_load_fn load_function)
109 {
110 loader->load = load_function;
111 return 1;
112 }
113
OSSL_STORE_LOADER_set_eof(OSSL_STORE_LOADER * loader,OSSL_STORE_eof_fn eof_function)114 int OSSL_STORE_LOADER_set_eof(OSSL_STORE_LOADER *loader,
115 OSSL_STORE_eof_fn eof_function)
116 {
117 loader->eof = eof_function;
118 return 1;
119 }
120
OSSL_STORE_LOADER_set_error(OSSL_STORE_LOADER * loader,OSSL_STORE_error_fn error_function)121 int OSSL_STORE_LOADER_set_error(OSSL_STORE_LOADER *loader,
122 OSSL_STORE_error_fn error_function)
123 {
124 loader->error = error_function;
125 return 1;
126 }
127
OSSL_STORE_LOADER_set_close(OSSL_STORE_LOADER * loader,OSSL_STORE_close_fn close_function)128 int OSSL_STORE_LOADER_set_close(OSSL_STORE_LOADER *loader,
129 OSSL_STORE_close_fn close_function)
130 {
131 loader->closefn = close_function;
132 return 1;
133 }
134
135 /*
136 * Functions for registering OSSL_STORE_LOADERs
137 */
138
store_loader_hash(const OSSL_STORE_LOADER * v)139 static unsigned long store_loader_hash(const OSSL_STORE_LOADER *v)
140 {
141 return OPENSSL_LH_strhash(v->scheme);
142 }
143
store_loader_cmp(const OSSL_STORE_LOADER * a,const OSSL_STORE_LOADER * b)144 static int store_loader_cmp(const OSSL_STORE_LOADER *a,
145 const OSSL_STORE_LOADER *b)
146 {
147 assert(a->scheme != NULL && b->scheme != NULL);
148 return strcmp(a->scheme, b->scheme);
149 }
150
151 static LHASH_OF(OSSL_STORE_LOADER) *loader_register = NULL;
ossl_store_register_init(void)152 static int ossl_store_register_init(void)
153 {
154 if (loader_register == NULL) {
155 loader_register = lh_OSSL_STORE_LOADER_new(store_loader_hash,
156 store_loader_cmp);
157 }
158 return loader_register != NULL;
159 }
160
ossl_store_register_loader_int(OSSL_STORE_LOADER * loader)161 int ossl_store_register_loader_int(OSSL_STORE_LOADER *loader)
162 {
163 const char *scheme = loader->scheme;
164 int ok = 0;
165
166 /*
167 * Check that the given scheme conforms to correct scheme syntax as per
168 * RFC 3986:
169 *
170 * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
171 */
172 if (ossl_isalpha(*scheme))
173 while (*scheme != '\0'
174 && (ossl_isalpha(*scheme)
175 || ossl_isdigit(*scheme)
176 || strchr("+-.", *scheme) != NULL))
177 scheme++;
178 if (*scheme != '\0') {
179 ERR_raise_data(ERR_LIB_OSSL_STORE, OSSL_STORE_R_INVALID_SCHEME,
180 "scheme=%s", loader->scheme);
181 return 0;
182 }
183
184 /* Check that functions we absolutely require are present */
185 if (loader->open == NULL || loader->load == NULL || loader->eof == NULL
186 || loader->error == NULL || loader->closefn == NULL) {
187 ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADER_INCOMPLETE);
188 return 0;
189 }
190
191 if (!RUN_ONCE(®istry_init, do_registry_init)) {
192 /* Should this error be raised in do_registry_init()? */
193 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_CRYPTO_LIB);
194 return 0;
195 }
196 if (!CRYPTO_THREAD_write_lock(registry_lock))
197 return 0;
198
199 if (ossl_store_register_init()
200 && (lh_OSSL_STORE_LOADER_insert(loader_register, loader) != NULL
201 || lh_OSSL_STORE_LOADER_error(loader_register) == 0))
202 ok = 1;
203
204 CRYPTO_THREAD_unlock(registry_lock);
205
206 return ok;
207 }
OSSL_STORE_register_loader(OSSL_STORE_LOADER * loader)208 int OSSL_STORE_register_loader(OSSL_STORE_LOADER *loader)
209 {
210 return ossl_store_register_loader_int(loader);
211 }
212
ossl_store_get0_loader_int(const char * scheme)213 const OSSL_STORE_LOADER *ossl_store_get0_loader_int(const char *scheme)
214 {
215 OSSL_STORE_LOADER template;
216 OSSL_STORE_LOADER *loader = NULL;
217
218 template.scheme = scheme;
219 template.open = NULL;
220 template.load = NULL;
221 template.eof = NULL;
222 template.closefn = NULL;
223 template.open_ex = NULL;
224
225 if (!RUN_ONCE(®istry_init, do_registry_init)) {
226 /* Should this error be raised in do_registry_init()? */
227 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_CRYPTO_LIB);
228 return NULL;
229 }
230 if (!CRYPTO_THREAD_write_lock(registry_lock))
231 return NULL;
232
233 if (!ossl_store_register_init())
234 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_INTERNAL_ERROR);
235 else if ((loader = lh_OSSL_STORE_LOADER_retrieve(loader_register,
236 &template)) == NULL)
237 ERR_raise_data(ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNREGISTERED_SCHEME,
238 "scheme=%s", scheme);
239
240 CRYPTO_THREAD_unlock(registry_lock);
241
242 return loader;
243 }
244
ossl_store_unregister_loader_int(const char * scheme)245 OSSL_STORE_LOADER *ossl_store_unregister_loader_int(const char *scheme)
246 {
247 OSSL_STORE_LOADER template;
248 OSSL_STORE_LOADER *loader = NULL;
249
250 template.scheme = scheme;
251 template.open = NULL;
252 template.load = NULL;
253 template.eof = NULL;
254 template.closefn = NULL;
255
256 if (!RUN_ONCE(®istry_init, do_registry_init)) {
257 /* Should this error be raised in do_registry_init()? */
258 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_CRYPTO_LIB);
259 return NULL;
260 }
261 if (!CRYPTO_THREAD_write_lock(registry_lock))
262 return NULL;
263
264 if (!ossl_store_register_init())
265 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_INTERNAL_ERROR);
266 else if ((loader = lh_OSSL_STORE_LOADER_delete(loader_register,
267 &template)) == NULL)
268 ERR_raise_data(ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNREGISTERED_SCHEME,
269 "scheme=%s", scheme);
270
271 CRYPTO_THREAD_unlock(registry_lock);
272
273 return loader;
274 }
OSSL_STORE_unregister_loader(const char * scheme)275 OSSL_STORE_LOADER *OSSL_STORE_unregister_loader(const char *scheme)
276 {
277 return ossl_store_unregister_loader_int(scheme);
278 }
279
ossl_store_destroy_loaders_int(void)280 void ossl_store_destroy_loaders_int(void)
281 {
282 lh_OSSL_STORE_LOADER_free(loader_register);
283 loader_register = NULL;
284 CRYPTO_THREAD_lock_free(registry_lock);
285 registry_lock = NULL;
286 }
287
288 /*
289 * Functions to list OSSL_STORE loaders
290 */
291
292 IMPLEMENT_LHASH_DOALL_ARG_CONST(OSSL_STORE_LOADER, void);
OSSL_STORE_do_all_loaders(void (* do_function)(const OSSL_STORE_LOADER * loader,void * do_arg),void * do_arg)293 int OSSL_STORE_do_all_loaders(void (*do_function) (const OSSL_STORE_LOADER
294 *loader, void *do_arg),
295 void *do_arg)
296 {
297 if (ossl_store_register_init())
298 lh_OSSL_STORE_LOADER_doall_void(loader_register, do_function, do_arg);
299 return 1;
300 }
301