1/* 2 * Copyright 2020-2022 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/crypto.h> 11#include "crypto/store.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 18int 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 27void 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 */ 45static 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 61static int up_ref_loader(void *method) 62{ 63 return OSSL_STORE_LOADER_up_ref(method); 64} 65 66static void free_loader(void *method) 67{ 68 OSSL_STORE_LOADER_free(method); 69} 70 71/* Permanent loader method store, constructor and destructor */ 72static void loader_store_free(void *vstore) 73{ 74 ossl_method_store_free(vstore); 75} 76 77static void *loader_store_new(OSSL_LIB_CTX *ctx) 78{ 79 return ossl_method_store_new(ctx); 80} 81 82 83static const OSSL_LIB_CTX_METHOD loader_store_method = { 84 /* We want loader_store to be cleaned up before the provider store */ 85 OSSL_LIB_CTX_METHOD_PRIORITY_2, 86 loader_store_new, 87 loader_store_free, 88}; 89 90/* Data to be passed through ossl_method_construct() */ 91struct loader_data_st { 92 OSSL_LIB_CTX *libctx; 93 int scheme_id; /* For get_loader_from_store() */ 94 const char *scheme; /* For get_loader_from_store() */ 95 const char *propquery; /* For get_loader_from_store() */ 96 97 OSSL_METHOD_STORE *tmp_store; /* For get_tmp_loader_store() */ 98 99 unsigned int flag_construct_error_occurred : 1; 100}; 101 102/* 103 * Generic routines to fetch / create OSSL_STORE methods with 104 * ossl_method_construct() 105 */ 106 107/* Temporary loader method store, constructor and destructor */ 108static void *get_tmp_loader_store(void *data) 109{ 110 struct loader_data_st *methdata = data; 111 112 if (methdata->tmp_store == NULL) 113 methdata->tmp_store = ossl_method_store_new(methdata->libctx); 114 return methdata->tmp_store; 115} 116 117 static void dealloc_tmp_loader_store(void *store) 118{ 119 if (store != NULL) 120 ossl_method_store_free(store); 121} 122 123/* Get the permanent loader store */ 124static OSSL_METHOD_STORE *get_loader_store(OSSL_LIB_CTX *libctx) 125{ 126 return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_STORE_LOADER_STORE_INDEX, 127 &loader_store_method); 128} 129 130static int reserve_loader_store(void *store, void *data) 131{ 132 struct loader_data_st *methdata = data; 133 134 if (store == NULL 135 && (store = get_loader_store(methdata->libctx)) == NULL) 136 return 0; 137 138 return ossl_method_lock_store(store); 139} 140 141static int unreserve_loader_store(void *store, void *data) 142{ 143 struct loader_data_st *methdata = data; 144 145 if (store == NULL 146 && (store = get_loader_store(methdata->libctx)) == NULL) 147 return 0; 148 149 return ossl_method_unlock_store(store); 150} 151 152/* Get loader methods from a store, or put one in */ 153static void *get_loader_from_store(void *store, const OSSL_PROVIDER **prov, 154 void *data) 155{ 156 struct loader_data_st *methdata = data; 157 void *method = NULL; 158 int id; 159 160 if ((id = methdata->scheme_id) == 0) { 161 OSSL_NAMEMAP *namemap = ossl_namemap_stored(methdata->libctx); 162 163 id = ossl_namemap_name2num(namemap, methdata->scheme); 164 } 165 166 if (store == NULL 167 && (store = get_loader_store(methdata->libctx)) == NULL) 168 return NULL; 169 170 if (!ossl_method_store_fetch(store, id, methdata->propquery, prov, &method)) 171 return NULL; 172 return method; 173} 174 175static int put_loader_in_store(void *store, void *method, 176 const OSSL_PROVIDER *prov, 177 const char *scheme, const char *propdef, 178 void *data) 179{ 180 struct loader_data_st *methdata = data; 181 OSSL_NAMEMAP *namemap; 182 int id; 183 184 if ((namemap = ossl_namemap_stored(methdata->libctx)) == NULL 185 || (id = ossl_namemap_name2num(namemap, scheme)) == 0) 186 return 0; 187 188 if (store == NULL && (store = get_loader_store(methdata->libctx)) == NULL) 189 return 0; 190 191 return ossl_method_store_add(store, prov, id, propdef, method, 192 up_ref_loader, free_loader); 193} 194 195static void *loader_from_algorithm(int scheme_id, const OSSL_ALGORITHM *algodef, 196 OSSL_PROVIDER *prov) 197{ 198 OSSL_STORE_LOADER *loader = NULL; 199 const OSSL_DISPATCH *fns = algodef->implementation; 200 201 if ((loader = new_loader(prov)) == NULL) 202 return NULL; 203 loader->scheme_id = scheme_id; 204 loader->propdef = algodef->property_definition; 205 loader->description = algodef->algorithm_description; 206 207 for (; fns->function_id != 0; fns++) { 208 switch (fns->function_id) { 209 case OSSL_FUNC_STORE_OPEN: 210 if (loader->p_open == NULL) 211 loader->p_open = OSSL_FUNC_store_open(fns); 212 break; 213 case OSSL_FUNC_STORE_ATTACH: 214 if (loader->p_attach == NULL) 215 loader->p_attach = OSSL_FUNC_store_attach(fns); 216 break; 217 case OSSL_FUNC_STORE_SETTABLE_CTX_PARAMS: 218 if (loader->p_settable_ctx_params == NULL) 219 loader->p_settable_ctx_params = 220 OSSL_FUNC_store_settable_ctx_params(fns); 221 break; 222 case OSSL_FUNC_STORE_SET_CTX_PARAMS: 223 if (loader->p_set_ctx_params == NULL) 224 loader->p_set_ctx_params = OSSL_FUNC_store_set_ctx_params(fns); 225 break; 226 case OSSL_FUNC_STORE_LOAD: 227 if (loader->p_load == NULL) 228 loader->p_load = OSSL_FUNC_store_load(fns); 229 break; 230 case OSSL_FUNC_STORE_EOF: 231 if (loader->p_eof == NULL) 232 loader->p_eof = OSSL_FUNC_store_eof(fns); 233 break; 234 case OSSL_FUNC_STORE_CLOSE: 235 if (loader->p_close == NULL) 236 loader->p_close = OSSL_FUNC_store_close(fns); 237 break; 238 case OSSL_FUNC_STORE_EXPORT_OBJECT: 239 if (loader->p_export_object == NULL) 240 loader->p_export_object = OSSL_FUNC_store_export_object(fns); 241 break; 242 } 243 } 244 245 if ((loader->p_open == NULL && loader->p_attach == NULL) 246 || loader->p_load == NULL 247 || loader->p_eof == NULL 248 || loader->p_close == NULL) { 249 /* Only set_ctx_params is optionaal */ 250 OSSL_STORE_LOADER_free(loader); 251 ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADER_INCOMPLETE); 252 return NULL; 253 } 254 return loader; 255} 256 257/* 258 * The core fetching functionality passes the scheme of the implementation. 259 * This function is responsible to getting an identity number for them, 260 * then call loader_from_algorithm() with that identity number. 261 */ 262static void *construct_loader(const OSSL_ALGORITHM *algodef, 263 OSSL_PROVIDER *prov, void *data) 264{ 265 /* 266 * This function is only called if get_loader_from_store() returned 267 * NULL, so it's safe to say that of all the spots to create a new 268 * namemap entry, this is it. Should the scheme already exist there, we 269 * know that ossl_namemap_add() will return its corresponding number. 270 */ 271 struct loader_data_st *methdata = data; 272 OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov); 273 OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); 274 const char *scheme = algodef->algorithm_names; 275 int id = ossl_namemap_add_name(namemap, 0, scheme); 276 void *method = NULL; 277 278 if (id != 0) 279 method = loader_from_algorithm(id, algodef, prov); 280 281 /* 282 * Flag to indicate that there was actual construction errors. This 283 * helps inner_loader_fetch() determine what error it should 284 * record on inaccessible algorithms. 285 */ 286 if (method == NULL) 287 methdata->flag_construct_error_occurred = 1; 288 289 return method; 290} 291 292/* Intermediary function to avoid ugly casts, used below */ 293static void destruct_loader(void *method, void *data) 294{ 295 OSSL_STORE_LOADER_free(method); 296} 297 298/* Fetching support. Can fetch by numeric identity or by scheme */ 299static OSSL_STORE_LOADER * 300inner_loader_fetch(struct loader_data_st *methdata, int id, 301 const char *scheme, const char *properties) 302{ 303 OSSL_METHOD_STORE *store = get_loader_store(methdata->libctx); 304 OSSL_NAMEMAP *namemap = ossl_namemap_stored(methdata->libctx); 305 const char *const propq = properties != NULL ? properties : ""; 306 void *method = NULL; 307 int unsupported = 0; 308 309 if (store == NULL || namemap == NULL) { 310 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_INVALID_ARGUMENT); 311 return NULL; 312 } 313 314 /* 315 * If we have been passed both an id and a scheme, we have an 316 * internal programming error. 317 */ 318 if (!ossl_assert(id == 0 || scheme == NULL)) { 319 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_INTERNAL_ERROR); 320 return NULL; 321 } 322 323 /* If we haven't received a name id yet, try to get one for the name */ 324 if (id == 0 && scheme != NULL) 325 id = ossl_namemap_name2num(namemap, scheme); 326 327 /* 328 * If we haven't found the name yet, chances are that the algorithm to 329 * be fetched is unsupported. 330 */ 331 if (id == 0) 332 unsupported = 1; 333 334 if (id == 0 335 || !ossl_method_store_cache_get(store, NULL, id, propq, &method)) { 336 OSSL_METHOD_CONSTRUCT_METHOD mcm = { 337 get_tmp_loader_store, 338 reserve_loader_store, 339 unreserve_loader_store, 340 get_loader_from_store, 341 put_loader_in_store, 342 construct_loader, 343 destruct_loader 344 }; 345 OSSL_PROVIDER *prov = NULL; 346 347 methdata->scheme_id = id; 348 methdata->scheme = scheme; 349 methdata->propquery = propq; 350 methdata->flag_construct_error_occurred = 0; 351 if ((method = ossl_method_construct(methdata->libctx, OSSL_OP_STORE, 352 &prov, 0 /* !force_cache */, 353 &mcm, methdata)) != NULL) { 354 /* 355 * If construction did create a method for us, we know that there 356 * is a correct scheme_id, since those have already been calculated 357 * in get_loader_from_store() and put_loader_in_store() above. 358 */ 359 if (id == 0) 360 id = ossl_namemap_name2num(namemap, scheme); 361 ossl_method_store_cache_set(store, prov, id, propq, method, 362 up_ref_loader, free_loader); 363 } 364 365 /* 366 * If we never were in the constructor, the algorithm to be fetched 367 * is unsupported. 368 */ 369 unsupported = !methdata->flag_construct_error_occurred; 370 } 371 372 if ((id != 0 || scheme != NULL) && method == NULL) { 373 int code = unsupported ? ERR_R_UNSUPPORTED : ERR_R_FETCH_FAILED; 374 const char *helpful_msg = 375 unsupported 376 ? ( "No store loader found. For standard store loaders you need " 377 "at least one of the default or base providers available. " 378 "Did you forget to load them? Info: " ) 379 : ""; 380 381 if (scheme == NULL) 382 scheme = ossl_namemap_num2name(namemap, id, 0); 383 ERR_raise_data(ERR_LIB_OSSL_STORE, code, 384 "%s%s, Scheme (%s : %d), Properties (%s)", 385 helpful_msg, 386 ossl_lib_ctx_get_descriptor(methdata->libctx), 387 scheme == NULL ? "<null>" : scheme, id, 388 properties == NULL ? "<null>" : properties); 389 } 390 391 return method; 392} 393 394OSSL_STORE_LOADER *OSSL_STORE_LOADER_fetch(OSSL_LIB_CTX *libctx, 395 const char *scheme, 396 const char *properties) 397{ 398 struct loader_data_st methdata; 399 void *method; 400 401 methdata.libctx = libctx; 402 methdata.tmp_store = NULL; 403 method = inner_loader_fetch(&methdata, 0, scheme, properties); 404 dealloc_tmp_loader_store(methdata.tmp_store); 405 return method; 406} 407 408OSSL_STORE_LOADER *ossl_store_loader_fetch_by_number(OSSL_LIB_CTX *libctx, 409 int scheme_id, 410 const char *properties) 411{ 412 struct loader_data_st methdata; 413 void *method; 414 415 methdata.libctx = libctx; 416 methdata.tmp_store = NULL; 417 method = inner_loader_fetch(&methdata, scheme_id, NULL, properties); 418 dealloc_tmp_loader_store(methdata.tmp_store); 419 return method; 420} 421 422int ossl_store_loader_store_cache_flush(OSSL_LIB_CTX *libctx) 423{ 424 OSSL_METHOD_STORE *store = get_loader_store(libctx); 425 426 if (store != NULL) 427 return ossl_method_store_cache_flush_all(store); 428 return 1; 429} 430 431int ossl_store_loader_store_remove_all_provided(const OSSL_PROVIDER *prov) 432{ 433 OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov); 434 OSSL_METHOD_STORE *store = get_loader_store(libctx); 435 436 if (store != NULL) 437 return ossl_method_store_remove_all_provided(store, prov); 438 return 1; 439} 440 441/* 442 * Library of basic method functions 443 */ 444 445const OSSL_PROVIDER *OSSL_STORE_LOADER_get0_provider(const OSSL_STORE_LOADER *loader) 446{ 447 if (!ossl_assert(loader != NULL)) { 448 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER); 449 return 0; 450 } 451 452 return loader->prov; 453} 454 455const char *OSSL_STORE_LOADER_get0_properties(const OSSL_STORE_LOADER *loader) 456{ 457 if (!ossl_assert(loader != NULL)) { 458 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER); 459 return 0; 460 } 461 462 return loader->propdef; 463} 464 465int ossl_store_loader_get_number(const OSSL_STORE_LOADER *loader) 466{ 467 if (!ossl_assert(loader != NULL)) { 468 ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER); 469 return 0; 470 } 471 472 return loader->scheme_id; 473} 474 475const char *OSSL_STORE_LOADER_get0_description(const OSSL_STORE_LOADER *loader) 476{ 477 return loader->description; 478} 479 480int OSSL_STORE_LOADER_is_a(const OSSL_STORE_LOADER *loader, const char *name) 481{ 482 if (loader->prov != NULL) { 483 OSSL_LIB_CTX *libctx = ossl_provider_libctx(loader->prov); 484 OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); 485 486 return ossl_namemap_name2num(namemap, name) == loader->scheme_id; 487 } 488 return 0; 489} 490 491struct do_one_data_st { 492 void (*user_fn)(OSSL_STORE_LOADER *loader, void *arg); 493 void *user_arg; 494}; 495 496static void do_one(ossl_unused int id, void *method, void *arg) 497{ 498 struct do_one_data_st *data = arg; 499 500 data->user_fn(method, data->user_arg); 501} 502 503void OSSL_STORE_LOADER_do_all_provided(OSSL_LIB_CTX *libctx, 504 void (*user_fn)(OSSL_STORE_LOADER *loader, 505 void *arg), 506 void *user_arg) 507{ 508 struct loader_data_st methdata; 509 struct do_one_data_st data; 510 511 methdata.libctx = libctx; 512 methdata.tmp_store = NULL; 513 (void)inner_loader_fetch(&methdata, 0, NULL, NULL /* properties */); 514 515 data.user_fn = user_fn; 516 data.user_arg = user_arg; 517 if (methdata.tmp_store != NULL) 518 ossl_method_store_do_all(methdata.tmp_store, &do_one, &data); 519 ossl_method_store_do_all(get_loader_store(libctx), &do_one, &data); 520 dealloc_tmp_loader_store(methdata.tmp_store); 521} 522 523int OSSL_STORE_LOADER_names_do_all(const OSSL_STORE_LOADER *loader, 524 void (*fn)(const char *name, void *data), 525 void *data) 526{ 527 if (loader == NULL) 528 return 0; 529 530 if (loader->prov != NULL) { 531 OSSL_LIB_CTX *libctx = ossl_provider_libctx(loader->prov); 532 OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); 533 534 return ossl_namemap_doall_names(namemap, loader->scheme_id, fn, data); 535 } 536 537 return 1; 538} 539