property.c 22 KB

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