219253a38acde15d900681534994bd574a2ce54a
[openssl.git] / crypto / engine / eng_table.c
1 /*
2  * Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include "internal/cryptlib.h"
11 #include <openssl/evp.h>
12 #include <openssl/lhash.h>
13 #include "eng_int.h"
14
15 /* The type of the items in the table */
16 struct st_engine_pile {
17     /* The 'nid' of this algorithm/mode */
18     int nid;
19     /* ENGINEs that implement this algorithm/mode. */
20     STACK_OF(ENGINE) *sk;
21     /* The default ENGINE to perform this algorithm/mode. */
22     ENGINE *funct;
23     /*
24      * Zero if 'sk' is newer than the cached 'funct', non-zero otherwise
25      */
26     int uptodate;
27 };
28
29 /* The type exposed in eng_int.h */
30 struct st_engine_table {
31     LHASH_OF(ENGINE_PILE) piles;
32 };                              /* ENGINE_TABLE */
33
34 typedef struct st_engine_pile_doall {
35     engine_table_doall_cb *cb;
36     void *arg;
37 } ENGINE_PILE_DOALL;
38
39 /* Global flags (ENGINE_TABLE_FLAG_***). */
40 static unsigned int table_flags = 0;
41
42 /* API function manipulating 'table_flags' */
43 unsigned int ENGINE_get_table_flags(void)
44 {
45     return table_flags;
46 }
47
48 void ENGINE_set_table_flags(unsigned int flags)
49 {
50     table_flags = flags;
51 }
52
53 /* Internal functions for the "piles" hash table */
54 static unsigned long engine_pile_hash(const ENGINE_PILE *c)
55 {
56     return c->nid;
57 }
58
59 static int engine_pile_cmp(const ENGINE_PILE *a, const ENGINE_PILE *b)
60 {
61     return a->nid - b->nid;
62 }
63
64 static int int_table_check(ENGINE_TABLE **t, int create)
65 {
66     LHASH_OF(ENGINE_PILE) *lh;
67
68     if (*t)
69         return 1;
70     if (!create)
71         return 0;
72     if ((lh = lh_ENGINE_PILE_new(engine_pile_hash, engine_pile_cmp)) == NULL)
73         return 0;
74     *t = (ENGINE_TABLE *)lh;
75     return 1;
76 }
77
78 /*
79  * Privately exposed (via eng_int.h) functions for adding and/or removing
80  * ENGINEs from the implementation table
81  */
82 int engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup,
83                           ENGINE *e, const int *nids, int num_nids,
84                           int setdefault)
85 {
86     int ret = 0, added = 0;
87     ENGINE_PILE tmplate, *fnd;
88     CRYPTO_THREAD_write_lock(global_engine_lock);
89     if (!(*table))
90         added = 1;
91     if (!int_table_check(table, 1))
92         goto end;
93     if (added)
94         /* The cleanup callback needs to be added */
95         engine_cleanup_add_first(cleanup);
96     while (num_nids--) {
97         tmplate.nid = *nids;
98         fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate);
99         if (!fnd) {
100             fnd = OPENSSL_malloc(sizeof(*fnd));
101             if (fnd == NULL)
102                 goto end;
103             fnd->uptodate = 1;
104             fnd->nid = *nids;
105             fnd->sk = sk_ENGINE_new_null();
106             if (!fnd->sk) {
107                 OPENSSL_free(fnd);
108                 goto end;
109             }
110             fnd->funct = NULL;
111             (void)lh_ENGINE_PILE_insert(&(*table)->piles, fnd);
112         }
113         /* A registration shouldn't add duplicate entries */
114         (void)sk_ENGINE_delete_ptr(fnd->sk, e);
115         /*
116          * if 'setdefault', this ENGINE goes to the head of the list
117          */
118         if (!sk_ENGINE_push(fnd->sk, e))
119             goto end;
120         /* "touch" this ENGINE_PILE */
121         fnd->uptodate = 0;
122         if (setdefault) {
123             if (!engine_unlocked_init(e)) {
124                 ENGINEerr(ENGINE_F_ENGINE_TABLE_REGISTER,
125                           ENGINE_R_INIT_FAILED);
126                 goto end;
127             }
128             if (fnd->funct)
129                 engine_unlocked_finish(fnd->funct, 0);
130             fnd->funct = e;
131             fnd->uptodate = 1;
132         }
133         nids++;
134     }
135     ret = 1;
136  end:
137     CRYPTO_THREAD_unlock(global_engine_lock);
138     return ret;
139 }
140
141 static void int_unregister_cb(ENGINE_PILE *pile, ENGINE *e)
142 {
143     int n;
144     /* Iterate the 'c->sk' stack removing any occurrence of 'e' */
145     while ((n = sk_ENGINE_find(pile->sk, e)) >= 0) {
146         (void)sk_ENGINE_delete(pile->sk, n);
147         pile->uptodate = 0;
148     }
149     if (pile->funct == e) {
150         engine_unlocked_finish(e, 0);
151         pile->funct = NULL;
152     }
153 }
154
155 IMPLEMENT_LHASH_DOALL_ARG(ENGINE_PILE, ENGINE);
156
157 void engine_table_unregister(ENGINE_TABLE **table, ENGINE *e)
158 {
159     CRYPTO_THREAD_write_lock(global_engine_lock);
160     if (int_table_check(table, 0))
161         lh_ENGINE_PILE_doall_ENGINE(&(*table)->piles, int_unregister_cb, e);
162     CRYPTO_THREAD_unlock(global_engine_lock);
163 }
164
165 static void int_cleanup_cb_doall(ENGINE_PILE *p)
166 {
167     if (!p)
168         return;
169     sk_ENGINE_free(p->sk);
170     if (p->funct)
171         engine_unlocked_finish(p->funct, 0);
172     OPENSSL_free(p);
173 }
174
175 void engine_table_cleanup(ENGINE_TABLE **table)
176 {
177     CRYPTO_THREAD_write_lock(global_engine_lock);
178     if (*table) {
179         lh_ENGINE_PILE_doall(&(*table)->piles, int_cleanup_cb_doall);
180         lh_ENGINE_PILE_free(&(*table)->piles);
181         *table = NULL;
182     }
183     CRYPTO_THREAD_unlock(global_engine_lock);
184 }
185
186 /* return a functional reference for a given 'nid' */
187 #ifndef ENGINE_TABLE_DEBUG
188 ENGINE *engine_table_select(ENGINE_TABLE **table, int nid)
189 #else
190 ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f,
191                                 int l)
192 #endif
193 {
194     ENGINE *ret = NULL;
195     ENGINE_PILE tmplate, *fnd = NULL;
196     int initres, loop = 0;
197
198     if (!(*table)) {
199 #ifdef ENGINE_TABLE_DEBUG
200         fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, nothing "
201                 "registered!\n", f, l, nid);
202 #endif
203         return NULL;
204     }
205     ERR_set_mark();
206     CRYPTO_THREAD_write_lock(global_engine_lock);
207     /*
208      * Check again inside the lock otherwise we could race against cleanup
209      * operations. But don't worry about a fprintf(stderr).
210      */
211     if (!int_table_check(table, 0))
212         goto end;
213     tmplate.nid = nid;
214     fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate);
215     if (!fnd)
216         goto end;
217     if (fnd->funct && engine_unlocked_init(fnd->funct)) {
218 #ifdef ENGINE_TABLE_DEBUG
219         fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
220                 "ENGINE '%s' cached\n", f, l, nid, fnd->funct->id);
221 #endif
222         ret = fnd->funct;
223         goto end;
224     }
225     if (fnd->uptodate) {
226         ret = fnd->funct;
227         goto end;
228     }
229  trynext:
230     ret = sk_ENGINE_value(fnd->sk, loop++);
231     if (!ret) {
232 #ifdef ENGINE_TABLE_DEBUG
233         fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no "
234                 "registered implementations would initialise\n", f, l, nid);
235 #endif
236         goto end;
237     }
238     /* Try to initialise the ENGINE? */
239     if ((ret->funct_ref > 0) || !(table_flags & ENGINE_TABLE_FLAG_NOINIT))
240         initres = engine_unlocked_init(ret);
241     else
242         initres = 0;
243     if (initres) {
244         /* Update 'funct' */
245         if ((fnd->funct != ret) && engine_unlocked_init(ret)) {
246             /* If there was a previous default we release it. */
247             if (fnd->funct)
248                 engine_unlocked_finish(fnd->funct, 0);
249             fnd->funct = ret;
250 #ifdef ENGINE_TABLE_DEBUG
251             fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, "
252                     "setting default to '%s'\n", f, l, nid, ret->id);
253 #endif
254         }
255 #ifdef ENGINE_TABLE_DEBUG
256         fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
257                 "newly initialised '%s'\n", f, l, nid, ret->id);
258 #endif
259         goto end;
260     }
261     goto trynext;
262  end:
263     /*
264      * If it failed, it is unlikely to succeed again until some future
265      * registrations have taken place. In all cases, we cache.
266      */
267     if (fnd)
268         fnd->uptodate = 1;
269 #ifdef ENGINE_TABLE_DEBUG
270     if (ret)
271         fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
272                 "ENGINE '%s'\n", f, l, nid, ret->id);
273     else
274         fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
275                 "'no matching ENGINE'\n", f, l, nid);
276 #endif
277     CRYPTO_THREAD_unlock(global_engine_lock);
278     /*
279      * Whatever happened, any failed init()s are not failures in this
280      * context, so clear our error state.
281      */
282     ERR_pop_to_mark();
283     return ret;
284 }
285
286 /* Table enumeration */
287
288 static void int_dall(const ENGINE_PILE *pile, ENGINE_PILE_DOALL *dall)
289 {
290     dall->cb(pile->nid, pile->sk, pile->funct, dall->arg);
291 }
292
293 IMPLEMENT_LHASH_DOALL_ARG_CONST(ENGINE_PILE, ENGINE_PILE_DOALL);
294
295 void engine_table_doall(ENGINE_TABLE *table, engine_table_doall_cb *cb,
296                         void *arg)
297 {
298     ENGINE_PILE_DOALL dall;
299     dall.cb = cb;
300     dall.arg = arg;
301     if (table)
302         lh_ENGINE_PILE_doall_ENGINE_PILE_DOALL(&table->piles, int_dall, &dall);
303 }