1109998Smarkm/* ==================================================================== 2331638Sjkim * Copyright (c) 2001-2018 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 9280297Sjkim * 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 */ 61280297Sjkimtypedef struct st_engine_pile { 62280297Sjkim /* The 'nid' of this algorithm/mode */ 63280297Sjkim int nid; 64280297Sjkim /* ENGINEs that implement this algorithm/mode. */ 65280297Sjkim STACK_OF(ENGINE) *sk; 66280297Sjkim /* The default ENGINE to perform this algorithm/mode. */ 67280297Sjkim ENGINE *funct; 68280297Sjkim /* 69280297Sjkim * Zero if 'sk' is newer than the cached 'funct', non-zero otherwise 70280297Sjkim */ 71280297Sjkim int uptodate; 72280297Sjkim} ENGINE_PILE; 73109998Smarkm 74238405SjkimDECLARE_LHASH_OF(ENGINE_PILE); 75238405Sjkim 76160814Ssimon/* The type exposed in eng_int.h */ 77280297Sjkimstruct st_engine_table { 78280297Sjkim LHASH_OF(ENGINE_PILE) piles; 79280297Sjkim}; /* ENGINE_TABLE */ 80109998Smarkm 81280297Sjkimtypedef struct st_engine_pile_doall { 82280297Sjkim engine_table_doall_cb *cb; 83280297Sjkim void *arg; 84280297Sjkim} ENGINE_PILE_DOALL; 85238405Sjkim 86160814Ssimon/* Global flags (ENGINE_TABLE_FLAG_***). */ 87109998Smarkmstatic unsigned int table_flags = 0; 88109998Smarkm 89109998Smarkm/* API function manipulating 'table_flags' */ 90109998Smarkmunsigned int ENGINE_get_table_flags(void) 91280297Sjkim{ 92280297Sjkim return table_flags; 93280297Sjkim} 94238405Sjkim 95109998Smarkmvoid ENGINE_set_table_flags(unsigned int flags) 96280297Sjkim{ 97280297Sjkim table_flags = flags; 98280297Sjkim} 99109998Smarkm 100109998Smarkm/* Internal functions for the "piles" hash table */ 101109998Smarkmstatic unsigned long engine_pile_hash(const ENGINE_PILE *c) 102280297Sjkim{ 103280297Sjkim return c->nid; 104280297Sjkim} 105238405Sjkim 106109998Smarkmstatic int engine_pile_cmp(const ENGINE_PILE *a, const ENGINE_PILE *b) 107280297Sjkim{ 108280297Sjkim return a->nid - b->nid; 109280297Sjkim} 110280297Sjkim 111238405Sjkimstatic IMPLEMENT_LHASH_HASH_FN(engine_pile, ENGINE_PILE) 112238405Sjkimstatic IMPLEMENT_LHASH_COMP_FN(engine_pile, ENGINE_PILE) 113238405Sjkim 114109998Smarkmstatic int int_table_check(ENGINE_TABLE **t, int create) 115280297Sjkim{ 116280297Sjkim LHASH_OF(ENGINE_PILE) *lh; 117238405Sjkim 118280297Sjkim if (*t) 119280297Sjkim return 1; 120280297Sjkim if (!create) 121280297Sjkim return 0; 122280297Sjkim if ((lh = lh_ENGINE_PILE_new()) == NULL) 123280297Sjkim return 0; 124280297Sjkim *t = (ENGINE_TABLE *)lh; 125280297Sjkim return 1; 126280297Sjkim} 127109998Smarkm 128280297Sjkim/* 129280297Sjkim * Privately exposed (via eng_int.h) functions for adding and/or removing 130280297Sjkim * ENGINEs from the implementation table 131280297Sjkim */ 132109998Smarkmint engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup, 133280297Sjkim ENGINE *e, const int *nids, int num_nids, 134280297Sjkim int setdefault) 135280297Sjkim{ 136280297Sjkim int ret = 0, added = 0; 137280297Sjkim ENGINE_PILE tmplate, *fnd; 138280297Sjkim CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 139280297Sjkim if (!(*table)) 140280297Sjkim added = 1; 141280297Sjkim if (!int_table_check(table, 1)) 142280297Sjkim goto end; 143280297Sjkim if (added) 144280297Sjkim /* The cleanup callback needs to be added */ 145280297Sjkim engine_cleanup_add_first(cleanup); 146280297Sjkim while (num_nids--) { 147280297Sjkim tmplate.nid = *nids; 148280297Sjkim fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate); 149280297Sjkim if (!fnd) { 150280297Sjkim fnd = OPENSSL_malloc(sizeof(ENGINE_PILE)); 151280297Sjkim if (!fnd) 152280297Sjkim goto end; 153280297Sjkim fnd->uptodate = 1; 154280297Sjkim fnd->nid = *nids; 155280297Sjkim fnd->sk = sk_ENGINE_new_null(); 156280297Sjkim if (!fnd->sk) { 157280297Sjkim OPENSSL_free(fnd); 158280297Sjkim goto end; 159280297Sjkim } 160280297Sjkim fnd->funct = NULL; 161280297Sjkim (void)lh_ENGINE_PILE_insert(&(*table)->piles, fnd); 162331638Sjkim if (lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate) != fnd) { 163331638Sjkim sk_ENGINE_free(fnd->sk); 164331638Sjkim OPENSSL_free(fnd); 165331638Sjkim goto end; 166331638Sjkim } 167280297Sjkim } 168280297Sjkim /* A registration shouldn't add duplciate entries */ 169280297Sjkim (void)sk_ENGINE_delete_ptr(fnd->sk, e); 170280297Sjkim /* 171280297Sjkim * if 'setdefault', this ENGINE goes to the head of the list 172280297Sjkim */ 173280297Sjkim if (!sk_ENGINE_push(fnd->sk, e)) 174280297Sjkim goto end; 175280297Sjkim /* "touch" this ENGINE_PILE */ 176280297Sjkim fnd->uptodate = 0; 177280297Sjkim if (setdefault) { 178280297Sjkim if (!engine_unlocked_init(e)) { 179280297Sjkim ENGINEerr(ENGINE_F_ENGINE_TABLE_REGISTER, 180280297Sjkim ENGINE_R_INIT_FAILED); 181280297Sjkim goto end; 182280297Sjkim } 183280297Sjkim if (fnd->funct) 184280297Sjkim engine_unlocked_finish(fnd->funct, 0); 185280297Sjkim fnd->funct = e; 186280297Sjkim fnd->uptodate = 1; 187280297Sjkim } 188280297Sjkim nids++; 189280297Sjkim } 190280297Sjkim ret = 1; 191280297Sjkim end: 192280297Sjkim CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 193280297Sjkim return ret; 194280297Sjkim} 195280297Sjkim 196238405Sjkimstatic void int_unregister_cb_doall_arg(ENGINE_PILE *pile, ENGINE *e) 197280297Sjkim{ 198280297Sjkim int n; 199280297Sjkim /* Iterate the 'c->sk' stack removing any occurance of 'e' */ 200280297Sjkim while ((n = sk_ENGINE_find(pile->sk, e)) >= 0) { 201280297Sjkim (void)sk_ENGINE_delete(pile->sk, n); 202280297Sjkim pile->uptodate = 0; 203280297Sjkim } 204280297Sjkim if (pile->funct == e) { 205280297Sjkim engine_unlocked_finish(e, 0); 206280297Sjkim pile->funct = NULL; 207280297Sjkim } 208280297Sjkim} 209280297Sjkim 210238405Sjkimstatic IMPLEMENT_LHASH_DOALL_ARG_FN(int_unregister_cb, ENGINE_PILE, ENGINE) 211238405Sjkim 212109998Smarkmvoid engine_table_unregister(ENGINE_TABLE **table, ENGINE *e) 213280297Sjkim{ 214280297Sjkim CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 215280297Sjkim if (int_table_check(table, 0)) 216280297Sjkim lh_ENGINE_PILE_doall_arg(&(*table)->piles, 217280297Sjkim LHASH_DOALL_ARG_FN(int_unregister_cb), 218280297Sjkim ENGINE, e); 219280297Sjkim CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 220280297Sjkim} 221109998Smarkm 222238405Sjkimstatic void int_cleanup_cb_doall(ENGINE_PILE *p) 223280297Sjkim{ 224280297Sjkim sk_ENGINE_free(p->sk); 225280297Sjkim if (p->funct) 226280297Sjkim engine_unlocked_finish(p->funct, 0); 227280297Sjkim OPENSSL_free(p); 228280297Sjkim} 229280297Sjkim 230238405Sjkimstatic IMPLEMENT_LHASH_DOALL_FN(int_cleanup_cb, ENGINE_PILE) 231238405Sjkim 232109998Smarkmvoid engine_table_cleanup(ENGINE_TABLE **table) 233280297Sjkim{ 234280297Sjkim CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 235280297Sjkim if (*table) { 236280297Sjkim lh_ENGINE_PILE_doall(&(*table)->piles, 237280297Sjkim LHASH_DOALL_FN(int_cleanup_cb)); 238280297Sjkim lh_ENGINE_PILE_free(&(*table)->piles); 239280297Sjkim *table = NULL; 240280297Sjkim } 241280297Sjkim CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 242280297Sjkim} 243109998Smarkm 244160814Ssimon/* return a functional reference for a given 'nid' */ 245109998Smarkm#ifndef ENGINE_TABLE_DEBUG 246109998SmarkmENGINE *engine_table_select(ENGINE_TABLE **table, int nid) 247109998Smarkm#else 248280297SjkimENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f, 249280297Sjkim int l) 250109998Smarkm#endif 251280297Sjkim{ 252280297Sjkim ENGINE *ret = NULL; 253280297Sjkim ENGINE_PILE tmplate, *fnd = NULL; 254280297Sjkim int initres, loop = 0; 255109998Smarkm 256280297Sjkim if (!(*table)) { 257109998Smarkm#ifdef ENGINE_TABLE_DEBUG 258280297Sjkim fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, nothing " 259280297Sjkim "registered!\n", f, l, nid); 260109998Smarkm#endif 261280297Sjkim return NULL; 262280297Sjkim } 263280297Sjkim ERR_set_mark(); 264280297Sjkim CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 265280297Sjkim /* 266280297Sjkim * Check again inside the lock otherwise we could race against cleanup 267280297Sjkim * operations. But don't worry about a fprintf(stderr). 268280297Sjkim */ 269280297Sjkim if (!int_table_check(table, 0)) 270280297Sjkim goto end; 271280297Sjkim tmplate.nid = nid; 272280297Sjkim fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate); 273280297Sjkim if (!fnd) 274280297Sjkim goto end; 275280297Sjkim if (fnd->funct && engine_unlocked_init(fnd->funct)) { 276109998Smarkm#ifdef ENGINE_TABLE_DEBUG 277280297Sjkim fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using " 278280297Sjkim "ENGINE '%s' cached\n", f, l, nid, fnd->funct->id); 279109998Smarkm#endif 280280297Sjkim ret = fnd->funct; 281280297Sjkim goto end; 282280297Sjkim } 283280297Sjkim if (fnd->uptodate) { 284280297Sjkim ret = fnd->funct; 285280297Sjkim goto end; 286280297Sjkim } 287280297Sjkim trynext: 288280297Sjkim ret = sk_ENGINE_value(fnd->sk, loop++); 289280297Sjkim if (!ret) { 290109998Smarkm#ifdef ENGINE_TABLE_DEBUG 291280297Sjkim fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no " 292280297Sjkim "registered implementations would initialise\n", f, l, nid); 293109998Smarkm#endif 294280297Sjkim goto end; 295280297Sjkim } 296280297Sjkim /* Try to initialise the ENGINE? */ 297280297Sjkim if ((ret->funct_ref > 0) || !(table_flags & ENGINE_TABLE_FLAG_NOINIT)) 298280297Sjkim initres = engine_unlocked_init(ret); 299280297Sjkim else 300280297Sjkim initres = 0; 301280297Sjkim if (initres) { 302280297Sjkim /* Update 'funct' */ 303280297Sjkim if ((fnd->funct != ret) && engine_unlocked_init(ret)) { 304280297Sjkim /* If there was a previous default we release it. */ 305280297Sjkim if (fnd->funct) 306280297Sjkim engine_unlocked_finish(fnd->funct, 0); 307280297Sjkim fnd->funct = ret; 308109998Smarkm#ifdef ENGINE_TABLE_DEBUG 309280297Sjkim fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, " 310280297Sjkim "setting default to '%s'\n", f, l, nid, ret->id); 311109998Smarkm#endif 312280297Sjkim } 313109998Smarkm#ifdef ENGINE_TABLE_DEBUG 314280297Sjkim fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using " 315280297Sjkim "newly initialised '%s'\n", f, l, nid, ret->id); 316109998Smarkm#endif 317280297Sjkim goto end; 318280297Sjkim } 319280297Sjkim goto trynext; 320280297Sjkim end: 321280297Sjkim /* 322280297Sjkim * If it failed, it is unlikely to succeed again until some future 323280297Sjkim * registrations have taken place. In all cases, we cache. 324280297Sjkim */ 325280297Sjkim if (fnd) 326280297Sjkim fnd->uptodate = 1; 327109998Smarkm#ifdef ENGINE_TABLE_DEBUG 328280297Sjkim if (ret) 329280297Sjkim fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching " 330280297Sjkim "ENGINE '%s'\n", f, l, nid, ret->id); 331280297Sjkim else 332280297Sjkim fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching " 333280297Sjkim "'no matching ENGINE'\n", f, l, nid); 334109998Smarkm#endif 335280297Sjkim CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 336280297Sjkim /* 337280297Sjkim * Whatever happened, any failed init()s are not failures in this 338280297Sjkim * context, so clear our error state. 339280297Sjkim */ 340280297Sjkim ERR_pop_to_mark(); 341280297Sjkim return ret; 342280297Sjkim} 343238405Sjkim 344238405Sjkim/* Table enumeration */ 345238405Sjkim 346238405Sjkimstatic void int_cb_doall_arg(ENGINE_PILE *pile, ENGINE_PILE_DOALL *dall) 347280297Sjkim{ 348280297Sjkim dall->cb(pile->nid, pile->sk, pile->funct, dall->arg); 349280297Sjkim} 350238405Sjkim 351280297Sjkimstatic IMPLEMENT_LHASH_DOALL_ARG_FN(int_cb, ENGINE_PILE, ENGINE_PILE_DOALL) 352280297Sjkim 353238405Sjkimvoid engine_table_doall(ENGINE_TABLE *table, engine_table_doall_cb *cb, 354280297Sjkim void *arg) 355280297Sjkim{ 356280297Sjkim ENGINE_PILE_DOALL dall; 357280297Sjkim dall.cb = cb; 358280297Sjkim dall.arg = arg; 359284283Sjkim if (table) 360284283Sjkim lh_ENGINE_PILE_doall_arg(&table->piles, 361284283Sjkim LHASH_DOALL_ARG_FN(int_cb), 362284283Sjkim ENGINE_PILE_DOALL, &dall); 363280297Sjkim} 364