1 /* 2 * Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include "internal/cryptlib.h" 11 #include <openssl/evp.h> 12 #include <openssl/lhash.h> 13 #include "eng_int.h" 14 15 /* The type of the items in the table */ 16 struct st_engine_pile { 17 /* The 'nid' of this algorithm/mode */ 18 int nid; 19 /* ENGINEs that implement this algorithm/mode. */ 20 STACK_OF(ENGINE) *sk; 21 /* The default ENGINE to perform this algorithm/mode. */ 22 ENGINE *funct; 23 /* 24 * Zero if 'sk' is newer than the cached 'funct', non-zero otherwise 25 */ 26 int uptodate; 27 }; 28 29 /* The type exposed in eng_int.h */ 30 struct st_engine_table { 31 LHASH_OF(ENGINE_PILE) piles; 32 }; /* ENGINE_TABLE */ 33 34 typedef struct st_engine_pile_doall { 35 engine_table_doall_cb *cb; 36 void *arg; 37 } ENGINE_PILE_DOALL; 38 39 /* Global flags (ENGINE_TABLE_FLAG_***). */ 40 static unsigned int table_flags = 0; 41 42 /* API function manipulating 'table_flags' */ 43 unsigned int ENGINE_get_table_flags(void) 44 { 45 return table_flags; 46 } 47 48 void ENGINE_set_table_flags(unsigned int flags) 49 { 50 table_flags = flags; 51 } 52 53 /* Internal functions for the "piles" hash table */ 54 static unsigned long engine_pile_hash(const ENGINE_PILE *c) 55 { 56 return c->nid; 57 } 58 59 static int engine_pile_cmp(const ENGINE_PILE *a, const ENGINE_PILE *b) 60 { 61 return a->nid - b->nid; 62 } 63 64 static int int_table_check(ENGINE_TABLE **t, int create) 65 { 66 LHASH_OF(ENGINE_PILE) *lh; 67 68 if (*t) 69 return 1; 70 if (!create) 71 return 0; 72 if ((lh = lh_ENGINE_PILE_new(engine_pile_hash, engine_pile_cmp)) == NULL) 73 return 0; 74 *t = (ENGINE_TABLE *)lh; 75 return 1; 76 } 77 78 /* 79 * Privately exposed (via eng_int.h) functions for adding and/or removing 80 * ENGINEs from the implementation table 81 */ 82 int engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup, 83 ENGINE *e, const int *nids, int num_nids, 84 int setdefault) 85 { 86 int ret = 0, added = 0; 87 ENGINE_PILE tmplate, *fnd; 88 CRYPTO_THREAD_write_lock(global_engine_lock); 89 if (!(*table)) 90 added = 1; 91 if (!int_table_check(table, 1)) 92 goto end; 93 if (added) 94 /* The cleanup callback needs to be added */ 95 engine_cleanup_add_first(cleanup); 96 while (num_nids--) { 97 tmplate.nid = *nids; 98 fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate); 99 if (!fnd) { 100 fnd = OPENSSL_malloc(sizeof(*fnd)); 101 if (fnd == NULL) 102 goto end; 103 fnd->uptodate = 1; 104 fnd->nid = *nids; 105 fnd->sk = sk_ENGINE_new_null(); 106 if (!fnd->sk) { 107 OPENSSL_free(fnd); 108 goto end; 109 } 110 fnd->funct = NULL; 111 (void)lh_ENGINE_PILE_insert(&(*table)->piles, fnd); 112 if (lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate) != fnd) { 113 sk_ENGINE_free(fnd->sk); 114 OPENSSL_free(fnd); 115 goto end; 116 } 117 } 118 /* A registration shouldn't add duplicate entries */ 119 (void)sk_ENGINE_delete_ptr(fnd->sk, e); 120 /* 121 * if 'setdefault', this ENGINE goes to the head of the list 122 */ 123 if (!sk_ENGINE_push(fnd->sk, e)) 124 goto end; 125 /* "touch" this ENGINE_PILE */ 126 fnd->uptodate = 0; 127 if (setdefault) { 128 if (!engine_unlocked_init(e)) { 129 ENGINEerr(ENGINE_F_ENGINE_TABLE_REGISTER, 130 ENGINE_R_INIT_FAILED); 131 goto end; 132 } 133 if (fnd->funct) 134 engine_unlocked_finish(fnd->funct, 0); 135 fnd->funct = e; 136 fnd->uptodate = 1; 137 } 138 nids++; 139 } 140 ret = 1; 141 end: 142 CRYPTO_THREAD_unlock(global_engine_lock); 143 return ret; 144 } 145 146 static void int_unregister_cb(ENGINE_PILE *pile, ENGINE *e) 147 { 148 int n; 149 /* Iterate the 'c->sk' stack removing any occurrence of 'e' */ 150 while ((n = sk_ENGINE_find(pile->sk, e)) >= 0) { 151 (void)sk_ENGINE_delete(pile->sk, n); 152 pile->uptodate = 0; 153 } 154 if (pile->funct == e) { 155 engine_unlocked_finish(e, 0); 156 pile->funct = NULL; 157 } 158 } 159 160 IMPLEMENT_LHASH_DOALL_ARG(ENGINE_PILE, ENGINE); 161 162 void engine_table_unregister(ENGINE_TABLE **table, ENGINE *e) 163 { 164 CRYPTO_THREAD_write_lock(global_engine_lock); 165 if (int_table_check(table, 0)) 166 lh_ENGINE_PILE_doall_ENGINE(&(*table)->piles, int_unregister_cb, e); 167 CRYPTO_THREAD_unlock(global_engine_lock); 168 } 169 170 static void int_cleanup_cb_doall(ENGINE_PILE *p) 171 { 172 if (!p) 173 return; 174 sk_ENGINE_free(p->sk); 175 if (p->funct) 176 engine_unlocked_finish(p->funct, 0); 177 OPENSSL_free(p); 178 } 179 180 void engine_table_cleanup(ENGINE_TABLE **table) 181 { 182 CRYPTO_THREAD_write_lock(global_engine_lock); 183 if (*table) { 184 lh_ENGINE_PILE_doall(&(*table)->piles, int_cleanup_cb_doall); 185 lh_ENGINE_PILE_free(&(*table)->piles); 186 *table = NULL; 187 } 188 CRYPTO_THREAD_unlock(global_engine_lock); 189 } 190 191 /* return a functional reference for a given 'nid' */ 192 #ifndef ENGINE_TABLE_DEBUG 193 ENGINE *engine_table_select(ENGINE_TABLE **table, int nid) 194 #else 195 ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f, 196 int l) 197 #endif 198 { 199 ENGINE *ret = NULL; 200 ENGINE_PILE tmplate, *fnd = NULL; 201 int initres, loop = 0; 202 203 if (!(*table)) { 204 #ifdef ENGINE_TABLE_DEBUG 205 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, nothing " 206 "registered!\n", f, l, nid); 207 #endif 208 return NULL; 209 } 210 ERR_set_mark(); 211 CRYPTO_THREAD_write_lock(global_engine_lock); 212 /* 213 * Check again inside the lock otherwise we could race against cleanup 214 * operations. But don't worry about a fprintf(stderr). 215 */ 216 if (!int_table_check(table, 0)) 217 goto end; 218 tmplate.nid = nid; 219 fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate); 220 if (!fnd) 221 goto end; 222 if (fnd->funct && engine_unlocked_init(fnd->funct)) { 223 #ifdef ENGINE_TABLE_DEBUG 224 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using " 225 "ENGINE '%s' cached\n", f, l, nid, fnd->funct->id); 226 #endif 227 ret = fnd->funct; 228 goto end; 229 } 230 if (fnd->uptodate) { 231 ret = fnd->funct; 232 goto end; 233 } 234 trynext: 235 ret = sk_ENGINE_value(fnd->sk, loop++); 236 if (!ret) { 237 #ifdef ENGINE_TABLE_DEBUG 238 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no " 239 "registered implementations would initialise\n", f, l, nid); 240 #endif 241 goto end; 242 } 243 /* Try to initialise the ENGINE? */ 244 if ((ret->funct_ref > 0) || !(table_flags & ENGINE_TABLE_FLAG_NOINIT)) 245 initres = engine_unlocked_init(ret); 246 else 247 initres = 0; 248 if (initres) { 249 /* Update 'funct' */ 250 if ((fnd->funct != ret) && engine_unlocked_init(ret)) { 251 /* If there was a previous default we release it. */ 252 if (fnd->funct) 253 engine_unlocked_finish(fnd->funct, 0); 254 fnd->funct = ret; 255 #ifdef ENGINE_TABLE_DEBUG 256 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, " 257 "setting default to '%s'\n", f, l, nid, ret->id); 258 #endif 259 } 260 #ifdef ENGINE_TABLE_DEBUG 261 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using " 262 "newly initialised '%s'\n", f, l, nid, ret->id); 263 #endif 264 goto end; 265 } 266 goto trynext; 267 end: 268 /* 269 * If it failed, it is unlikely to succeed again until some future 270 * registrations have taken place. In all cases, we cache. 271 */ 272 if (fnd) 273 fnd->uptodate = 1; 274 #ifdef ENGINE_TABLE_DEBUG 275 if (ret) 276 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching " 277 "ENGINE '%s'\n", f, l, nid, ret->id); 278 else 279 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching " 280 "'no matching ENGINE'\n", f, l, nid); 281 #endif 282 CRYPTO_THREAD_unlock(global_engine_lock); 283 /* 284 * Whatever happened, any failed init()s are not failures in this 285 * context, so clear our error state. 286 */ 287 ERR_pop_to_mark(); 288 return ret; 289 } 290 291 /* Table enumeration */ 292 293 static void int_dall(const ENGINE_PILE *pile, ENGINE_PILE_DOALL *dall) 294 { 295 dall->cb(pile->nid, pile->sk, pile->funct, dall->arg); 296 } 297 298 IMPLEMENT_LHASH_DOALL_ARG_CONST(ENGINE_PILE, ENGINE_PILE_DOALL); 299 300 void engine_table_doall(ENGINE_TABLE *table, engine_table_doall_cb *cb, 301 void *arg) 302 { 303 ENGINE_PILE_DOALL dall; 304 dall.cb = cb; 305 dall.arg = arg; 306 if (table) 307 lh_ENGINE_PILE_doall_ENGINE_PILE_DOALL(&table->piles, int_dall, &dall); 308 } 309