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(OSSL_STORE_LOADER *loader,
72 OSSL_STORE_open_ex_fn open_ex_function)
73 {
74 loader->open_ex = open_ex_function;
75 return 1;
76 }
77
OSSL_STORE_LOADER_set_attach(OSSL_STORE_LOADER * loader,OSSL_STORE_attach_fn attach_function)78 int OSSL_STORE_LOADER_set_attach(OSSL_STORE_LOADER *loader,
79 OSSL_STORE_attach_fn attach_function)
80 {
81 loader->attach = attach_function;
82 return 1;
83 }
84
OSSL_STORE_LOADER_set_ctrl(OSSL_STORE_LOADER * loader,OSSL_STORE_ctrl_fn ctrl_function)85 int OSSL_STORE_LOADER_set_ctrl(OSSL_STORE_LOADER *loader,
86 OSSL_STORE_ctrl_fn ctrl_function)
87 {
88 loader->ctrl = ctrl_function;
89 return 1;
90 }
91
OSSL_STORE_LOADER_set_expect(OSSL_STORE_LOADER * loader,OSSL_STORE_expect_fn expect_function)92 int OSSL_STORE_LOADER_set_expect(OSSL_STORE_LOADER *loader,
93 OSSL_STORE_expect_fn expect_function)
94 {
95 loader->expect = expect_function;
96 return 1;
97 }
98
OSSL_STORE_LOADER_set_find(OSSL_STORE_LOADER * loader,OSSL_STORE_find_fn find_function)99 int OSSL_STORE_LOADER_set_find(OSSL_STORE_LOADER *loader,
100 OSSL_STORE_find_fn find_function)
101 {
102 loader->find = find_function;
103 return 1;
104 }
105
OSSL_STORE_LOADER_set_load(OSSL_STORE_LOADER * loader,OSSL_STORE_load_fn load_function)106 int OSSL_STORE_LOADER_set_load(OSSL_STORE_LOADER *loader,
107 OSSL_STORE_load_fn load_function)
108 {
109 loader->load = load_function;
110 return 1;
111 }
112
OSSL_STORE_LOADER_set_eof(OSSL_STORE_LOADER * loader,OSSL_STORE_eof_fn eof_function)113 int OSSL_STORE_LOADER_set_eof(OSSL_STORE_LOADER *loader,
114 OSSL_STORE_eof_fn eof_function)
115 {
116 loader->eof = eof_function;
117 return 1;
118 }
119
OSSL_STORE_LOADER_set_error(OSSL_STORE_LOADER * loader,OSSL_STORE_error_fn error_function)120 int OSSL_STORE_LOADER_set_error(OSSL_STORE_LOADER *loader,
121 OSSL_STORE_error_fn error_function)
122 {
123 loader->error = error_function;
124 return 1;
125 }
126
OSSL_STORE_LOADER_set_close(OSSL_STORE_LOADER * loader,OSSL_STORE_close_fn close_function)127 int OSSL_STORE_LOADER_set_close(OSSL_STORE_LOADER *loader,
128 OSSL_STORE_close_fn close_function)
129 {
130 loader->closefn = close_function;
131 return 1;
132 }
133
134 /*
135 * Functions for registering OSSL_STORE_LOADERs
136 */
137
store_loader_hash(const OSSL_STORE_LOADER * v)138 static unsigned long store_loader_hash(const OSSL_STORE_LOADER *v)
139 {
140 return OPENSSL_LH_strhash(v->scheme);
141 }
142
store_loader_cmp(const OSSL_STORE_LOADER * a,const OSSL_STORE_LOADER * b)143 static int store_loader_cmp(const OSSL_STORE_LOADER *a,
144 const OSSL_STORE_LOADER *b)
145 {
146 assert(a->scheme != NULL && b->scheme != NULL);
147 return strcmp(a->scheme, b->scheme);
148 }
149
150 static LHASH_OF(OSSL_STORE_LOADER) *loader_register = NULL;
ossl_store_register_init(void)151 static int ossl_store_register_init(void)
152 {
153 if (loader_register == NULL) {
154 loader_register = lh_OSSL_STORE_LOADER_new(store_loader_hash,
155 store_loader_cmp);
156 }
157 return loader_register != NULL;
158 }
159
ossl_store_register_loader_int(OSSL_STORE_LOADER * loader)160 int ossl_store_register_loader_int(OSSL_STORE_LOADER *loader)
161 {
162 const char *scheme = loader->scheme;
163 int ok = 0;
164
165 /*
166 * Check that the given scheme conforms to correct scheme syntax as per
167 * RFC 3986:
168 *
169 * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
170 */
171 if (ossl_isalpha(*scheme))
172 while (*scheme != '\0'
173 && (ossl_isalpha(*scheme)
174 || ossl_isdigit(*scheme)
175 || strchr("+-.", *scheme) != NULL))
176 scheme++;
177 if (*scheme != '\0') {
178 ERR_raise_data(ERR_LIB_OSSL_STORE, OSSL_STORE_R_INVALID_SCHEME,
179 "scheme=%s", loader->scheme);
180 return 0;
181 }
182
183 /* Check that functions we absolutely require are present */
184 if (loader->open == NULL || loader->load == NULL || loader->eof == NULL
185 || loader->error == NULL || loader->closefn == NULL) {
186 ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADER_INCOMPLETE);
187 return 0;
188 }
189
190 if (!RUN_ONCE(®istry_init, do_registry_init)) {
191 /* Should this error be raised in do_registry_init()? */
192 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_CRYPTO_LIB);
193 return 0;
194 }
195 if (!CRYPTO_THREAD_write_lock(registry_lock))
196 return 0;
197
198 if (ossl_store_register_init()
199 && (lh_OSSL_STORE_LOADER_insert(loader_register, loader) != NULL
200 || lh_OSSL_STORE_LOADER_error(loader_register) == 0))
201 ok = 1;
202
203 CRYPTO_THREAD_unlock(registry_lock);
204
205 return ok;
206 }
OSSL_STORE_register_loader(OSSL_STORE_LOADER * loader)207 int OSSL_STORE_register_loader(OSSL_STORE_LOADER *loader)
208 {
209 return ossl_store_register_loader_int(loader);
210 }
211
ossl_store_get0_loader_int(const char * scheme)212 const OSSL_STORE_LOADER *ossl_store_get0_loader_int(const char *scheme)
213 {
214 OSSL_STORE_LOADER template;
215 OSSL_STORE_LOADER *loader = NULL;
216
217 template.scheme = scheme;
218 template.open = NULL;
219 template.load = NULL;
220 template.eof = NULL;
221 template.closefn = NULL;
222 template.open_ex = NULL;
223
224 if (!RUN_ONCE(®istry_init, do_registry_init)) {
225 /* Should this error be raised in do_registry_init()? */
226 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_CRYPTO_LIB);
227 return NULL;
228 }
229 if (!CRYPTO_THREAD_write_lock(registry_lock))
230 return NULL;
231
232 if (!ossl_store_register_init())
233 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_INTERNAL_ERROR);
234 else if ((loader = lh_OSSL_STORE_LOADER_retrieve(loader_register,
235 &template))
236 == 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))
268 == NULL)
269 ERR_raise_data(ERR_LIB_OSSL_STORE, OSSL_STORE_R_UNREGISTERED_SCHEME,
270 "scheme=%s", scheme);
271
272 CRYPTO_THREAD_unlock(registry_lock);
273
274 return loader;
275 }
OSSL_STORE_unregister_loader(const char * scheme)276 OSSL_STORE_LOADER *OSSL_STORE_unregister_loader(const char *scheme)
277 {
278 return ossl_store_unregister_loader_int(scheme);
279 }
280
ossl_store_destroy_loaders_int(void)281 void ossl_store_destroy_loaders_int(void)
282 {
283 lh_OSSL_STORE_LOADER_free(loader_register);
284 loader_register = NULL;
285 CRYPTO_THREAD_lock_free(registry_lock);
286 registry_lock = NULL;
287 }
288
289 /*
290 * Functions to list OSSL_STORE loaders
291 */
292
293 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)294 int OSSL_STORE_do_all_loaders(void (*do_function)(const OSSL_STORE_LOADER
295 *loader,
296 void *do_arg),
297 void *do_arg)
298 {
299 if (ossl_store_register_init())
300 lh_OSSL_STORE_LOADER_doall_void(loader_register, do_function, do_arg);
301 return 1;
302 }
303