summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/engine/eng_table.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libcrypto/engine/eng_table.c')
-rw-r--r--src/lib/libcrypto/engine/eng_table.c94
1 files changed, 70 insertions, 24 deletions
diff --git a/src/lib/libcrypto/engine/eng_table.c b/src/lib/libcrypto/engine/eng_table.c
index 8879a267d1..c69a84a8bf 100644
--- a/src/lib/libcrypto/engine/eng_table.c
+++ b/src/lib/libcrypto/engine/eng_table.c
@@ -52,31 +52,49 @@
52 * 52 *
53 */ 53 */
54 54
55#include "cryptlib.h"
56#include <openssl/evp.h> 55#include <openssl/evp.h>
57#include <openssl/lhash.h> 56#include <openssl/engine.h>
58#include "eng_int.h" 57#include "eng_int.h"
59 58
59/* This is the type of item in the 'implementation' table. Each 'nid' hashes to
60 * a (potentially NULL) ENGINE_PILE structure which contains a stack of ENGINE*
61 * pointers. These pointers aren't references, because they're inserted and
62 * removed during ENGINE creation and ENGINE destruction. They point to ENGINEs
63 * that *exist* (ie. have a structural reference count greater than zero) rather
64 * than ENGINEs that are *functional*. Each pointer in those stacks are to
65 * ENGINEs that implements the algorithm corresponding to each 'nid'. */
66
60/* The type of the items in the table */ 67/* The type of the items in the table */
61typedef struct st_engine_pile 68typedef struct st_engine_pile
62 { 69 {
63 /* The 'nid' of this algorithm/mode */ 70 /* The 'nid' of the algorithm/mode this ENGINE_PILE structure represents
71 * */
64 int nid; 72 int nid;
65 /* ENGINEs that implement this algorithm/mode. */ 73 /* A stack of ENGINE pointers for ENGINEs that support this
74 * algorithm/mode. In the event that 'funct' is NULL, the first entry in
75 * this stack that initialises will be set as 'funct' and assumed as the
76 * default for operations of this type. */
66 STACK_OF(ENGINE) *sk; 77 STACK_OF(ENGINE) *sk;
67 /* The default ENGINE to perform this algorithm/mode. */ 78 /* The default ENGINE to perform this algorithm/mode. */
68 ENGINE *funct; 79 ENGINE *funct;
69 /* Zero if 'sk' is newer than the cached 'funct', non-zero otherwise */ 80 /* This value optimises engine_table_select(). If it is called it sets
81 * this value to 1. Any changes to this ENGINE_PILE resets it to zero.
82 * As such, no ENGINE_init() thrashing is done unless ENGINEs
83 * continually register (and/or unregister). */
70 int uptodate; 84 int uptodate;
71 } ENGINE_PILE; 85 } ENGINE_PILE;
72 86
73/* The type exposed in eng_int.h */ 87/* The type of the hash table of ENGINE_PILE structures such that each are
88 * unique and keyed by the 'nid' value. */
74struct st_engine_table 89struct st_engine_table
75 { 90 {
76 LHASH piles; 91 LHASH piles;
77 }; /* ENGINE_TABLE */ 92 }; /* ENGINE_TABLE */
78 93
79/* Global flags (ENGINE_TABLE_FLAG_***). */ 94/* This value stores global options controlling behaviour of (mostly) the
95 * engine_table_select() function. It's a bitmask of flag values of the form
96 * ENGINE_TABLE_FLAG_*** (as defined in engine.h) and is controlled by the
97 * ENGINE_[get|set]_table_flags() function. */
80static unsigned int table_flags = 0; 98static unsigned int table_flags = 0;
81 99
82/* API function manipulating 'table_flags' */ 100/* API function manipulating 'table_flags' */
@@ -103,8 +121,10 @@ static IMPLEMENT_LHASH_COMP_FN(engine_pile_cmp, const ENGINE_PILE *)
103static int int_table_check(ENGINE_TABLE **t, int create) 121static int int_table_check(ENGINE_TABLE **t, int create)
104 { 122 {
105 LHASH *lh; 123 LHASH *lh;
106 if(*t) return 1; 124 if(*t)
107 if(!create) return 0; 125 return 1;
126 if(!create)
127 return 0;
108 if((lh = lh_new(LHASH_HASH_FN(engine_pile_hash), 128 if((lh = lh_new(LHASH_HASH_FN(engine_pile_hash),
109 LHASH_COMP_FN(engine_pile_cmp))) == NULL) 129 LHASH_COMP_FN(engine_pile_cmp))) == NULL)
110 return 0; 130 return 0;
@@ -134,7 +154,8 @@ int engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup,
134 if(!fnd) 154 if(!fnd)
135 { 155 {
136 fnd = OPENSSL_malloc(sizeof(ENGINE_PILE)); 156 fnd = OPENSSL_malloc(sizeof(ENGINE_PILE));
137 if(!fnd) goto end; 157 if(!fnd)
158 goto end;
138 fnd->uptodate = 1; 159 fnd->uptodate = 1;
139 fnd->nid = *nids; 160 fnd->nid = *nids;
140 fnd->sk = sk_ENGINE_new_null(); 161 fnd->sk = sk_ENGINE_new_null();
@@ -143,11 +164,11 @@ int engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup,
143 OPENSSL_free(fnd); 164 OPENSSL_free(fnd);
144 goto end; 165 goto end;
145 } 166 }
146 fnd->funct = NULL; 167 fnd->funct= NULL;
147 lh_insert(&(*table)->piles, fnd); 168 lh_insert(&(*table)->piles, fnd);
148 } 169 }
149 /* A registration shouldn't add duplciate entries */ 170 /* A registration shouldn't add duplciate entries */
150 (void)sk_ENGINE_delete_ptr(fnd->sk, e); 171 sk_ENGINE_delete_ptr(fnd->sk, e);
151 /* if 'setdefault', this ENGINE goes to the head of the list */ 172 /* if 'setdefault', this ENGINE goes to the head of the list */
152 if(!sk_ENGINE_push(fnd->sk, e)) 173 if(!sk_ENGINE_push(fnd->sk, e))
153 goto end; 174 goto end;
@@ -164,7 +185,6 @@ int engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup,
164 if(fnd->funct) 185 if(fnd->funct)
165 engine_unlocked_finish(fnd->funct, 0); 186 engine_unlocked_finish(fnd->funct, 0);
166 fnd->funct = e; 187 fnd->funct = e;
167 fnd->uptodate = 1;
168 } 188 }
169 nids++; 189 nids++;
170 } 190 }
@@ -179,7 +199,8 @@ static void int_unregister_cb(ENGINE_PILE *pile, ENGINE *e)
179 /* Iterate the 'c->sk' stack removing any occurance of 'e' */ 199 /* Iterate the 'c->sk' stack removing any occurance of 'e' */
180 while((n = sk_ENGINE_find(pile->sk, e)) >= 0) 200 while((n = sk_ENGINE_find(pile->sk, e)) >= 0)
181 { 201 {
182 (void)sk_ENGINE_delete(pile->sk, n); 202 sk_ENGINE_delete(pile->sk, n);
203 /* "touch" this ENGINE_CIPHER */
183 pile->uptodate = 0; 204 pile->uptodate = 0;
184 } 205 }
185 if(pile->funct == e) 206 if(pile->funct == e)
@@ -218,7 +239,9 @@ void engine_table_cleanup(ENGINE_TABLE **table)
218 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 239 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
219 } 240 }
220 241
221/* return a functional reference for a given 'nid' */ 242/* Exposed API function to get a functional reference from the implementation
243 * table (ie. try to get a functional reference from the tabled structural
244 * references) for a given cipher 'nid' */
222#ifndef ENGINE_TABLE_DEBUG 245#ifndef ENGINE_TABLE_DEBUG
223ENGINE *engine_table_select(ENGINE_TABLE **table, int nid) 246ENGINE *engine_table_select(ENGINE_TABLE **table, int nid)
224#else 247#else
@@ -229,21 +252,25 @@ ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f, in
229 ENGINE_PILE tmplate, *fnd=NULL; 252 ENGINE_PILE tmplate, *fnd=NULL;
230 int initres, loop = 0; 253 int initres, loop = 0;
231 254
255 /* If 'engine_ciphers' is NULL, then it's absolutely *sure* that no
256 * ENGINEs have registered any implementations! */
232 if(!(*table)) 257 if(!(*table))
233 { 258 {
234#ifdef ENGINE_TABLE_DEBUG 259#ifdef ENGINE_TABLE_DEBUG
235 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, nothing " 260 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no "
236 "registered!\n", f, l, nid); 261 "registered for anything!\n", f, l, nid);
237#endif 262#endif
238 return NULL; 263 return NULL;
239 } 264 }
240 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 265 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
241 /* Check again inside the lock otherwise we could race against cleanup 266 /* Check again inside the lock otherwise we could race against cleanup
242 * operations. But don't worry about a fprintf(stderr). */ 267 * operations. But don't worry about a fprintf(stderr). */
243 if(!int_table_check(table, 0)) goto end; 268 if(!int_table_check(table, 0))
269 goto end;
244 tmplate.nid = nid; 270 tmplate.nid = nid;
245 fnd = lh_retrieve(&(*table)->piles, &tmplate); 271 fnd = lh_retrieve(&(*table)->piles, &tmplate);
246 if(!fnd) goto end; 272 if(!fnd)
273 goto end;
247 if(fnd->funct && engine_unlocked_init(fnd->funct)) 274 if(fnd->funct && engine_unlocked_init(fnd->funct))
248 { 275 {
249#ifdef ENGINE_TABLE_DEBUG 276#ifdef ENGINE_TABLE_DEBUG
@@ -269,19 +296,34 @@ trynext:
269#endif 296#endif
270 goto end; 297 goto end;
271 } 298 }
272 /* Try to initialise the ENGINE? */ 299#if 0
300 /* Don't need to get a reference if we hold the lock. If the locking has
301 * to change in future, that would be different ... */
302 ret->struct_ref++; engine_ref_debug(ret, 0, 1)
303#endif
304 /* Try and initialise the ENGINE if it's already functional *or* if the
305 * ENGINE_TABLE_FLAG_NOINIT flag is not set. */
273 if((ret->funct_ref > 0) || !(table_flags & ENGINE_TABLE_FLAG_NOINIT)) 306 if((ret->funct_ref > 0) || !(table_flags & ENGINE_TABLE_FLAG_NOINIT))
274 initres = engine_unlocked_init(ret); 307 initres = engine_unlocked_init(ret);
275 else 308 else
276 initres = 0; 309 initres = 0;
310#if 0
311 /* Release the structural reference */
312 ret->struct_ref--; engine_ref_debug(ret, 0, -1);
313#endif
277 if(initres) 314 if(initres)
278 { 315 {
279 /* Update 'funct' */ 316 /* If we didn't have a default (functional reference) for this
317 * 'nid' (or we had one but for whatever reason we're now
318 * initialising a different one), use this opportunity to set
319 * 'funct'. */
280 if((fnd->funct != ret) && engine_unlocked_init(ret)) 320 if((fnd->funct != ret) && engine_unlocked_init(ret))
281 { 321 {
282 /* If there was a previous default we release it. */ 322 /* If there was a previous default we release it. */
283 if(fnd->funct) 323 if(fnd->funct)
284 engine_unlocked_finish(fnd->funct, 0); 324 engine_unlocked_finish(fnd->funct, 0);
325 /* We got an extra functional reference for the
326 * per-'nid' default */
285 fnd->funct = ret; 327 fnd->funct = ret;
286#ifdef ENGINE_TABLE_DEBUG 328#ifdef ENGINE_TABLE_DEBUG
287 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, " 329 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, "
@@ -296,9 +338,13 @@ trynext:
296 } 338 }
297 goto trynext; 339 goto trynext;
298end: 340end:
299 /* If it failed, it is unlikely to succeed again until some future 341 /* Whatever happened - we should "untouch" our uptodate file seeing as
300 * registrations have taken place. In all cases, we cache. */ 342 * we have tried our best to find a functional reference for 'nid'. If
301 if(fnd) fnd->uptodate = 1; 343 * it failed, it is unlikely to succeed again until some future
344 * registrations (or unregistrations) have taken place that affect that
345 * 'nid'. */
346 if(fnd)
347 fnd->uptodate = 1;
302#ifdef ENGINE_TABLE_DEBUG 348#ifdef ENGINE_TABLE_DEBUG
303 if(ret) 349 if(ret)
304 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching " 350 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "