diff options
Diffstat (limited to 'src/lib/libcrypto/engine/eng_table.c')
-rw-r--r-- | src/lib/libcrypto/engine/eng_table.c | 94 |
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 */ |
61 | typedef struct st_engine_pile | 68 | typedef 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. */ | ||
74 | struct st_engine_table | 89 | struct 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. */ | ||
80 | static unsigned int table_flags = 0; | 98 | static 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 *) | |||
103 | static int int_table_check(ENGINE_TABLE **t, int create) | 121 | static 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 |
223 | ENGINE *engine_table_select(ENGINE_TABLE **table, int nid) | 246 | ENGINE *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; |
298 | end: | 340 | end: |
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 " |