Import LibreSSL v2.4.2 to vendor branch
[dragonfly.git] / crypto / libressl / crypto / engine / eng_table.c
blob4fd83a00d89d3def2112229f5fc5c77e1df90ed9
1 /* $OpenBSD: eng_table.c,v 1.7 2014/07/11 08:44:48 jsing Exp $ */
2 /* ====================================================================
3 * Copyright (c) 2001 The OpenSSL Project. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
17 * 3. All advertising materials mentioning features or use of this
18 * software must display the following acknowledgment:
19 * "This product includes software developed by the OpenSSL Project
20 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
22 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23 * endorse or promote products derived from this software without
24 * prior written permission. For written permission, please contact
25 * licensing@OpenSSL.org.
27 * 5. Products derived from this software may not be called "OpenSSL"
28 * nor may "OpenSSL" appear in their names without prior written
29 * permission of the OpenSSL Project.
31 * 6. Redistributions of any form whatsoever must retain the following
32 * acknowledgment:
33 * "This product includes software developed by the OpenSSL Project
34 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
36 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47 * OF THE POSSIBILITY OF SUCH DAMAGE.
48 * ====================================================================
50 * This product includes cryptographic software written by Eric Young
51 * (eay@cryptsoft.com). This product includes software written by Tim
52 * Hudson (tjh@cryptsoft.com).
56 #include <openssl/err.h>
57 #include <openssl/evp.h>
58 #include <openssl/lhash.h>
60 #include "eng_int.h"
62 /* The type of the items in the table */
63 typedef struct st_engine_pile {
64 /* The 'nid' of this algorithm/mode */
65 int nid;
66 /* ENGINEs that implement this algorithm/mode. */
67 STACK_OF(ENGINE) *sk;
68 /* The default ENGINE to perform this algorithm/mode. */
69 ENGINE *funct;
70 /* Zero if 'sk' is newer than the cached 'funct', non-zero otherwise */
71 int uptodate;
72 } ENGINE_PILE;
74 DECLARE_LHASH_OF(ENGINE_PILE);
76 /* The type exposed in eng_int.h */
77 struct st_engine_table {
78 LHASH_OF(ENGINE_PILE) piles;
79 }; /* ENGINE_TABLE */
81 typedef struct st_engine_pile_doall {
82 engine_table_doall_cb *cb;
83 void *arg;
84 } ENGINE_PILE_DOALL;
86 /* Global flags (ENGINE_TABLE_FLAG_***). */
87 static unsigned int table_flags = 0;
89 /* API function manipulating 'table_flags' */
90 unsigned int
91 ENGINE_get_table_flags(void)
93 return table_flags;
96 void
97 ENGINE_set_table_flags(unsigned int flags)
99 table_flags = flags;
102 /* Internal functions for the "piles" hash table */
103 static unsigned long
104 engine_pile_hash(const ENGINE_PILE *c)
106 return c->nid;
109 static int
110 engine_pile_cmp(const ENGINE_PILE *a, const ENGINE_PILE *b)
112 return a->nid - b->nid;
114 static IMPLEMENT_LHASH_HASH_FN(engine_pile, ENGINE_PILE)
115 static IMPLEMENT_LHASH_COMP_FN(engine_pile, ENGINE_PILE)
117 static int
118 int_table_check(ENGINE_TABLE **t, int create)
120 LHASH_OF(ENGINE_PILE) *lh;
122 if (*t)
123 return 1;
124 if (!create)
125 return 0;
126 if ((lh = lh_ENGINE_PILE_new()) == NULL)
127 return 0;
128 *t = (ENGINE_TABLE *)lh;
129 return 1;
132 /* Privately exposed (via eng_int.h) functions for adding and/or removing
133 * ENGINEs from the implementation table */
135 engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup,
136 ENGINE *e, const int *nids, int num_nids, int setdefault)
138 int ret = 0, added = 0;
139 ENGINE_PILE tmplate, *fnd;
141 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
142 if (!(*table))
143 added = 1;
144 if (!int_table_check(table, 1))
145 goto end;
146 if (added)
147 /* The cleanup callback needs to be added */
148 engine_cleanup_add_first(cleanup);
149 while (num_nids--) {
150 tmplate.nid = *nids;
151 fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate);
152 if (!fnd) {
153 fnd = malloc(sizeof(ENGINE_PILE));
154 if (!fnd)
155 goto end;
156 fnd->uptodate = 1;
157 fnd->nid = *nids;
158 fnd->sk = sk_ENGINE_new_null();
159 if (!fnd->sk) {
160 free(fnd);
161 goto end;
163 fnd->funct = NULL;
164 (void)lh_ENGINE_PILE_insert(&(*table)->piles, fnd);
166 /* A registration shouldn't add duplciate entries */
167 (void)sk_ENGINE_delete_ptr(fnd->sk, e);
168 /* if 'setdefault', this ENGINE goes to the head of the list */
169 if (!sk_ENGINE_push(fnd->sk, e))
170 goto end;
171 /* "touch" this ENGINE_PILE */
172 fnd->uptodate = 0;
173 if (setdefault) {
174 if (!engine_unlocked_init(e)) {
175 ENGINEerr(ENGINE_F_ENGINE_TABLE_REGISTER,
176 ENGINE_R_INIT_FAILED);
177 goto end;
179 if (fnd->funct)
180 engine_unlocked_finish(fnd->funct, 0);
181 fnd->funct = e;
182 fnd->uptodate = 1;
184 nids++;
186 ret = 1;
187 end:
188 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
189 return ret;
192 static void
193 int_unregister_cb_doall_arg(ENGINE_PILE *pile, ENGINE *e)
195 int n;
197 /* Iterate the 'c->sk' stack removing any occurance of 'e' */
198 while ((n = sk_ENGINE_find(pile->sk, e)) >= 0) {
199 (void)sk_ENGINE_delete(pile->sk, n);
200 pile->uptodate = 0;
202 if (pile->funct == e) {
203 engine_unlocked_finish(e, 0);
204 pile->funct = NULL;
207 static IMPLEMENT_LHASH_DOALL_ARG_FN(int_unregister_cb, ENGINE_PILE, ENGINE)
209 void
210 engine_table_unregister(ENGINE_TABLE **table, ENGINE *e)
212 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
213 if (int_table_check(table, 0))
214 lh_ENGINE_PILE_doall_arg(&(*table)->piles,
215 LHASH_DOALL_ARG_FN(int_unregister_cb), ENGINE, e);
216 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
219 static void
220 int_cleanup_cb_doall(ENGINE_PILE *p)
222 sk_ENGINE_free(p->sk);
223 if (p->funct)
224 engine_unlocked_finish(p->funct, 0);
225 free(p);
227 static IMPLEMENT_LHASH_DOALL_FN(int_cleanup_cb, ENGINE_PILE)
229 void
230 engine_table_cleanup(ENGINE_TABLE **table)
232 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
233 if (*table) {
234 lh_ENGINE_PILE_doall(&(*table)->piles,
235 LHASH_DOALL_FN(int_cleanup_cb));
236 lh_ENGINE_PILE_free(&(*table)->piles);
237 *table = NULL;
239 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
242 /* return a functional reference for a given 'nid' */
243 #ifndef ENGINE_TABLE_DEBUG
244 ENGINE *
245 engine_table_select(ENGINE_TABLE **table, int nid)
246 #else
247 ENGINE *
248 engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f, int l)
249 #endif
251 ENGINE *ret = NULL;
252 ENGINE_PILE tmplate, *fnd = NULL;
253 int initres, loop = 0;
255 if (!(*table)) {
256 #ifdef ENGINE_TABLE_DEBUG
257 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, nothing "
258 "registered!\n", f, l, nid);
259 #endif
260 return NULL;
262 ERR_set_mark();
263 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
264 /* Check again inside the lock otherwise we could race against cleanup
265 * operations. But don't worry about a fprintf(stderr). */
266 if (!int_table_check(table, 0))
267 goto end;
268 tmplate.nid = nid;
269 fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate);
270 if (!fnd)
271 goto end;
272 if (fnd->funct && engine_unlocked_init(fnd->funct)) {
273 #ifdef ENGINE_TABLE_DEBUG
274 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
275 "ENGINE '%s' cached\n", f, l, nid, fnd->funct->id);
276 #endif
277 ret = fnd->funct;
278 goto end;
280 if (fnd->uptodate) {
281 ret = fnd->funct;
282 goto end;
284 trynext:
285 ret = sk_ENGINE_value(fnd->sk, loop++);
286 if (!ret) {
287 #ifdef ENGINE_TABLE_DEBUG
288 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no "
289 "registered implementations would initialise\n", f, l, nid);
290 #endif
291 goto end;
293 /* Try to initialise the ENGINE? */
294 if ((ret->funct_ref > 0) || !(table_flags & ENGINE_TABLE_FLAG_NOINIT))
295 initres = engine_unlocked_init(ret);
296 else
297 initres = 0;
298 if (initres) {
299 /* Update 'funct' */
300 if ((fnd->funct != ret) && engine_unlocked_init(ret)) {
301 /* If there was a previous default we release it. */
302 if (fnd->funct)
303 engine_unlocked_finish(fnd->funct, 0);
304 fnd->funct = ret;
305 #ifdef ENGINE_TABLE_DEBUG
306 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, "
307 "setting default to '%s'\n", f, l, nid, ret->id);
308 #endif
310 #ifdef ENGINE_TABLE_DEBUG
311 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
312 "newly initialised '%s'\n", f, l, nid, ret->id);
313 #endif
314 goto end;
316 goto trynext;
317 end:
318 /* If it failed, it is unlikely to succeed again until some future
319 * registrations have taken place. In all cases, we cache. */
320 if (fnd)
321 fnd->uptodate = 1;
322 #ifdef ENGINE_TABLE_DEBUG
323 if (ret)
324 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
325 "ENGINE '%s'\n", f, l, nid, ret->id);
326 else
327 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
328 "'no matching ENGINE'\n", f, l, nid);
329 #endif
330 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
331 /* Whatever happened, any failed init()s are not failures in this
332 * context, so clear our error state. */
333 ERR_pop_to_mark();
334 return ret;
337 /* Table enumeration */
339 static void
340 int_cb_doall_arg(ENGINE_PILE *pile, ENGINE_PILE_DOALL *dall)
342 dall->cb(pile->nid, pile->sk, pile->funct, dall->arg);
344 static IMPLEMENT_LHASH_DOALL_ARG_FN(int_cb, ENGINE_PILE, ENGINE_PILE_DOALL)
346 void
347 engine_table_doall(ENGINE_TABLE *table, engine_table_doall_cb *cb, void *arg)
349 ENGINE_PILE_DOALL dall;
351 dall.cb = cb;
352 dall.arg = arg;
353 lh_ENGINE_PILE_doall_arg(&table->piles, LHASH_DOALL_ARG_FN(int_cb),
354 ENGINE_PILE_DOALL, &dall);