eng_table.c revision 109998
1106106Sjmallett/* ==================================================================== 2106106Sjmallett * Copyright (c) 2001 The OpenSSL Project. All rights reserved. 3106106Sjmallett * 4106106Sjmallett * Redistribution and use in source and binary forms, with or without 5106106Sjmallett * modification, are permitted provided that the following conditions 6106106Sjmallett * are met: 7106106Sjmallett * 8106106Sjmallett * 1. Redistributions of source code must retain the above copyright 9106106Sjmallett * notice, this list of conditions and the following disclaimer. 10106106Sjmallett * 11106106Sjmallett * 2. Redistributions in binary form must reproduce the above copyright 12106106Sjmallett * notice, this list of conditions and the following disclaimer in 13106106Sjmallett * the documentation and/or other materials provided with the 14106106Sjmallett * distribution. 15106106Sjmallett * 16106106Sjmallett * 3. All advertising materials mentioning features or use of this 17106106Sjmallett * software must display the following acknowledgment: 18106106Sjmallett * "This product includes software developed by the OpenSSL Project 19106106Sjmallett * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 20106106Sjmallett * 21106106Sjmallett * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 22106106Sjmallett * endorse or promote products derived from this software without 23106106Sjmallett * prior written permission. For written permission, please contact 24106106Sjmallett * licensing@OpenSSL.org. 25106106Sjmallett * 26106106Sjmallett * 5. Products derived from this software may not be called "OpenSSL" 27106106Sjmallett * nor may "OpenSSL" appear in their names without prior written 28106106Sjmallett * permission of the OpenSSL Project. 29106106Sjmallett * 30106106Sjmallett * 6. Redistributions of any form whatsoever must retain the following 31106106Sjmallett * acknowledgment: 32106106Sjmallett * "This product includes software developed by the OpenSSL Project 33106106Sjmallett * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 34106106Sjmallett * 35106106Sjmallett * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 36106106Sjmallett * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 37106106Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 38106106Sjmallett * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 39106106Sjmallett * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40106106Sjmallett * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 41106106Sjmallett * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 42141104Sharti * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 43141104Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 44141104Sharti * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 45141104Sharti * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 46141133Sharti * OF THE POSSIBILITY OF SUCH DAMAGE. 47141104Sharti * ==================================================================== 48146047Sharti * 49146047Sharti * This product includes cryptographic software written by Eric Young 50146047Sharti * (eay@cryptsoft.com). This product includes software written by Tim 51146047Sharti * Hudson (tjh@cryptsoft.com). 52146047Sharti * 53146047Sharti */ 54146062Sharti 55146062Sharti#include <openssl/evp.h> 56146062Sharti#include <openssl/engine.h> 57146062Sharti#include "eng_int.h" 58146062Sharti 59146062Sharti/* This is the type of item in the 'implementation' table. Each 'nid' hashes to 60146134Sharti * a (potentially NULL) ENGINE_PILE structure which contains a stack of ENGINE* 61146134Sharti * pointers. These pointers aren't references, because they're inserted and 62146134Sharti * removed during ENGINE creation and ENGINE destruction. They point to ENGINEs 63146134Sharti * that *exist* (ie. have a structural reference count greater than zero) rather 64146134Sharti * than ENGINEs that are *functional*. Each pointer in those stacks are to 65146134Sharti * ENGINEs that implements the algorithm corresponding to each 'nid'. */ 66146062Sharti 67146062Sharti/* The type of the items in the table */ 68146062Shartitypedef struct st_engine_pile 69143963Sharti { 70143963Sharti /* The 'nid' of the algorithm/mode this ENGINE_PILE structure represents 71146039Sharti * */ 72143963Sharti int nid; 73145971Sharti /* A stack of ENGINE pointers for ENGINEs that support this 74146038Sharti * algorithm/mode. In the event that 'funct' is NULL, the first entry in 75143963Sharti * this stack that initialises will be set as 'funct' and assumed as the 76143963Sharti * default for operations of this type. */ 77145971Sharti STACK_OF(ENGINE) *sk; 78146027Sharti /* The default ENGINE to perform this algorithm/mode. */ 79146048Sharti ENGINE *funct; 80143963Sharti /* This value optimises engine_table_select(). If it is called it sets 81106106Sjmallett * this value to 1. Any changes to this ENGINE_PILE resets it to zero. 82141104Sharti * As such, no ENGINE_init() thrashing is done unless ENGINEs 83 * continually register (and/or unregister). */ 84 int uptodate; 85 } ENGINE_PILE; 86 87/* The type of the hash table of ENGINE_PILE structures such that each are 88 * unique and keyed by the 'nid' value. */ 89struct st_engine_table 90 { 91 LHASH piles; 92 }; /* ENGINE_TABLE */ 93 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. */ 98static unsigned int table_flags = 0; 99 100/* API function manipulating 'table_flags' */ 101unsigned int ENGINE_get_table_flags(void) 102 { 103 return table_flags; 104 } 105void ENGINE_set_table_flags(unsigned int flags) 106 { 107 table_flags = flags; 108 } 109 110/* Internal functions for the "piles" hash table */ 111static unsigned long engine_pile_hash(const ENGINE_PILE *c) 112 { 113 return c->nid; 114 } 115static int engine_pile_cmp(const ENGINE_PILE *a, const ENGINE_PILE *b) 116 { 117 return a->nid - b->nid; 118 } 119static IMPLEMENT_LHASH_HASH_FN(engine_pile_hash, const ENGINE_PILE *) 120static IMPLEMENT_LHASH_COMP_FN(engine_pile_cmp, const ENGINE_PILE *) 121static int int_table_check(ENGINE_TABLE **t, int create) 122 { 123 LHASH *lh; 124 if(*t) 125 return 1; 126 if(!create) 127 return 0; 128 if((lh = lh_new(LHASH_HASH_FN(engine_pile_hash), 129 LHASH_COMP_FN(engine_pile_cmp))) == NULL) 130 return 0; 131 *t = (ENGINE_TABLE *)lh; 132 return 1; 133 } 134 135/* Privately exposed (via eng_int.h) functions for adding and/or removing 136 * ENGINEs from the implementation table */ 137int engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup, 138 ENGINE *e, const int *nids, int num_nids, int setdefault) 139 { 140 int ret = 0, added = 0; 141 ENGINE_PILE tmplate, *fnd; 142 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 143 if(!(*table)) 144 added = 1; 145 if(!int_table_check(table, 1)) 146 goto end; 147 if(added) 148 /* The cleanup callback needs to be added */ 149 engine_cleanup_add_first(cleanup); 150 while(num_nids--) 151 { 152 tmplate.nid = *nids; 153 fnd = lh_retrieve(&(*table)->piles, &tmplate); 154 if(!fnd) 155 { 156 fnd = OPENSSL_malloc(sizeof(ENGINE_PILE)); 157 if(!fnd) 158 goto end; 159 fnd->uptodate = 1; 160 fnd->nid = *nids; 161 fnd->sk = sk_ENGINE_new_null(); 162 if(!fnd->sk) 163 { 164 OPENSSL_free(fnd); 165 goto end; 166 } 167 fnd->funct= NULL; 168 lh_insert(&(*table)->piles, fnd); 169 } 170 /* A registration shouldn't add duplciate entries */ 171 sk_ENGINE_delete_ptr(fnd->sk, e); 172 /* if 'setdefault', this ENGINE goes to the head of the list */ 173 if(!sk_ENGINE_push(fnd->sk, e)) 174 goto end; 175 /* "touch" this ENGINE_PILE */ 176 fnd->uptodate = 0; 177 if(setdefault) 178 { 179 if(!engine_unlocked_init(e)) 180 { 181 ENGINEerr(ENGINE_F_ENGINE_TABLE_REGISTER, 182 ENGINE_R_INIT_FAILED); 183 goto end; 184 } 185 if(fnd->funct) 186 engine_unlocked_finish(fnd->funct, 0); 187 fnd->funct = e; 188 } 189 nids++; 190 } 191 ret = 1; 192end: 193 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 194 return ret; 195 } 196static void int_unregister_cb(ENGINE_PILE *pile, ENGINE *e) 197 { 198 int n; 199 /* Iterate the 'c->sk' stack removing any occurance of 'e' */ 200 while((n = sk_ENGINE_find(pile->sk, e)) >= 0) 201 { 202 sk_ENGINE_delete(pile->sk, n); 203 /* "touch" this ENGINE_CIPHER */ 204 pile->uptodate = 0; 205 } 206 if(pile->funct == e) 207 { 208 engine_unlocked_finish(e, 0); 209 pile->funct = NULL; 210 } 211 } 212static IMPLEMENT_LHASH_DOALL_ARG_FN(int_unregister_cb,ENGINE_PILE *,ENGINE *) 213void engine_table_unregister(ENGINE_TABLE **table, ENGINE *e) 214 { 215 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 216 if(int_table_check(table, 0)) 217 lh_doall_arg(&(*table)->piles, 218 LHASH_DOALL_ARG_FN(int_unregister_cb), e); 219 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 220 } 221 222static void int_cleanup_cb(ENGINE_PILE *p) 223 { 224 sk_ENGINE_free(p->sk); 225 if(p->funct) 226 engine_unlocked_finish(p->funct, 0); 227 OPENSSL_free(p); 228 } 229static IMPLEMENT_LHASH_DOALL_FN(int_cleanup_cb,ENGINE_PILE *) 230void engine_table_cleanup(ENGINE_TABLE **table) 231 { 232 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 233 if(*table) 234 { 235 lh_doall(&(*table)->piles, LHASH_DOALL_FN(int_cleanup_cb)); 236 lh_free(&(*table)->piles); 237 *table = NULL; 238 } 239 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 240 } 241 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' */ 245#ifndef ENGINE_TABLE_DEBUG 246ENGINE *engine_table_select(ENGINE_TABLE **table, int nid) 247#else 248ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f, int l) 249#endif 250 { 251 ENGINE *ret = NULL; 252 ENGINE_PILE tmplate, *fnd=NULL; 253 int initres, loop = 0; 254 255 /* If 'engine_ciphers' is NULL, then it's absolutely *sure* that no 256 * ENGINEs have registered any implementations! */ 257 if(!(*table)) 258 { 259#ifdef ENGINE_TABLE_DEBUG 260 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no " 261 "registered for anything!\n", f, l, nid); 262#endif 263 return NULL; 264 } 265 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 266 /* Check again inside the lock otherwise we could race against cleanup 267 * operations. But don't worry about a fprintf(stderr). */ 268 if(!int_table_check(table, 0)) 269 goto end; 270 tmplate.nid = nid; 271 fnd = lh_retrieve(&(*table)->piles, &tmplate); 272 if(!fnd) 273 goto end; 274 if(fnd->funct && engine_unlocked_init(fnd->funct)) 275 { 276#ifdef ENGINE_TABLE_DEBUG 277 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using " 278 "ENGINE '%s' cached\n", f, l, nid, fnd->funct->id); 279#endif 280 ret = fnd->funct; 281 goto end; 282 } 283 if(fnd->uptodate) 284 { 285 ret = fnd->funct; 286 goto end; 287 } 288trynext: 289 ret = sk_ENGINE_value(fnd->sk, loop++); 290 if(!ret) 291 { 292#ifdef ENGINE_TABLE_DEBUG 293 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no " 294 "registered implementations would initialise\n", 295 f, l, nid); 296#endif 297 goto end; 298 } 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. */ 306 if((ret->funct_ref > 0) || !(table_flags & ENGINE_TABLE_FLAG_NOINIT)) 307 initres = engine_unlocked_init(ret); 308 else 309 initres = 0; 310#if 0 311 /* Release the structural reference */ 312 ret->struct_ref--; engine_ref_debug(ret, 0, -1); 313#endif 314 if(initres) 315 { 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'. */ 320 if((fnd->funct != ret) && engine_unlocked_init(ret)) 321 { 322 /* If there was a previous default we release it. */ 323 if(fnd->funct) 324 engine_unlocked_finish(fnd->funct, 0); 325 /* We got an extra functional reference for the 326 * per-'nid' default */ 327 fnd->funct = ret; 328#ifdef ENGINE_TABLE_DEBUG 329 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, " 330 "setting default to '%s'\n", f, l, nid, ret->id); 331#endif 332 } 333#ifdef ENGINE_TABLE_DEBUG 334 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using " 335 "newly initialised '%s'\n", f, l, nid, ret->id); 336#endif 337 goto end; 338 } 339 goto trynext; 340end: 341 /* Whatever happened - we should "untouch" our uptodate file seeing as 342 * we have tried our best to find a functional reference for 'nid'. If 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; 348#ifdef ENGINE_TABLE_DEBUG 349 if(ret) 350 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching " 351 "ENGINE '%s'\n", f, l, nid, ret->id); 352 else 353 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching " 354 "'no matching ENGINE'\n", f, l, nid); 355#endif 356 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 357 /* Whatever happened, any failed init()s are not failures in this 358 * context, so clear our error state. */ 359 ERR_clear_error(); 360 return ret; 361 } 362