1109998Smarkm/* ==================================================================== 2109998Smarkm * Copyright (c) 2001 The OpenSSL Project. All rights reserved. 3109998Smarkm * 4109998Smarkm * Redistribution and use in source and binary forms, with or without 5109998Smarkm * modification, are permitted provided that the following conditions 6109998Smarkm * are met: 7109998Smarkm * 8109998Smarkm * 1. Redistributions of source code must retain the above copyright 9109998Smarkm * notice, this list of conditions and the following disclaimer. 10109998Smarkm * 11109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright 12109998Smarkm * notice, this list of conditions and the following disclaimer in 13109998Smarkm * the documentation and/or other materials provided with the 14109998Smarkm * distribution. 15109998Smarkm * 16109998Smarkm * 3. All advertising materials mentioning features or use of this 17109998Smarkm * software must display the following acknowledgment: 18109998Smarkm * "This product includes software developed by the OpenSSL Project 19109998Smarkm * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 20109998Smarkm * 21109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 22109998Smarkm * endorse or promote products derived from this software without 23109998Smarkm * prior written permission. For written permission, please contact 24109998Smarkm * licensing@OpenSSL.org. 25109998Smarkm * 26109998Smarkm * 5. Products derived from this software may not be called "OpenSSL" 27109998Smarkm * nor may "OpenSSL" appear in their names without prior written 28109998Smarkm * permission of the OpenSSL Project. 29109998Smarkm * 30109998Smarkm * 6. Redistributions of any form whatsoever must retain the following 31109998Smarkm * acknowledgment: 32109998Smarkm * "This product includes software developed by the OpenSSL Project 33109998Smarkm * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 34109998Smarkm * 35109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 36109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 37109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 38109998Smarkm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 39109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 41109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 42109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 43109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 44109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 45109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 46109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE. 47109998Smarkm * ==================================================================== 48109998Smarkm * 49109998Smarkm * This product includes cryptographic software written by Eric Young 50109998Smarkm * (eay@cryptsoft.com). This product includes software written by Tim 51109998Smarkm * Hudson (tjh@cryptsoft.com). 52109998Smarkm * 53109998Smarkm */ 54109998Smarkm 55160814Ssimon#include "cryptlib.h" 56109998Smarkm#include <openssl/evp.h> 57160814Ssimon#include <openssl/lhash.h> 58109998Smarkm#include "eng_int.h" 59109998Smarkm 60109998Smarkm/* The type of the items in the table */ 61109998Smarkmtypedef struct st_engine_pile 62109998Smarkm { 63160814Ssimon /* The 'nid' of this algorithm/mode */ 64109998Smarkm int nid; 65160814Ssimon /* ENGINEs that implement this algorithm/mode. */ 66109998Smarkm STACK_OF(ENGINE) *sk; 67109998Smarkm /* The default ENGINE to perform this algorithm/mode. */ 68109998Smarkm ENGINE *funct; 69160814Ssimon /* Zero if 'sk' is newer than the cached 'funct', non-zero otherwise */ 70109998Smarkm int uptodate; 71109998Smarkm } ENGINE_PILE; 72109998Smarkm 73238405SjkimDECLARE_LHASH_OF(ENGINE_PILE); 74238405Sjkim 75160814Ssimon/* The type exposed in eng_int.h */ 76109998Smarkmstruct st_engine_table 77109998Smarkm { 78238405Sjkim LHASH_OF(ENGINE_PILE) piles; 79109998Smarkm }; /* ENGINE_TABLE */ 80109998Smarkm 81238405Sjkim 82238405Sjkimtypedef struct st_engine_pile_doall 83238405Sjkim { 84238405Sjkim engine_table_doall_cb *cb; 85238405Sjkim void *arg; 86238405Sjkim } ENGINE_PILE_DOALL; 87238405Sjkim 88238405Sjkim 89160814Ssimon/* Global flags (ENGINE_TABLE_FLAG_***). */ 90109998Smarkmstatic unsigned int table_flags = 0; 91109998Smarkm 92109998Smarkm/* API function manipulating 'table_flags' */ 93109998Smarkmunsigned int ENGINE_get_table_flags(void) 94109998Smarkm { 95109998Smarkm return table_flags; 96109998Smarkm } 97238405Sjkim 98109998Smarkmvoid ENGINE_set_table_flags(unsigned int flags) 99109998Smarkm { 100109998Smarkm table_flags = flags; 101109998Smarkm } 102109998Smarkm 103109998Smarkm/* Internal functions for the "piles" hash table */ 104109998Smarkmstatic unsigned long engine_pile_hash(const ENGINE_PILE *c) 105109998Smarkm { 106109998Smarkm return c->nid; 107109998Smarkm } 108238405Sjkim 109109998Smarkmstatic int engine_pile_cmp(const ENGINE_PILE *a, const ENGINE_PILE *b) 110109998Smarkm { 111109998Smarkm return a->nid - b->nid; 112109998Smarkm } 113238405Sjkimstatic IMPLEMENT_LHASH_HASH_FN(engine_pile, ENGINE_PILE) 114238405Sjkimstatic IMPLEMENT_LHASH_COMP_FN(engine_pile, ENGINE_PILE) 115238405Sjkim 116109998Smarkmstatic int int_table_check(ENGINE_TABLE **t, int create) 117109998Smarkm { 118238405Sjkim LHASH_OF(ENGINE_PILE) *lh; 119238405Sjkim 120160814Ssimon if(*t) return 1; 121160814Ssimon if(!create) return 0; 122238405Sjkim if((lh = lh_ENGINE_PILE_new()) == NULL) 123109998Smarkm return 0; 124109998Smarkm *t = (ENGINE_TABLE *)lh; 125109998Smarkm return 1; 126109998Smarkm } 127109998Smarkm 128109998Smarkm/* Privately exposed (via eng_int.h) functions for adding and/or removing 129109998Smarkm * ENGINEs from the implementation table */ 130109998Smarkmint engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup, 131109998Smarkm ENGINE *e, const int *nids, int num_nids, int setdefault) 132109998Smarkm { 133109998Smarkm int ret = 0, added = 0; 134109998Smarkm ENGINE_PILE tmplate, *fnd; 135109998Smarkm CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 136109998Smarkm if(!(*table)) 137109998Smarkm added = 1; 138109998Smarkm if(!int_table_check(table, 1)) 139109998Smarkm goto end; 140109998Smarkm if(added) 141109998Smarkm /* The cleanup callback needs to be added */ 142109998Smarkm engine_cleanup_add_first(cleanup); 143109998Smarkm while(num_nids--) 144109998Smarkm { 145109998Smarkm tmplate.nid = *nids; 146238405Sjkim fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate); 147109998Smarkm if(!fnd) 148109998Smarkm { 149109998Smarkm fnd = OPENSSL_malloc(sizeof(ENGINE_PILE)); 150160814Ssimon if(!fnd) goto end; 151194206Ssimon fnd->uptodate = 1; 152109998Smarkm fnd->nid = *nids; 153109998Smarkm fnd->sk = sk_ENGINE_new_null(); 154109998Smarkm if(!fnd->sk) 155109998Smarkm { 156109998Smarkm OPENSSL_free(fnd); 157109998Smarkm goto end; 158109998Smarkm } 159160814Ssimon fnd->funct = NULL; 160238405Sjkim (void)lh_ENGINE_PILE_insert(&(*table)->piles, fnd); 161109998Smarkm } 162109998Smarkm /* A registration shouldn't add duplciate entries */ 163194206Ssimon (void)sk_ENGINE_delete_ptr(fnd->sk, e); 164109998Smarkm /* if 'setdefault', this ENGINE goes to the head of the list */ 165109998Smarkm if(!sk_ENGINE_push(fnd->sk, e)) 166109998Smarkm goto end; 167109998Smarkm /* "touch" this ENGINE_PILE */ 168194206Ssimon fnd->uptodate = 0; 169109998Smarkm if(setdefault) 170109998Smarkm { 171109998Smarkm if(!engine_unlocked_init(e)) 172109998Smarkm { 173109998Smarkm ENGINEerr(ENGINE_F_ENGINE_TABLE_REGISTER, 174109998Smarkm ENGINE_R_INIT_FAILED); 175109998Smarkm goto end; 176109998Smarkm } 177109998Smarkm if(fnd->funct) 178109998Smarkm engine_unlocked_finish(fnd->funct, 0); 179109998Smarkm fnd->funct = e; 180194206Ssimon fnd->uptodate = 1; 181109998Smarkm } 182109998Smarkm nids++; 183109998Smarkm } 184109998Smarkm ret = 1; 185109998Smarkmend: 186109998Smarkm CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 187109998Smarkm return ret; 188109998Smarkm } 189238405Sjkimstatic void int_unregister_cb_doall_arg(ENGINE_PILE *pile, ENGINE *e) 190109998Smarkm { 191109998Smarkm int n; 192109998Smarkm /* Iterate the 'c->sk' stack removing any occurance of 'e' */ 193109998Smarkm while((n = sk_ENGINE_find(pile->sk, e)) >= 0) 194109998Smarkm { 195194206Ssimon (void)sk_ENGINE_delete(pile->sk, n); 196194206Ssimon pile->uptodate = 0; 197109998Smarkm } 198109998Smarkm if(pile->funct == e) 199109998Smarkm { 200109998Smarkm engine_unlocked_finish(e, 0); 201109998Smarkm pile->funct = NULL; 202109998Smarkm } 203109998Smarkm } 204238405Sjkimstatic IMPLEMENT_LHASH_DOALL_ARG_FN(int_unregister_cb, ENGINE_PILE, ENGINE) 205238405Sjkim 206109998Smarkmvoid engine_table_unregister(ENGINE_TABLE **table, ENGINE *e) 207109998Smarkm { 208109998Smarkm CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 209109998Smarkm if(int_table_check(table, 0)) 210238405Sjkim lh_ENGINE_PILE_doall_arg(&(*table)->piles, 211238405Sjkim LHASH_DOALL_ARG_FN(int_unregister_cb), 212238405Sjkim ENGINE, e); 213109998Smarkm CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 214109998Smarkm } 215109998Smarkm 216238405Sjkimstatic void int_cleanup_cb_doall(ENGINE_PILE *p) 217109998Smarkm { 218109998Smarkm sk_ENGINE_free(p->sk); 219109998Smarkm if(p->funct) 220109998Smarkm engine_unlocked_finish(p->funct, 0); 221109998Smarkm OPENSSL_free(p); 222109998Smarkm } 223238405Sjkimstatic IMPLEMENT_LHASH_DOALL_FN(int_cleanup_cb, ENGINE_PILE) 224238405Sjkim 225109998Smarkmvoid engine_table_cleanup(ENGINE_TABLE **table) 226109998Smarkm { 227109998Smarkm CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 228109998Smarkm if(*table) 229109998Smarkm { 230238405Sjkim lh_ENGINE_PILE_doall(&(*table)->piles, 231238405Sjkim LHASH_DOALL_FN(int_cleanup_cb)); 232238405Sjkim lh_ENGINE_PILE_free(&(*table)->piles); 233109998Smarkm *table = NULL; 234109998Smarkm } 235109998Smarkm CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 236109998Smarkm } 237109998Smarkm 238160814Ssimon/* return a functional reference for a given 'nid' */ 239109998Smarkm#ifndef ENGINE_TABLE_DEBUG 240109998SmarkmENGINE *engine_table_select(ENGINE_TABLE **table, int nid) 241109998Smarkm#else 242109998SmarkmENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f, int l) 243109998Smarkm#endif 244109998Smarkm { 245109998Smarkm ENGINE *ret = NULL; 246109998Smarkm ENGINE_PILE tmplate, *fnd=NULL; 247109998Smarkm int initres, loop = 0; 248109998Smarkm 249109998Smarkm if(!(*table)) 250109998Smarkm { 251109998Smarkm#ifdef ENGINE_TABLE_DEBUG 252160814Ssimon fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, nothing " 253160814Ssimon "registered!\n", f, l, nid); 254109998Smarkm#endif 255109998Smarkm return NULL; 256109998Smarkm } 257205128Ssimon ERR_set_mark(); 258109998Smarkm CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 259109998Smarkm /* Check again inside the lock otherwise we could race against cleanup 260109998Smarkm * operations. But don't worry about a fprintf(stderr). */ 261160814Ssimon if(!int_table_check(table, 0)) goto end; 262109998Smarkm tmplate.nid = nid; 263238405Sjkim fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate); 264160814Ssimon if(!fnd) goto end; 265109998Smarkm if(fnd->funct && engine_unlocked_init(fnd->funct)) 266109998Smarkm { 267109998Smarkm#ifdef ENGINE_TABLE_DEBUG 268109998Smarkm fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using " 269109998Smarkm "ENGINE '%s' cached\n", f, l, nid, fnd->funct->id); 270109998Smarkm#endif 271109998Smarkm ret = fnd->funct; 272109998Smarkm goto end; 273109998Smarkm } 274109998Smarkm if(fnd->uptodate) 275109998Smarkm { 276109998Smarkm ret = fnd->funct; 277109998Smarkm goto end; 278109998Smarkm } 279109998Smarkmtrynext: 280109998Smarkm ret = sk_ENGINE_value(fnd->sk, loop++); 281109998Smarkm if(!ret) 282109998Smarkm { 283109998Smarkm#ifdef ENGINE_TABLE_DEBUG 284109998Smarkm fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no " 285109998Smarkm "registered implementations would initialise\n", 286109998Smarkm f, l, nid); 287109998Smarkm#endif 288109998Smarkm goto end; 289109998Smarkm } 290160814Ssimon /* Try to initialise the ENGINE? */ 291109998Smarkm if((ret->funct_ref > 0) || !(table_flags & ENGINE_TABLE_FLAG_NOINIT)) 292109998Smarkm initres = engine_unlocked_init(ret); 293109998Smarkm else 294109998Smarkm initres = 0; 295109998Smarkm if(initres) 296109998Smarkm { 297160814Ssimon /* Update 'funct' */ 298109998Smarkm if((fnd->funct != ret) && engine_unlocked_init(ret)) 299109998Smarkm { 300109998Smarkm /* If there was a previous default we release it. */ 301109998Smarkm if(fnd->funct) 302109998Smarkm engine_unlocked_finish(fnd->funct, 0); 303109998Smarkm fnd->funct = ret; 304109998Smarkm#ifdef ENGINE_TABLE_DEBUG 305109998Smarkm fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, " 306109998Smarkm "setting default to '%s'\n", f, l, nid, ret->id); 307109998Smarkm#endif 308109998Smarkm } 309109998Smarkm#ifdef ENGINE_TABLE_DEBUG 310109998Smarkm fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using " 311109998Smarkm "newly initialised '%s'\n", f, l, nid, ret->id); 312109998Smarkm#endif 313109998Smarkm goto end; 314109998Smarkm } 315109998Smarkm goto trynext; 316109998Smarkmend: 317160814Ssimon /* If it failed, it is unlikely to succeed again until some future 318160814Ssimon * registrations have taken place. In all cases, we cache. */ 319160814Ssimon if(fnd) fnd->uptodate = 1; 320109998Smarkm#ifdef ENGINE_TABLE_DEBUG 321109998Smarkm if(ret) 322109998Smarkm fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching " 323109998Smarkm "ENGINE '%s'\n", f, l, nid, ret->id); 324109998Smarkm else 325109998Smarkm fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching " 326109998Smarkm "'no matching ENGINE'\n", f, l, nid); 327109998Smarkm#endif 328109998Smarkm CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 329109998Smarkm /* Whatever happened, any failed init()s are not failures in this 330109998Smarkm * context, so clear our error state. */ 331205128Ssimon ERR_pop_to_mark(); 332109998Smarkm return ret; 333109998Smarkm } 334238405Sjkim 335238405Sjkim/* Table enumeration */ 336238405Sjkim 337238405Sjkimstatic void int_cb_doall_arg(ENGINE_PILE *pile, ENGINE_PILE_DOALL *dall) 338238405Sjkim { 339238405Sjkim dall->cb(pile->nid, pile->sk, pile->funct, dall->arg); 340238405Sjkim } 341238405Sjkimstatic IMPLEMENT_LHASH_DOALL_ARG_FN(int_cb, ENGINE_PILE,ENGINE_PILE_DOALL) 342238405Sjkim 343238405Sjkimvoid engine_table_doall(ENGINE_TABLE *table, engine_table_doall_cb *cb, 344238405Sjkim void *arg) 345238405Sjkim { 346238405Sjkim ENGINE_PILE_DOALL dall; 347238405Sjkim dall.cb = cb; 348238405Sjkim dall.arg = arg; 349238405Sjkim lh_ENGINE_PILE_doall_arg(&table->piles, LHASH_DOALL_ARG_FN(int_cb), 350238405Sjkim ENGINE_PILE_DOALL, &dall); 351238405Sjkim } 352