property.c 21 KB

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