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