2
0

eng_table.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /* ====================================================================
  2. * Copyright (c) 2001 The OpenSSL Project. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in
  13. * the documentation and/or other materials provided with the
  14. * distribution.
  15. *
  16. * 3. All advertising materials mentioning features or use of this
  17. * software must display the following acknowledgment:
  18. * "This product includes software developed by the OpenSSL Project
  19. * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
  20. *
  21. * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
  22. * endorse or promote products derived from this software without
  23. * prior written permission. For written permission, please contact
  24. * licensing@OpenSSL.org.
  25. *
  26. * 5. Products derived from this software may not be called "OpenSSL"
  27. * nor may "OpenSSL" appear in their names without prior written
  28. * permission of the OpenSSL Project.
  29. *
  30. * 6. Redistributions of any form whatsoever must retain the following
  31. * acknowledgment:
  32. * "This product includes software developed by the OpenSSL Project
  33. * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
  34. *
  35. * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
  36. * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  38. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  41. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  42. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  44. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  45. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  46. * OF THE POSSIBILITY OF SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This product includes cryptographic software written by Eric Young
  50. * (eay@cryptsoft.com). This product includes software written by Tim
  51. * Hudson (tjh@cryptsoft.com).
  52. *
  53. */
  54. #include "cryptlib.h"
  55. #include <openssl/evp.h>
  56. #include <openssl/lhash.h>
  57. #include "eng_int.h"
  58. /* The type of the items in the table */
  59. typedef struct st_engine_pile {
  60. /* The 'nid' of this algorithm/mode */
  61. int nid;
  62. /* ENGINEs that implement this algorithm/mode. */
  63. STACK_OF(ENGINE) *sk;
  64. /* The default ENGINE to perform this algorithm/mode. */
  65. ENGINE *funct;
  66. /*
  67. * Zero if 'sk' is newer than the cached 'funct', non-zero otherwise
  68. */
  69. int uptodate;
  70. } ENGINE_PILE;
  71. /* The type exposed in eng_int.h */
  72. struct st_engine_table {
  73. LHASH piles;
  74. }; /* ENGINE_TABLE */
  75. /* Global flags (ENGINE_TABLE_FLAG_***). */
  76. static unsigned int table_flags = 0;
  77. /* API function manipulating 'table_flags' */
  78. unsigned int ENGINE_get_table_flags(void)
  79. {
  80. return table_flags;
  81. }
  82. void ENGINE_set_table_flags(unsigned int flags)
  83. {
  84. table_flags = flags;
  85. }
  86. /* Internal functions for the "piles" hash table */
  87. static unsigned long engine_pile_hash(const ENGINE_PILE *c)
  88. {
  89. return c->nid;
  90. }
  91. static int engine_pile_cmp(const ENGINE_PILE *a, const ENGINE_PILE *b)
  92. {
  93. return a->nid - b->nid;
  94. }
  95. static IMPLEMENT_LHASH_HASH_FN(engine_pile_hash, const ENGINE_PILE *)
  96. static IMPLEMENT_LHASH_COMP_FN(engine_pile_cmp, const ENGINE_PILE *)
  97. static int int_table_check(ENGINE_TABLE **t, int create)
  98. {
  99. LHASH *lh;
  100. if (*t)
  101. return 1;
  102. if (!create)
  103. return 0;
  104. if ((lh = lh_new(LHASH_HASH_FN(engine_pile_hash),
  105. LHASH_COMP_FN(engine_pile_cmp))) == NULL)
  106. return 0;
  107. *t = (ENGINE_TABLE *)lh;
  108. return 1;
  109. }
  110. /*
  111. * Privately exposed (via eng_int.h) functions for adding and/or removing
  112. * ENGINEs from the implementation table
  113. */
  114. int engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup,
  115. ENGINE *e, const int *nids, int num_nids,
  116. int setdefault)
  117. {
  118. int ret = 0, added = 0;
  119. ENGINE_PILE tmplate, *fnd;
  120. CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
  121. if (!(*table))
  122. added = 1;
  123. if (!int_table_check(table, 1))
  124. goto end;
  125. if (added)
  126. /* The cleanup callback needs to be added */
  127. engine_cleanup_add_first(cleanup);
  128. while (num_nids--) {
  129. tmplate.nid = *nids;
  130. fnd = lh_retrieve(&(*table)->piles, &tmplate);
  131. if (!fnd) {
  132. fnd = OPENSSL_malloc(sizeof(ENGINE_PILE));
  133. if (!fnd)
  134. goto end;
  135. fnd->uptodate = 1;
  136. fnd->nid = *nids;
  137. fnd->sk = sk_ENGINE_new_null();
  138. if (!fnd->sk) {
  139. OPENSSL_free(fnd);
  140. goto end;
  141. }
  142. fnd->funct = NULL;
  143. lh_insert(&(*table)->piles, fnd);
  144. }
  145. /* A registration shouldn't add duplciate entries */
  146. (void)sk_ENGINE_delete_ptr(fnd->sk, e);
  147. /*
  148. * if 'setdefault', this ENGINE goes to the head of the list
  149. */
  150. if (!sk_ENGINE_push(fnd->sk, e))
  151. goto end;
  152. /* "touch" this ENGINE_PILE */
  153. fnd->uptodate = 0;
  154. if (setdefault) {
  155. if (!engine_unlocked_init(e)) {
  156. ENGINEerr(ENGINE_F_ENGINE_TABLE_REGISTER,
  157. ENGINE_R_INIT_FAILED);
  158. goto end;
  159. }
  160. if (fnd->funct)
  161. engine_unlocked_finish(fnd->funct, 0);
  162. fnd->funct = e;
  163. fnd->uptodate = 1;
  164. }
  165. nids++;
  166. }
  167. ret = 1;
  168. end:
  169. CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
  170. return ret;
  171. }
  172. static void int_unregister_cb(ENGINE_PILE *pile, ENGINE *e)
  173. {
  174. int n;
  175. /* Iterate the 'c->sk' stack removing any occurance of 'e' */
  176. while ((n = sk_ENGINE_find(pile->sk, e)) >= 0) {
  177. (void)sk_ENGINE_delete(pile->sk, n);
  178. pile->uptodate = 0;
  179. }
  180. if (pile->funct == e) {
  181. engine_unlocked_finish(e, 0);
  182. pile->funct = NULL;
  183. }
  184. }
  185. static IMPLEMENT_LHASH_DOALL_ARG_FN(int_unregister_cb, ENGINE_PILE *,
  186. ENGINE *)
  187. void engine_table_unregister(ENGINE_TABLE **table, ENGINE *e)
  188. {
  189. CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
  190. if (int_table_check(table, 0))
  191. lh_doall_arg(&(*table)->piles,
  192. LHASH_DOALL_ARG_FN(int_unregister_cb), e);
  193. CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
  194. }
  195. static void int_cleanup_cb(ENGINE_PILE *p)
  196. {
  197. sk_ENGINE_free(p->sk);
  198. if (p->funct)
  199. engine_unlocked_finish(p->funct, 0);
  200. OPENSSL_free(p);
  201. }
  202. static IMPLEMENT_LHASH_DOALL_FN(int_cleanup_cb, ENGINE_PILE *)
  203. void engine_table_cleanup(ENGINE_TABLE **table)
  204. {
  205. CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
  206. if (*table) {
  207. lh_doall(&(*table)->piles, LHASH_DOALL_FN(int_cleanup_cb));
  208. lh_free(&(*table)->piles);
  209. *table = NULL;
  210. }
  211. CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
  212. }
  213. /* return a functional reference for a given 'nid' */
  214. #ifndef ENGINE_TABLE_DEBUG
  215. ENGINE *engine_table_select(ENGINE_TABLE **table, int nid)
  216. #else
  217. ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f,
  218. int l)
  219. #endif
  220. {
  221. ENGINE *ret = NULL;
  222. ENGINE_PILE tmplate, *fnd = NULL;
  223. int initres, loop = 0;
  224. if (!(*table)) {
  225. #ifdef ENGINE_TABLE_DEBUG
  226. fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, nothing "
  227. "registered!\n", f, l, nid);
  228. #endif
  229. return NULL;
  230. }
  231. ERR_set_mark();
  232. CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
  233. /*
  234. * Check again inside the lock otherwise we could race against cleanup
  235. * operations. But don't worry about a fprintf(stderr).
  236. */
  237. if (!int_table_check(table, 0))
  238. goto end;
  239. tmplate.nid = nid;
  240. fnd = lh_retrieve(&(*table)->piles, &tmplate);
  241. if (!fnd)
  242. goto end;
  243. if (fnd->funct && engine_unlocked_init(fnd->funct)) {
  244. #ifdef ENGINE_TABLE_DEBUG
  245. fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
  246. "ENGINE '%s' cached\n", f, l, nid, fnd->funct->id);
  247. #endif
  248. ret = fnd->funct;
  249. goto end;
  250. }
  251. if (fnd->uptodate) {
  252. ret = fnd->funct;
  253. goto end;
  254. }
  255. trynext:
  256. ret = sk_ENGINE_value(fnd->sk, loop++);
  257. if (!ret) {
  258. #ifdef ENGINE_TABLE_DEBUG
  259. fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no "
  260. "registered implementations would initialise\n", f, l, nid);
  261. #endif
  262. goto end;
  263. }
  264. /* Try to initialise the ENGINE? */
  265. if ((ret->funct_ref > 0) || !(table_flags & ENGINE_TABLE_FLAG_NOINIT))
  266. initres = engine_unlocked_init(ret);
  267. else
  268. initres = 0;
  269. if (initres) {
  270. /* Update 'funct' */
  271. if ((fnd->funct != ret) && engine_unlocked_init(ret)) {
  272. /* If there was a previous default we release it. */
  273. if (fnd->funct)
  274. engine_unlocked_finish(fnd->funct, 0);
  275. fnd->funct = ret;
  276. #ifdef ENGINE_TABLE_DEBUG
  277. fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, "
  278. "setting default to '%s'\n", f, l, nid, ret->id);
  279. #endif
  280. }
  281. #ifdef ENGINE_TABLE_DEBUG
  282. fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
  283. "newly initialised '%s'\n", f, l, nid, ret->id);
  284. #endif
  285. goto end;
  286. }
  287. goto trynext;
  288. end:
  289. /*
  290. * If it failed, it is unlikely to succeed again until some future
  291. * registrations have taken place. In all cases, we cache.
  292. */
  293. if (fnd)
  294. fnd->uptodate = 1;
  295. #ifdef ENGINE_TABLE_DEBUG
  296. if (ret)
  297. fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
  298. "ENGINE '%s'\n", f, l, nid, ret->id);
  299. else
  300. fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
  301. "'no matching ENGINE'\n", f, l, nid);
  302. #endif
  303. CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
  304. /*
  305. * Whatever happened, any failed init()s are not failures in this
  306. * context, so clear our error state.
  307. */
  308. ERR_pop_to_mark();
  309. return ret;
  310. }