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