1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 4e1051a39Sopenharmony_ci * 5e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 6e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 7e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 8e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 9e1051a39Sopenharmony_ci */ 10e1051a39Sopenharmony_ci 11e1051a39Sopenharmony_ci#include <string.h> 12e1051a39Sopenharmony_ci#include <stdio.h> 13e1051a39Sopenharmony_ci#include <stdarg.h> 14e1051a39Sopenharmony_ci#include <openssl/crypto.h> 15e1051a39Sopenharmony_ci#include "internal/core.h" 16e1051a39Sopenharmony_ci#include "internal/property.h" 17e1051a39Sopenharmony_ci#include "internal/provider.h" 18e1051a39Sopenharmony_ci#include "internal/tsan_assist.h" 19e1051a39Sopenharmony_ci#include "crypto/ctype.h" 20e1051a39Sopenharmony_ci#include <openssl/lhash.h> 21e1051a39Sopenharmony_ci#include <openssl/rand.h> 22e1051a39Sopenharmony_ci#include "internal/thread_once.h" 23e1051a39Sopenharmony_ci#include "crypto/lhash.h" 24e1051a39Sopenharmony_ci#include "crypto/sparse_array.h" 25e1051a39Sopenharmony_ci#include "property_local.h" 26e1051a39Sopenharmony_ci 27e1051a39Sopenharmony_ci/* 28e1051a39Sopenharmony_ci * The number of elements in the query cache before we initiate a flush. 29e1051a39Sopenharmony_ci * If reducing this, also ensure the stochastic test in test/property_test.c 30e1051a39Sopenharmony_ci * isn't likely to fail. 31e1051a39Sopenharmony_ci */ 32e1051a39Sopenharmony_ci#define IMPL_CACHE_FLUSH_THRESHOLD 500 33e1051a39Sopenharmony_ci 34e1051a39Sopenharmony_citypedef struct { 35e1051a39Sopenharmony_ci void *method; 36e1051a39Sopenharmony_ci int (*up_ref)(void *); 37e1051a39Sopenharmony_ci void (*free)(void *); 38e1051a39Sopenharmony_ci} METHOD; 39e1051a39Sopenharmony_ci 40e1051a39Sopenharmony_citypedef struct { 41e1051a39Sopenharmony_ci const OSSL_PROVIDER *provider; 42e1051a39Sopenharmony_ci OSSL_PROPERTY_LIST *properties; 43e1051a39Sopenharmony_ci METHOD method; 44e1051a39Sopenharmony_ci} IMPLEMENTATION; 45e1051a39Sopenharmony_ci 46e1051a39Sopenharmony_ciDEFINE_STACK_OF(IMPLEMENTATION) 47e1051a39Sopenharmony_ci 48e1051a39Sopenharmony_citypedef struct { 49e1051a39Sopenharmony_ci const OSSL_PROVIDER *provider; 50e1051a39Sopenharmony_ci const char *query; 51e1051a39Sopenharmony_ci METHOD method; 52e1051a39Sopenharmony_ci char body[1]; 53e1051a39Sopenharmony_ci} QUERY; 54e1051a39Sopenharmony_ci 55e1051a39Sopenharmony_ciDEFINE_LHASH_OF(QUERY); 56e1051a39Sopenharmony_ci 57e1051a39Sopenharmony_citypedef struct { 58e1051a39Sopenharmony_ci int nid; 59e1051a39Sopenharmony_ci STACK_OF(IMPLEMENTATION) *impls; 60e1051a39Sopenharmony_ci LHASH_OF(QUERY) *cache; 61e1051a39Sopenharmony_ci} ALGORITHM; 62e1051a39Sopenharmony_ci 63e1051a39Sopenharmony_cistruct ossl_method_store_st { 64e1051a39Sopenharmony_ci OSSL_LIB_CTX *ctx; 65e1051a39Sopenharmony_ci SPARSE_ARRAY_OF(ALGORITHM) *algs; 66e1051a39Sopenharmony_ci /* 67e1051a39Sopenharmony_ci * Lock to protect the |algs| array from concurrent writing, when 68e1051a39Sopenharmony_ci * individual implementations or queries are inserted. This is used 69e1051a39Sopenharmony_ci * by the appropriate functions here. 70e1051a39Sopenharmony_ci */ 71e1051a39Sopenharmony_ci CRYPTO_RWLOCK *lock; 72e1051a39Sopenharmony_ci /* 73e1051a39Sopenharmony_ci * Lock to reserve the whole store. This is used when fetching a set 74e1051a39Sopenharmony_ci * of algorithms, via these functions, found in crypto/core_fetch.c: 75e1051a39Sopenharmony_ci * ossl_method_construct_reserve_store() 76e1051a39Sopenharmony_ci * ossl_method_construct_unreserve_store() 77e1051a39Sopenharmony_ci */ 78e1051a39Sopenharmony_ci CRYPTO_RWLOCK *biglock; 79e1051a39Sopenharmony_ci 80e1051a39Sopenharmony_ci /* query cache specific values */ 81e1051a39Sopenharmony_ci 82e1051a39Sopenharmony_ci /* Count of the query cache entries for all algs */ 83e1051a39Sopenharmony_ci size_t cache_nelem; 84e1051a39Sopenharmony_ci 85e1051a39Sopenharmony_ci /* Flag: 1 if query cache entries for all algs need flushing */ 86e1051a39Sopenharmony_ci int cache_need_flush; 87e1051a39Sopenharmony_ci}; 88e1051a39Sopenharmony_ci 89e1051a39Sopenharmony_citypedef struct { 90e1051a39Sopenharmony_ci LHASH_OF(QUERY) *cache; 91e1051a39Sopenharmony_ci size_t nelem; 92e1051a39Sopenharmony_ci uint32_t seed; 93e1051a39Sopenharmony_ci unsigned char using_global_seed; 94e1051a39Sopenharmony_ci} IMPL_CACHE_FLUSH; 95e1051a39Sopenharmony_ci 96e1051a39Sopenharmony_ciDEFINE_SPARSE_ARRAY_OF(ALGORITHM); 97e1051a39Sopenharmony_ci 98e1051a39Sopenharmony_ciDEFINE_STACK_OF(ALGORITHM) 99e1051a39Sopenharmony_ci 100e1051a39Sopenharmony_citypedef struct ossl_global_properties_st { 101e1051a39Sopenharmony_ci OSSL_PROPERTY_LIST *list; 102e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 103e1051a39Sopenharmony_ci unsigned int no_mirrored : 1; 104e1051a39Sopenharmony_ci#endif 105e1051a39Sopenharmony_ci} OSSL_GLOBAL_PROPERTIES; 106e1051a39Sopenharmony_ci 107e1051a39Sopenharmony_cistatic void ossl_method_cache_flush_alg(OSSL_METHOD_STORE *store, 108e1051a39Sopenharmony_ci ALGORITHM *alg); 109e1051a39Sopenharmony_cistatic void ossl_method_cache_flush(OSSL_METHOD_STORE *store, int nid); 110e1051a39Sopenharmony_ci 111e1051a39Sopenharmony_ci/* Global properties are stored per library context */ 112e1051a39Sopenharmony_cistatic void ossl_ctx_global_properties_free(void *vglobp) 113e1051a39Sopenharmony_ci{ 114e1051a39Sopenharmony_ci OSSL_GLOBAL_PROPERTIES *globp = vglobp; 115e1051a39Sopenharmony_ci 116e1051a39Sopenharmony_ci if (globp != NULL) { 117e1051a39Sopenharmony_ci ossl_property_free(globp->list); 118e1051a39Sopenharmony_ci OPENSSL_free(globp); 119e1051a39Sopenharmony_ci } 120e1051a39Sopenharmony_ci} 121e1051a39Sopenharmony_ci 122e1051a39Sopenharmony_cistatic void *ossl_ctx_global_properties_new(OSSL_LIB_CTX *ctx) 123e1051a39Sopenharmony_ci{ 124e1051a39Sopenharmony_ci return OPENSSL_zalloc(sizeof(OSSL_GLOBAL_PROPERTIES)); 125e1051a39Sopenharmony_ci} 126e1051a39Sopenharmony_ci 127e1051a39Sopenharmony_cistatic const OSSL_LIB_CTX_METHOD ossl_ctx_global_properties_method = { 128e1051a39Sopenharmony_ci OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY, 129e1051a39Sopenharmony_ci ossl_ctx_global_properties_new, 130e1051a39Sopenharmony_ci ossl_ctx_global_properties_free, 131e1051a39Sopenharmony_ci}; 132e1051a39Sopenharmony_ci 133e1051a39Sopenharmony_ciOSSL_PROPERTY_LIST **ossl_ctx_global_properties(OSSL_LIB_CTX *libctx, 134e1051a39Sopenharmony_ci int loadconfig) 135e1051a39Sopenharmony_ci{ 136e1051a39Sopenharmony_ci OSSL_GLOBAL_PROPERTIES *globp; 137e1051a39Sopenharmony_ci 138e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 139e1051a39Sopenharmony_ci if (loadconfig && !OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL)) 140e1051a39Sopenharmony_ci return NULL; 141e1051a39Sopenharmony_ci#endif 142e1051a39Sopenharmony_ci globp = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES, 143e1051a39Sopenharmony_ci &ossl_ctx_global_properties_method); 144e1051a39Sopenharmony_ci 145e1051a39Sopenharmony_ci return globp != NULL ? &globp->list : NULL; 146e1051a39Sopenharmony_ci} 147e1051a39Sopenharmony_ci 148e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 149e1051a39Sopenharmony_ciint ossl_global_properties_no_mirrored(OSSL_LIB_CTX *libctx) 150e1051a39Sopenharmony_ci{ 151e1051a39Sopenharmony_ci OSSL_GLOBAL_PROPERTIES *globp 152e1051a39Sopenharmony_ci = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES, 153e1051a39Sopenharmony_ci &ossl_ctx_global_properties_method); 154e1051a39Sopenharmony_ci 155e1051a39Sopenharmony_ci return globp != NULL && globp->no_mirrored ? 1 : 0; 156e1051a39Sopenharmony_ci} 157e1051a39Sopenharmony_ci 158e1051a39Sopenharmony_civoid ossl_global_properties_stop_mirroring(OSSL_LIB_CTX *libctx) 159e1051a39Sopenharmony_ci{ 160e1051a39Sopenharmony_ci OSSL_GLOBAL_PROPERTIES *globp 161e1051a39Sopenharmony_ci = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES, 162e1051a39Sopenharmony_ci &ossl_ctx_global_properties_method); 163e1051a39Sopenharmony_ci 164e1051a39Sopenharmony_ci if (globp != NULL) 165e1051a39Sopenharmony_ci globp->no_mirrored = 1; 166e1051a39Sopenharmony_ci} 167e1051a39Sopenharmony_ci#endif 168e1051a39Sopenharmony_ci 169e1051a39Sopenharmony_cistatic int ossl_method_up_ref(METHOD *method) 170e1051a39Sopenharmony_ci{ 171e1051a39Sopenharmony_ci return (*method->up_ref)(method->method); 172e1051a39Sopenharmony_ci} 173e1051a39Sopenharmony_ci 174e1051a39Sopenharmony_cistatic void ossl_method_free(METHOD *method) 175e1051a39Sopenharmony_ci{ 176e1051a39Sopenharmony_ci (*method->free)(method->method); 177e1051a39Sopenharmony_ci} 178e1051a39Sopenharmony_ci 179e1051a39Sopenharmony_cistatic __owur int ossl_property_read_lock(OSSL_METHOD_STORE *p) 180e1051a39Sopenharmony_ci{ 181e1051a39Sopenharmony_ci return p != NULL ? CRYPTO_THREAD_read_lock(p->lock) : 0; 182e1051a39Sopenharmony_ci} 183e1051a39Sopenharmony_ci 184e1051a39Sopenharmony_cistatic __owur int ossl_property_write_lock(OSSL_METHOD_STORE *p) 185e1051a39Sopenharmony_ci{ 186e1051a39Sopenharmony_ci return p != NULL ? CRYPTO_THREAD_write_lock(p->lock) : 0; 187e1051a39Sopenharmony_ci} 188e1051a39Sopenharmony_ci 189e1051a39Sopenharmony_cistatic int ossl_property_unlock(OSSL_METHOD_STORE *p) 190e1051a39Sopenharmony_ci{ 191e1051a39Sopenharmony_ci return p != 0 ? CRYPTO_THREAD_unlock(p->lock) : 0; 192e1051a39Sopenharmony_ci} 193e1051a39Sopenharmony_ci 194e1051a39Sopenharmony_cistatic unsigned long query_hash(const QUERY *a) 195e1051a39Sopenharmony_ci{ 196e1051a39Sopenharmony_ci return OPENSSL_LH_strhash(a->query); 197e1051a39Sopenharmony_ci} 198e1051a39Sopenharmony_ci 199e1051a39Sopenharmony_cistatic int query_cmp(const QUERY *a, const QUERY *b) 200e1051a39Sopenharmony_ci{ 201e1051a39Sopenharmony_ci int res = strcmp(a->query, b->query); 202e1051a39Sopenharmony_ci 203e1051a39Sopenharmony_ci if (res == 0 && a->provider != NULL && b->provider != NULL) 204e1051a39Sopenharmony_ci res = b->provider > a->provider ? 1 205e1051a39Sopenharmony_ci : b->provider < a->provider ? -1 206e1051a39Sopenharmony_ci : 0; 207e1051a39Sopenharmony_ci return res; 208e1051a39Sopenharmony_ci} 209e1051a39Sopenharmony_ci 210e1051a39Sopenharmony_cistatic void impl_free(IMPLEMENTATION *impl) 211e1051a39Sopenharmony_ci{ 212e1051a39Sopenharmony_ci if (impl != NULL) { 213e1051a39Sopenharmony_ci ossl_method_free(&impl->method); 214e1051a39Sopenharmony_ci OPENSSL_free(impl); 215e1051a39Sopenharmony_ci } 216e1051a39Sopenharmony_ci} 217e1051a39Sopenharmony_ci 218e1051a39Sopenharmony_cistatic void impl_cache_free(QUERY *elem) 219e1051a39Sopenharmony_ci{ 220e1051a39Sopenharmony_ci if (elem != NULL) { 221e1051a39Sopenharmony_ci ossl_method_free(&elem->method); 222e1051a39Sopenharmony_ci OPENSSL_free(elem); 223e1051a39Sopenharmony_ci } 224e1051a39Sopenharmony_ci} 225e1051a39Sopenharmony_ci 226e1051a39Sopenharmony_cistatic void impl_cache_flush_alg(ossl_uintmax_t idx, ALGORITHM *alg) 227e1051a39Sopenharmony_ci{ 228e1051a39Sopenharmony_ci lh_QUERY_doall(alg->cache, &impl_cache_free); 229e1051a39Sopenharmony_ci lh_QUERY_flush(alg->cache); 230e1051a39Sopenharmony_ci} 231e1051a39Sopenharmony_ci 232e1051a39Sopenharmony_cistatic void alg_cleanup(ossl_uintmax_t idx, ALGORITHM *a, void *arg) 233e1051a39Sopenharmony_ci{ 234e1051a39Sopenharmony_ci OSSL_METHOD_STORE *store = arg; 235e1051a39Sopenharmony_ci 236e1051a39Sopenharmony_ci if (a != NULL) { 237e1051a39Sopenharmony_ci sk_IMPLEMENTATION_pop_free(a->impls, &impl_free); 238e1051a39Sopenharmony_ci lh_QUERY_doall(a->cache, &impl_cache_free); 239e1051a39Sopenharmony_ci lh_QUERY_free(a->cache); 240e1051a39Sopenharmony_ci OPENSSL_free(a); 241e1051a39Sopenharmony_ci } 242e1051a39Sopenharmony_ci if (store != NULL) 243e1051a39Sopenharmony_ci ossl_sa_ALGORITHM_set(store->algs, idx, NULL); 244e1051a39Sopenharmony_ci} 245e1051a39Sopenharmony_ci 246e1051a39Sopenharmony_ci/* 247e1051a39Sopenharmony_ci * The OSSL_LIB_CTX param here allows access to underlying property data needed 248e1051a39Sopenharmony_ci * for computation 249e1051a39Sopenharmony_ci */ 250e1051a39Sopenharmony_ciOSSL_METHOD_STORE *ossl_method_store_new(OSSL_LIB_CTX *ctx) 251e1051a39Sopenharmony_ci{ 252e1051a39Sopenharmony_ci OSSL_METHOD_STORE *res; 253e1051a39Sopenharmony_ci 254e1051a39Sopenharmony_ci res = OPENSSL_zalloc(sizeof(*res)); 255e1051a39Sopenharmony_ci if (res != NULL) { 256e1051a39Sopenharmony_ci res->ctx = ctx; 257e1051a39Sopenharmony_ci if ((res->algs = ossl_sa_ALGORITHM_new()) == NULL 258e1051a39Sopenharmony_ci || (res->lock = CRYPTO_THREAD_lock_new()) == NULL 259e1051a39Sopenharmony_ci || (res->biglock = CRYPTO_THREAD_lock_new()) == NULL) { 260e1051a39Sopenharmony_ci ossl_method_store_free(res); 261e1051a39Sopenharmony_ci return NULL; 262e1051a39Sopenharmony_ci } 263e1051a39Sopenharmony_ci } 264e1051a39Sopenharmony_ci return res; 265e1051a39Sopenharmony_ci} 266e1051a39Sopenharmony_ci 267e1051a39Sopenharmony_civoid ossl_method_store_free(OSSL_METHOD_STORE *store) 268e1051a39Sopenharmony_ci{ 269e1051a39Sopenharmony_ci if (store != NULL) { 270e1051a39Sopenharmony_ci if (store->algs != NULL) 271e1051a39Sopenharmony_ci ossl_sa_ALGORITHM_doall_arg(store->algs, &alg_cleanup, store); 272e1051a39Sopenharmony_ci ossl_sa_ALGORITHM_free(store->algs); 273e1051a39Sopenharmony_ci CRYPTO_THREAD_lock_free(store->lock); 274e1051a39Sopenharmony_ci CRYPTO_THREAD_lock_free(store->biglock); 275e1051a39Sopenharmony_ci OPENSSL_free(store); 276e1051a39Sopenharmony_ci } 277e1051a39Sopenharmony_ci} 278e1051a39Sopenharmony_ci 279e1051a39Sopenharmony_ciint ossl_method_lock_store(OSSL_METHOD_STORE *store) 280e1051a39Sopenharmony_ci{ 281e1051a39Sopenharmony_ci return store != NULL ? CRYPTO_THREAD_write_lock(store->biglock) : 0; 282e1051a39Sopenharmony_ci} 283e1051a39Sopenharmony_ci 284e1051a39Sopenharmony_ciint ossl_method_unlock_store(OSSL_METHOD_STORE *store) 285e1051a39Sopenharmony_ci{ 286e1051a39Sopenharmony_ci return store != NULL ? CRYPTO_THREAD_unlock(store->biglock) : 0; 287e1051a39Sopenharmony_ci} 288e1051a39Sopenharmony_ci 289e1051a39Sopenharmony_cistatic ALGORITHM *ossl_method_store_retrieve(OSSL_METHOD_STORE *store, int nid) 290e1051a39Sopenharmony_ci{ 291e1051a39Sopenharmony_ci return ossl_sa_ALGORITHM_get(store->algs, nid); 292e1051a39Sopenharmony_ci} 293e1051a39Sopenharmony_ci 294e1051a39Sopenharmony_cistatic int ossl_method_store_insert(OSSL_METHOD_STORE *store, ALGORITHM *alg) 295e1051a39Sopenharmony_ci{ 296e1051a39Sopenharmony_ci return ossl_sa_ALGORITHM_set(store->algs, alg->nid, alg); 297e1051a39Sopenharmony_ci} 298e1051a39Sopenharmony_ci 299e1051a39Sopenharmony_ciint ossl_method_store_add(OSSL_METHOD_STORE *store, const OSSL_PROVIDER *prov, 300e1051a39Sopenharmony_ci int nid, const char *properties, void *method, 301e1051a39Sopenharmony_ci int (*method_up_ref)(void *), 302e1051a39Sopenharmony_ci void (*method_destruct)(void *)) 303e1051a39Sopenharmony_ci{ 304e1051a39Sopenharmony_ci ALGORITHM *alg = NULL; 305e1051a39Sopenharmony_ci IMPLEMENTATION *impl; 306e1051a39Sopenharmony_ci int ret = 0; 307e1051a39Sopenharmony_ci int i; 308e1051a39Sopenharmony_ci 309e1051a39Sopenharmony_ci if (nid <= 0 || method == NULL || store == NULL) 310e1051a39Sopenharmony_ci return 0; 311e1051a39Sopenharmony_ci if (properties == NULL) 312e1051a39Sopenharmony_ci properties = ""; 313e1051a39Sopenharmony_ci 314e1051a39Sopenharmony_ci if (!ossl_assert(prov != NULL)) 315e1051a39Sopenharmony_ci return 0; 316e1051a39Sopenharmony_ci 317e1051a39Sopenharmony_ci /* Create new entry */ 318e1051a39Sopenharmony_ci impl = OPENSSL_malloc(sizeof(*impl)); 319e1051a39Sopenharmony_ci if (impl == NULL) 320e1051a39Sopenharmony_ci return 0; 321e1051a39Sopenharmony_ci impl->method.method = method; 322e1051a39Sopenharmony_ci impl->method.up_ref = method_up_ref; 323e1051a39Sopenharmony_ci impl->method.free = method_destruct; 324e1051a39Sopenharmony_ci if (!ossl_method_up_ref(&impl->method)) { 325e1051a39Sopenharmony_ci OPENSSL_free(impl); 326e1051a39Sopenharmony_ci return 0; 327e1051a39Sopenharmony_ci } 328e1051a39Sopenharmony_ci impl->provider = prov; 329e1051a39Sopenharmony_ci 330e1051a39Sopenharmony_ci /* Insert into the hash table if required */ 331e1051a39Sopenharmony_ci if (!ossl_property_write_lock(store)) { 332e1051a39Sopenharmony_ci OPENSSL_free(impl); 333e1051a39Sopenharmony_ci return 0; 334e1051a39Sopenharmony_ci } 335e1051a39Sopenharmony_ci ossl_method_cache_flush(store, nid); 336e1051a39Sopenharmony_ci if ((impl->properties = ossl_prop_defn_get(store->ctx, properties)) == NULL) { 337e1051a39Sopenharmony_ci impl->properties = ossl_parse_property(store->ctx, properties); 338e1051a39Sopenharmony_ci if (impl->properties == NULL) 339e1051a39Sopenharmony_ci goto err; 340e1051a39Sopenharmony_ci if (!ossl_prop_defn_set(store->ctx, properties, &impl->properties)) { 341e1051a39Sopenharmony_ci ossl_property_free(impl->properties); 342e1051a39Sopenharmony_ci impl->properties = NULL; 343e1051a39Sopenharmony_ci goto err; 344e1051a39Sopenharmony_ci } 345e1051a39Sopenharmony_ci } 346e1051a39Sopenharmony_ci 347e1051a39Sopenharmony_ci alg = ossl_method_store_retrieve(store, nid); 348e1051a39Sopenharmony_ci if (alg == NULL) { 349e1051a39Sopenharmony_ci if ((alg = OPENSSL_zalloc(sizeof(*alg))) == NULL 350e1051a39Sopenharmony_ci || (alg->impls = sk_IMPLEMENTATION_new_null()) == NULL 351e1051a39Sopenharmony_ci || (alg->cache = lh_QUERY_new(&query_hash, &query_cmp)) == NULL) 352e1051a39Sopenharmony_ci goto err; 353e1051a39Sopenharmony_ci alg->nid = nid; 354e1051a39Sopenharmony_ci if (!ossl_method_store_insert(store, alg)) 355e1051a39Sopenharmony_ci goto err; 356e1051a39Sopenharmony_ci } 357e1051a39Sopenharmony_ci 358e1051a39Sopenharmony_ci /* Push onto stack if there isn't one there already */ 359e1051a39Sopenharmony_ci for (i = 0; i < sk_IMPLEMENTATION_num(alg->impls); i++) { 360e1051a39Sopenharmony_ci const IMPLEMENTATION *tmpimpl = sk_IMPLEMENTATION_value(alg->impls, i); 361e1051a39Sopenharmony_ci 362e1051a39Sopenharmony_ci if (tmpimpl->provider == impl->provider 363e1051a39Sopenharmony_ci && tmpimpl->properties == impl->properties) 364e1051a39Sopenharmony_ci break; 365e1051a39Sopenharmony_ci } 366e1051a39Sopenharmony_ci if (i == sk_IMPLEMENTATION_num(alg->impls) 367e1051a39Sopenharmony_ci && sk_IMPLEMENTATION_push(alg->impls, impl)) 368e1051a39Sopenharmony_ci ret = 1; 369e1051a39Sopenharmony_ci ossl_property_unlock(store); 370e1051a39Sopenharmony_ci if (ret == 0) 371e1051a39Sopenharmony_ci impl_free(impl); 372e1051a39Sopenharmony_ci return ret; 373e1051a39Sopenharmony_ci 374e1051a39Sopenharmony_cierr: 375e1051a39Sopenharmony_ci ossl_property_unlock(store); 376e1051a39Sopenharmony_ci alg_cleanup(0, alg, NULL); 377e1051a39Sopenharmony_ci impl_free(impl); 378e1051a39Sopenharmony_ci return 0; 379e1051a39Sopenharmony_ci} 380e1051a39Sopenharmony_ci 381e1051a39Sopenharmony_ciint ossl_method_store_remove(OSSL_METHOD_STORE *store, int nid, 382e1051a39Sopenharmony_ci const void *method) 383e1051a39Sopenharmony_ci{ 384e1051a39Sopenharmony_ci ALGORITHM *alg = NULL; 385e1051a39Sopenharmony_ci int i; 386e1051a39Sopenharmony_ci 387e1051a39Sopenharmony_ci if (nid <= 0 || method == NULL || store == NULL) 388e1051a39Sopenharmony_ci return 0; 389e1051a39Sopenharmony_ci 390e1051a39Sopenharmony_ci if (!ossl_property_write_lock(store)) 391e1051a39Sopenharmony_ci return 0; 392e1051a39Sopenharmony_ci ossl_method_cache_flush(store, nid); 393e1051a39Sopenharmony_ci alg = ossl_method_store_retrieve(store, nid); 394e1051a39Sopenharmony_ci if (alg == NULL) { 395e1051a39Sopenharmony_ci ossl_property_unlock(store); 396e1051a39Sopenharmony_ci return 0; 397e1051a39Sopenharmony_ci } 398e1051a39Sopenharmony_ci 399e1051a39Sopenharmony_ci /* 400e1051a39Sopenharmony_ci * A sorting find then a delete could be faster but these stacks should be 401e1051a39Sopenharmony_ci * relatively small, so we avoid the overhead. Sorting could also surprise 402e1051a39Sopenharmony_ci * users when result orderings change (even though they are not guaranteed). 403e1051a39Sopenharmony_ci */ 404e1051a39Sopenharmony_ci for (i = 0; i < sk_IMPLEMENTATION_num(alg->impls); i++) { 405e1051a39Sopenharmony_ci IMPLEMENTATION *impl = sk_IMPLEMENTATION_value(alg->impls, i); 406e1051a39Sopenharmony_ci 407e1051a39Sopenharmony_ci if (impl->method.method == method) { 408e1051a39Sopenharmony_ci impl_free(impl); 409e1051a39Sopenharmony_ci (void)sk_IMPLEMENTATION_delete(alg->impls, i); 410e1051a39Sopenharmony_ci ossl_property_unlock(store); 411e1051a39Sopenharmony_ci return 1; 412e1051a39Sopenharmony_ci } 413e1051a39Sopenharmony_ci } 414e1051a39Sopenharmony_ci ossl_property_unlock(store); 415e1051a39Sopenharmony_ci return 0; 416e1051a39Sopenharmony_ci} 417e1051a39Sopenharmony_ci 418e1051a39Sopenharmony_cistruct alg_cleanup_by_provider_data_st { 419e1051a39Sopenharmony_ci OSSL_METHOD_STORE *store; 420e1051a39Sopenharmony_ci const OSSL_PROVIDER *prov; 421e1051a39Sopenharmony_ci}; 422e1051a39Sopenharmony_ci 423e1051a39Sopenharmony_cistatic void 424e1051a39Sopenharmony_cialg_cleanup_by_provider(ossl_uintmax_t idx, ALGORITHM *alg, void *arg) 425e1051a39Sopenharmony_ci{ 426e1051a39Sopenharmony_ci struct alg_cleanup_by_provider_data_st *data = arg; 427e1051a39Sopenharmony_ci int i, count; 428e1051a39Sopenharmony_ci 429e1051a39Sopenharmony_ci /* 430e1051a39Sopenharmony_ci * We walk the stack backwards, to avoid having to deal with stack shifts 431e1051a39Sopenharmony_ci * caused by deletion 432e1051a39Sopenharmony_ci */ 433e1051a39Sopenharmony_ci for (count = 0, i = sk_IMPLEMENTATION_num(alg->impls); i-- > 0;) { 434e1051a39Sopenharmony_ci IMPLEMENTATION *impl = sk_IMPLEMENTATION_value(alg->impls, i); 435e1051a39Sopenharmony_ci 436e1051a39Sopenharmony_ci if (impl->provider == data->prov) { 437e1051a39Sopenharmony_ci impl_free(impl); 438e1051a39Sopenharmony_ci (void)sk_IMPLEMENTATION_delete(alg->impls, i); 439e1051a39Sopenharmony_ci count++; 440e1051a39Sopenharmony_ci } 441e1051a39Sopenharmony_ci } 442e1051a39Sopenharmony_ci 443e1051a39Sopenharmony_ci /* 444e1051a39Sopenharmony_ci * If we removed any implementation, we also clear the whole associated 445e1051a39Sopenharmony_ci * cache, 'cause that's the sensible thing to do. 446e1051a39Sopenharmony_ci * There's no point flushing the cache entries where we didn't remove 447e1051a39Sopenharmony_ci * any implementation, though. 448e1051a39Sopenharmony_ci */ 449e1051a39Sopenharmony_ci if (count > 0) 450e1051a39Sopenharmony_ci ossl_method_cache_flush_alg(data->store, alg); 451e1051a39Sopenharmony_ci} 452e1051a39Sopenharmony_ci 453e1051a39Sopenharmony_ciint ossl_method_store_remove_all_provided(OSSL_METHOD_STORE *store, 454e1051a39Sopenharmony_ci const OSSL_PROVIDER *prov) 455e1051a39Sopenharmony_ci{ 456e1051a39Sopenharmony_ci struct alg_cleanup_by_provider_data_st data; 457e1051a39Sopenharmony_ci 458e1051a39Sopenharmony_ci if (!ossl_property_write_lock(store)) 459e1051a39Sopenharmony_ci return 0; 460e1051a39Sopenharmony_ci data.prov = prov; 461e1051a39Sopenharmony_ci data.store = store; 462e1051a39Sopenharmony_ci ossl_sa_ALGORITHM_doall_arg(store->algs, &alg_cleanup_by_provider, &data); 463e1051a39Sopenharmony_ci ossl_property_unlock(store); 464e1051a39Sopenharmony_ci return 1; 465e1051a39Sopenharmony_ci} 466e1051a39Sopenharmony_ci 467e1051a39Sopenharmony_cistatic void alg_do_one(ALGORITHM *alg, IMPLEMENTATION *impl, 468e1051a39Sopenharmony_ci void (*fn)(int id, void *method, void *fnarg), 469e1051a39Sopenharmony_ci void *fnarg) 470e1051a39Sopenharmony_ci{ 471e1051a39Sopenharmony_ci fn(alg->nid, impl->method.method, fnarg); 472e1051a39Sopenharmony_ci} 473e1051a39Sopenharmony_ci 474e1051a39Sopenharmony_cistatic void alg_copy(ossl_uintmax_t idx, ALGORITHM *alg, void *arg) 475e1051a39Sopenharmony_ci{ 476e1051a39Sopenharmony_ci STACK_OF(ALGORITHM) *newalg = arg; 477e1051a39Sopenharmony_ci 478e1051a39Sopenharmony_ci (void)sk_ALGORITHM_push(newalg, alg); 479e1051a39Sopenharmony_ci} 480e1051a39Sopenharmony_ci 481e1051a39Sopenharmony_civoid ossl_method_store_do_all(OSSL_METHOD_STORE *store, 482e1051a39Sopenharmony_ci void (*fn)(int id, void *method, void *fnarg), 483e1051a39Sopenharmony_ci void *fnarg) 484e1051a39Sopenharmony_ci{ 485e1051a39Sopenharmony_ci int i, j; 486e1051a39Sopenharmony_ci int numalgs, numimps; 487e1051a39Sopenharmony_ci STACK_OF(ALGORITHM) *tmpalgs; 488e1051a39Sopenharmony_ci ALGORITHM *alg; 489e1051a39Sopenharmony_ci 490e1051a39Sopenharmony_ci if (store != NULL) { 491e1051a39Sopenharmony_ci 492e1051a39Sopenharmony_ci if (!ossl_property_read_lock(store)) 493e1051a39Sopenharmony_ci return; 494e1051a39Sopenharmony_ci 495e1051a39Sopenharmony_ci tmpalgs = sk_ALGORITHM_new_reserve(NULL, 496e1051a39Sopenharmony_ci ossl_sa_ALGORITHM_num(store->algs)); 497e1051a39Sopenharmony_ci if (tmpalgs == NULL) { 498e1051a39Sopenharmony_ci ossl_property_unlock(store); 499e1051a39Sopenharmony_ci return; 500e1051a39Sopenharmony_ci } 501e1051a39Sopenharmony_ci 502e1051a39Sopenharmony_ci ossl_sa_ALGORITHM_doall_arg(store->algs, alg_copy, tmpalgs); 503e1051a39Sopenharmony_ci ossl_property_unlock(store); 504e1051a39Sopenharmony_ci numalgs = sk_ALGORITHM_num(tmpalgs); 505e1051a39Sopenharmony_ci for (i = 0; i < numalgs; i++) { 506e1051a39Sopenharmony_ci alg = sk_ALGORITHM_value(tmpalgs, i); 507e1051a39Sopenharmony_ci numimps = sk_IMPLEMENTATION_num(alg->impls); 508e1051a39Sopenharmony_ci for (j = 0; j < numimps; j++) 509e1051a39Sopenharmony_ci alg_do_one(alg, sk_IMPLEMENTATION_value(alg->impls, j), fn, fnarg); 510e1051a39Sopenharmony_ci } 511e1051a39Sopenharmony_ci sk_ALGORITHM_free(tmpalgs); 512e1051a39Sopenharmony_ci } 513e1051a39Sopenharmony_ci} 514e1051a39Sopenharmony_ci 515e1051a39Sopenharmony_ciint ossl_method_store_fetch(OSSL_METHOD_STORE *store, 516e1051a39Sopenharmony_ci int nid, const char *prop_query, 517e1051a39Sopenharmony_ci const OSSL_PROVIDER **prov_rw, void **method) 518e1051a39Sopenharmony_ci{ 519e1051a39Sopenharmony_ci OSSL_PROPERTY_LIST **plp; 520e1051a39Sopenharmony_ci ALGORITHM *alg; 521e1051a39Sopenharmony_ci IMPLEMENTATION *impl, *best_impl = NULL; 522e1051a39Sopenharmony_ci OSSL_PROPERTY_LIST *pq = NULL, *p2 = NULL; 523e1051a39Sopenharmony_ci const OSSL_PROVIDER *prov = prov_rw != NULL ? *prov_rw : NULL; 524e1051a39Sopenharmony_ci int ret = 0; 525e1051a39Sopenharmony_ci int j, best = -1, score, optional; 526e1051a39Sopenharmony_ci 527e1051a39Sopenharmony_ci if (nid <= 0 || method == NULL || store == NULL) 528e1051a39Sopenharmony_ci return 0; 529e1051a39Sopenharmony_ci 530e1051a39Sopenharmony_ci#ifndef FIPS_MODULE 531e1051a39Sopenharmony_ci if (ossl_lib_ctx_is_default(store->ctx) 532e1051a39Sopenharmony_ci && !OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL)) 533e1051a39Sopenharmony_ci return 0; 534e1051a39Sopenharmony_ci#endif 535e1051a39Sopenharmony_ci 536e1051a39Sopenharmony_ci /* This only needs to be a read lock, because the query won't create anything */ 537e1051a39Sopenharmony_ci if (!ossl_property_read_lock(store)) 538e1051a39Sopenharmony_ci return 0; 539e1051a39Sopenharmony_ci alg = ossl_method_store_retrieve(store, nid); 540e1051a39Sopenharmony_ci if (alg == NULL) { 541e1051a39Sopenharmony_ci ossl_property_unlock(store); 542e1051a39Sopenharmony_ci return 0; 543e1051a39Sopenharmony_ci } 544e1051a39Sopenharmony_ci 545e1051a39Sopenharmony_ci if (prop_query != NULL) 546e1051a39Sopenharmony_ci p2 = pq = ossl_parse_query(store->ctx, prop_query, 0); 547e1051a39Sopenharmony_ci plp = ossl_ctx_global_properties(store->ctx, 0); 548e1051a39Sopenharmony_ci if (plp != NULL && *plp != NULL) { 549e1051a39Sopenharmony_ci if (pq == NULL) { 550e1051a39Sopenharmony_ci pq = *plp; 551e1051a39Sopenharmony_ci } else { 552e1051a39Sopenharmony_ci p2 = ossl_property_merge(pq, *plp); 553e1051a39Sopenharmony_ci ossl_property_free(pq); 554e1051a39Sopenharmony_ci if (p2 == NULL) 555e1051a39Sopenharmony_ci goto fin; 556e1051a39Sopenharmony_ci pq = p2; 557e1051a39Sopenharmony_ci } 558e1051a39Sopenharmony_ci } 559e1051a39Sopenharmony_ci 560e1051a39Sopenharmony_ci if (pq == NULL) { 561e1051a39Sopenharmony_ci for (j = 0; j < sk_IMPLEMENTATION_num(alg->impls); j++) { 562e1051a39Sopenharmony_ci if ((impl = sk_IMPLEMENTATION_value(alg->impls, j)) != NULL 563e1051a39Sopenharmony_ci && (prov == NULL || impl->provider == prov)) { 564e1051a39Sopenharmony_ci best_impl = impl; 565e1051a39Sopenharmony_ci ret = 1; 566e1051a39Sopenharmony_ci break; 567e1051a39Sopenharmony_ci } 568e1051a39Sopenharmony_ci } 569e1051a39Sopenharmony_ci goto fin; 570e1051a39Sopenharmony_ci } 571e1051a39Sopenharmony_ci optional = ossl_property_has_optional(pq); 572e1051a39Sopenharmony_ci for (j = 0; j < sk_IMPLEMENTATION_num(alg->impls); j++) { 573e1051a39Sopenharmony_ci if ((impl = sk_IMPLEMENTATION_value(alg->impls, j)) != NULL 574e1051a39Sopenharmony_ci && (prov == NULL || impl->provider == prov)) { 575e1051a39Sopenharmony_ci score = ossl_property_match_count(pq, impl->properties); 576e1051a39Sopenharmony_ci if (score > best) { 577e1051a39Sopenharmony_ci best_impl = impl; 578e1051a39Sopenharmony_ci best = score; 579e1051a39Sopenharmony_ci ret = 1; 580e1051a39Sopenharmony_ci if (!optional) 581e1051a39Sopenharmony_ci goto fin; 582e1051a39Sopenharmony_ci } 583e1051a39Sopenharmony_ci } 584e1051a39Sopenharmony_ci } 585e1051a39Sopenharmony_cifin: 586e1051a39Sopenharmony_ci if (ret && ossl_method_up_ref(&best_impl->method)) { 587e1051a39Sopenharmony_ci *method = best_impl->method.method; 588e1051a39Sopenharmony_ci if (prov_rw != NULL) 589e1051a39Sopenharmony_ci *prov_rw = best_impl->provider; 590e1051a39Sopenharmony_ci } else { 591e1051a39Sopenharmony_ci ret = 0; 592e1051a39Sopenharmony_ci } 593e1051a39Sopenharmony_ci ossl_property_unlock(store); 594e1051a39Sopenharmony_ci ossl_property_free(p2); 595e1051a39Sopenharmony_ci return ret; 596e1051a39Sopenharmony_ci} 597e1051a39Sopenharmony_ci 598e1051a39Sopenharmony_cistatic void ossl_method_cache_flush_alg(OSSL_METHOD_STORE *store, 599e1051a39Sopenharmony_ci ALGORITHM *alg) 600e1051a39Sopenharmony_ci{ 601e1051a39Sopenharmony_ci store->cache_nelem -= lh_QUERY_num_items(alg->cache); 602e1051a39Sopenharmony_ci impl_cache_flush_alg(0, alg); 603e1051a39Sopenharmony_ci} 604e1051a39Sopenharmony_ci 605e1051a39Sopenharmony_cistatic void ossl_method_cache_flush(OSSL_METHOD_STORE *store, int nid) 606e1051a39Sopenharmony_ci{ 607e1051a39Sopenharmony_ci ALGORITHM *alg = ossl_method_store_retrieve(store, nid); 608e1051a39Sopenharmony_ci 609e1051a39Sopenharmony_ci if (alg != NULL) 610e1051a39Sopenharmony_ci ossl_method_cache_flush_alg(store, alg); 611e1051a39Sopenharmony_ci} 612e1051a39Sopenharmony_ci 613e1051a39Sopenharmony_ciint ossl_method_store_cache_flush_all(OSSL_METHOD_STORE *store) 614e1051a39Sopenharmony_ci{ 615e1051a39Sopenharmony_ci if (!ossl_property_write_lock(store)) 616e1051a39Sopenharmony_ci return 0; 617e1051a39Sopenharmony_ci ossl_sa_ALGORITHM_doall(store->algs, &impl_cache_flush_alg); 618e1051a39Sopenharmony_ci store->cache_nelem = 0; 619e1051a39Sopenharmony_ci ossl_property_unlock(store); 620e1051a39Sopenharmony_ci return 1; 621e1051a39Sopenharmony_ci} 622e1051a39Sopenharmony_ci 623e1051a39Sopenharmony_ciIMPLEMENT_LHASH_DOALL_ARG(QUERY, IMPL_CACHE_FLUSH); 624e1051a39Sopenharmony_ci 625e1051a39Sopenharmony_ci/* 626e1051a39Sopenharmony_ci * Flush an element from the query cache (perhaps). 627e1051a39Sopenharmony_ci * 628e1051a39Sopenharmony_ci * In order to avoid taking a write lock or using atomic operations 629e1051a39Sopenharmony_ci * to keep accurate least recently used (LRU) or least frequently used 630e1051a39Sopenharmony_ci * (LFU) information, the procedure used here is to stochastically 631e1051a39Sopenharmony_ci * flush approximately half the cache. 632e1051a39Sopenharmony_ci * 633e1051a39Sopenharmony_ci * This procedure isn't ideal, LRU or LFU would be better. However, 634e1051a39Sopenharmony_ci * in normal operation, reaching a full cache would be unexpected. 635e1051a39Sopenharmony_ci * It means that no steady state of algorithm queries has been reached. 636e1051a39Sopenharmony_ci * That is, it is most likely an attack of some form. A suboptimal clearance 637e1051a39Sopenharmony_ci * strategy that doesn't degrade performance of the normal case is 638e1051a39Sopenharmony_ci * preferable to a more refined approach that imposes a performance 639e1051a39Sopenharmony_ci * impact. 640e1051a39Sopenharmony_ci */ 641e1051a39Sopenharmony_cistatic void impl_cache_flush_cache(QUERY *c, IMPL_CACHE_FLUSH *state) 642e1051a39Sopenharmony_ci{ 643e1051a39Sopenharmony_ci uint32_t n; 644e1051a39Sopenharmony_ci 645e1051a39Sopenharmony_ci /* 646e1051a39Sopenharmony_ci * Implement the 32 bit xorshift as suggested by George Marsaglia in: 647e1051a39Sopenharmony_ci * https://doi.org/10.18637/jss.v008.i14 648e1051a39Sopenharmony_ci * 649e1051a39Sopenharmony_ci * This is a very fast PRNG so there is no need to extract bits one at a 650e1051a39Sopenharmony_ci * time and use the entire value each time. 651e1051a39Sopenharmony_ci */ 652e1051a39Sopenharmony_ci n = state->seed; 653e1051a39Sopenharmony_ci n ^= n << 13; 654e1051a39Sopenharmony_ci n ^= n >> 17; 655e1051a39Sopenharmony_ci n ^= n << 5; 656e1051a39Sopenharmony_ci state->seed = n; 657e1051a39Sopenharmony_ci 658e1051a39Sopenharmony_ci if ((n & 1) != 0) 659e1051a39Sopenharmony_ci impl_cache_free(lh_QUERY_delete(state->cache, c)); 660e1051a39Sopenharmony_ci else 661e1051a39Sopenharmony_ci state->nelem++; 662e1051a39Sopenharmony_ci} 663e1051a39Sopenharmony_ci 664e1051a39Sopenharmony_cistatic void impl_cache_flush_one_alg(ossl_uintmax_t idx, ALGORITHM *alg, 665e1051a39Sopenharmony_ci void *v) 666e1051a39Sopenharmony_ci{ 667e1051a39Sopenharmony_ci IMPL_CACHE_FLUSH *state = (IMPL_CACHE_FLUSH *)v; 668e1051a39Sopenharmony_ci 669e1051a39Sopenharmony_ci state->cache = alg->cache; 670e1051a39Sopenharmony_ci lh_QUERY_doall_IMPL_CACHE_FLUSH(state->cache, &impl_cache_flush_cache, 671e1051a39Sopenharmony_ci state); 672e1051a39Sopenharmony_ci} 673e1051a39Sopenharmony_ci 674e1051a39Sopenharmony_cistatic void ossl_method_cache_flush_some(OSSL_METHOD_STORE *store) 675e1051a39Sopenharmony_ci{ 676e1051a39Sopenharmony_ci IMPL_CACHE_FLUSH state; 677e1051a39Sopenharmony_ci static TSAN_QUALIFIER uint32_t global_seed = 1; 678e1051a39Sopenharmony_ci 679e1051a39Sopenharmony_ci state.nelem = 0; 680e1051a39Sopenharmony_ci state.using_global_seed = 0; 681e1051a39Sopenharmony_ci if ((state.seed = OPENSSL_rdtsc()) == 0) { 682e1051a39Sopenharmony_ci /* If there is no timer available, seed another way */ 683e1051a39Sopenharmony_ci state.using_global_seed = 1; 684e1051a39Sopenharmony_ci state.seed = tsan_load(&global_seed); 685e1051a39Sopenharmony_ci } 686e1051a39Sopenharmony_ci store->cache_need_flush = 0; 687e1051a39Sopenharmony_ci ossl_sa_ALGORITHM_doall_arg(store->algs, &impl_cache_flush_one_alg, &state); 688e1051a39Sopenharmony_ci store->cache_nelem = state.nelem; 689e1051a39Sopenharmony_ci /* Without a timer, update the global seed */ 690e1051a39Sopenharmony_ci if (state.using_global_seed) 691e1051a39Sopenharmony_ci tsan_store(&global_seed, state.seed); 692e1051a39Sopenharmony_ci} 693e1051a39Sopenharmony_ci 694e1051a39Sopenharmony_ciint ossl_method_store_cache_get(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov, 695e1051a39Sopenharmony_ci int nid, const char *prop_query, void **method) 696e1051a39Sopenharmony_ci{ 697e1051a39Sopenharmony_ci ALGORITHM *alg; 698e1051a39Sopenharmony_ci QUERY elem, *r; 699e1051a39Sopenharmony_ci int res = 0; 700e1051a39Sopenharmony_ci 701e1051a39Sopenharmony_ci if (nid <= 0 || store == NULL || prop_query == NULL) 702e1051a39Sopenharmony_ci return 0; 703e1051a39Sopenharmony_ci 704e1051a39Sopenharmony_ci if (!ossl_property_read_lock(store)) 705e1051a39Sopenharmony_ci return 0; 706e1051a39Sopenharmony_ci alg = ossl_method_store_retrieve(store, nid); 707e1051a39Sopenharmony_ci if (alg == NULL) 708e1051a39Sopenharmony_ci goto err; 709e1051a39Sopenharmony_ci 710e1051a39Sopenharmony_ci elem.query = prop_query; 711e1051a39Sopenharmony_ci elem.provider = prov; 712e1051a39Sopenharmony_ci r = lh_QUERY_retrieve(alg->cache, &elem); 713e1051a39Sopenharmony_ci if (r == NULL) 714e1051a39Sopenharmony_ci goto err; 715e1051a39Sopenharmony_ci if (ossl_method_up_ref(&r->method)) { 716e1051a39Sopenharmony_ci *method = r->method.method; 717e1051a39Sopenharmony_ci res = 1; 718e1051a39Sopenharmony_ci } 719e1051a39Sopenharmony_cierr: 720e1051a39Sopenharmony_ci ossl_property_unlock(store); 721e1051a39Sopenharmony_ci return res; 722e1051a39Sopenharmony_ci} 723e1051a39Sopenharmony_ci 724e1051a39Sopenharmony_ciint ossl_method_store_cache_set(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov, 725e1051a39Sopenharmony_ci int nid, const char *prop_query, void *method, 726e1051a39Sopenharmony_ci int (*method_up_ref)(void *), 727e1051a39Sopenharmony_ci void (*method_destruct)(void *)) 728e1051a39Sopenharmony_ci{ 729e1051a39Sopenharmony_ci QUERY elem, *old, *p = NULL; 730e1051a39Sopenharmony_ci ALGORITHM *alg; 731e1051a39Sopenharmony_ci size_t len; 732e1051a39Sopenharmony_ci int res = 1; 733e1051a39Sopenharmony_ci 734e1051a39Sopenharmony_ci if (nid <= 0 || store == NULL || prop_query == NULL) 735e1051a39Sopenharmony_ci return 0; 736e1051a39Sopenharmony_ci 737e1051a39Sopenharmony_ci if (!ossl_assert(prov != NULL)) 738e1051a39Sopenharmony_ci return 0; 739e1051a39Sopenharmony_ci 740e1051a39Sopenharmony_ci if (!ossl_property_write_lock(store)) 741e1051a39Sopenharmony_ci return 0; 742e1051a39Sopenharmony_ci if (store->cache_need_flush) 743e1051a39Sopenharmony_ci ossl_method_cache_flush_some(store); 744e1051a39Sopenharmony_ci alg = ossl_method_store_retrieve(store, nid); 745e1051a39Sopenharmony_ci if (alg == NULL) 746e1051a39Sopenharmony_ci goto err; 747e1051a39Sopenharmony_ci 748e1051a39Sopenharmony_ci if (method == NULL) { 749e1051a39Sopenharmony_ci elem.query = prop_query; 750e1051a39Sopenharmony_ci elem.provider = prov; 751e1051a39Sopenharmony_ci if ((old = lh_QUERY_delete(alg->cache, &elem)) != NULL) { 752e1051a39Sopenharmony_ci impl_cache_free(old); 753e1051a39Sopenharmony_ci store->cache_nelem--; 754e1051a39Sopenharmony_ci } 755e1051a39Sopenharmony_ci goto end; 756e1051a39Sopenharmony_ci } 757e1051a39Sopenharmony_ci p = OPENSSL_malloc(sizeof(*p) + (len = strlen(prop_query))); 758e1051a39Sopenharmony_ci if (p != NULL) { 759e1051a39Sopenharmony_ci p->query = p->body; 760e1051a39Sopenharmony_ci p->provider = prov; 761e1051a39Sopenharmony_ci p->method.method = method; 762e1051a39Sopenharmony_ci p->method.up_ref = method_up_ref; 763e1051a39Sopenharmony_ci p->method.free = method_destruct; 764e1051a39Sopenharmony_ci if (!ossl_method_up_ref(&p->method)) 765e1051a39Sopenharmony_ci goto err; 766e1051a39Sopenharmony_ci memcpy((char *)p->query, prop_query, len + 1); 767e1051a39Sopenharmony_ci if ((old = lh_QUERY_insert(alg->cache, p)) != NULL) { 768e1051a39Sopenharmony_ci impl_cache_free(old); 769e1051a39Sopenharmony_ci goto end; 770e1051a39Sopenharmony_ci } 771e1051a39Sopenharmony_ci if (!lh_QUERY_error(alg->cache)) { 772e1051a39Sopenharmony_ci if (++store->cache_nelem >= IMPL_CACHE_FLUSH_THRESHOLD) 773e1051a39Sopenharmony_ci store->cache_need_flush = 1; 774e1051a39Sopenharmony_ci goto end; 775e1051a39Sopenharmony_ci } 776e1051a39Sopenharmony_ci ossl_method_free(&p->method); 777e1051a39Sopenharmony_ci } 778e1051a39Sopenharmony_cierr: 779e1051a39Sopenharmony_ci res = 0; 780e1051a39Sopenharmony_ci OPENSSL_free(p); 781e1051a39Sopenharmony_ciend: 782e1051a39Sopenharmony_ci ossl_property_unlock(store); 783e1051a39Sopenharmony_ci return res; 784e1051a39Sopenharmony_ci} 785