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