123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485 |
- /*
- * Copyright 2001-2023 The OpenSSL Project Authors. All Rights Reserved.
- * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
- *
- * Licensed under the Apache License 2.0 (the "License"). You may not use
- * this file except in compliance with the License. You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
- /* We need to use some engine deprecated APIs */
- #define OPENSSL_SUPPRESS_DEPRECATED
- #include "eng_local.h"
- /*
- * The linked-list of pointers to engine types. engine_list_head incorporates
- * an implicit structural reference but engine_list_tail does not - the
- * latter is a computational optimization and only points to something that
- * is already pointed to by its predecessor in the list (or engine_list_head
- * itself). In the same way, the use of the "prev" pointer in each ENGINE is
- * to save excessive list iteration, it doesn't correspond to an extra
- * structural reference. Hence, engine_list_head, and each non-null "next"
- * pointer account for the list itself assuming exactly 1 structural
- * reference on each list member.
- */
- static ENGINE *engine_list_head = NULL;
- static ENGINE *engine_list_tail = NULL;
- /*
- * The linked list of currently loaded dynamic engines.
- */
- static ENGINE *engine_dyn_list_head = NULL;
- static ENGINE *engine_dyn_list_tail = NULL;
- /*
- * This cleanup function is only needed internally. If it should be called,
- * we register it with the "engine_cleanup_int()" stack to be called during
- * cleanup.
- */
- static void engine_list_cleanup(void)
- {
- ENGINE *iterator = engine_list_head;
- while (iterator != NULL) {
- ENGINE_remove(iterator);
- iterator = engine_list_head;
- }
- return;
- }
- /*
- * These static functions starting with a lower case "engine_" always take
- * place when global_engine_lock has been locked up.
- */
- static int engine_list_add(ENGINE *e)
- {
- int conflict = 0;
- ENGINE *iterator = NULL;
- int ref;
- if (e == NULL) {
- ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- iterator = engine_list_head;
- while (iterator && !conflict) {
- conflict = (strcmp(iterator->id, e->id) == 0);
- iterator = iterator->next;
- }
- if (conflict) {
- ERR_raise(ERR_LIB_ENGINE, ENGINE_R_CONFLICTING_ENGINE_ID);
- return 0;
- }
- /*
- * Having the engine in the list assumes a structural reference.
- */
- if (!CRYPTO_UP_REF(&e->struct_ref, &ref)) {
- ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
- return 0;
- }
- ENGINE_REF_PRINT(e, 0, 1);
- if (engine_list_head == NULL) {
- /* We are adding to an empty list. */
- if (engine_list_tail != NULL) {
- CRYPTO_DOWN_REF(&e->struct_ref, &ref);
- ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
- return 0;
- }
- /*
- * The first time the list allocates, we should register the cleanup.
- */
- if (!engine_cleanup_add_last(engine_list_cleanup)) {
- CRYPTO_DOWN_REF(&e->struct_ref, &ref);
- ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
- return 0;
- }
- engine_list_head = e;
- e->prev = NULL;
- } else {
- /* We are adding to the tail of an existing list. */
- if ((engine_list_tail == NULL) || (engine_list_tail->next != NULL)) {
- CRYPTO_DOWN_REF(&e->struct_ref, &ref);
- ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
- return 0;
- }
- engine_list_tail->next = e;
- e->prev = engine_list_tail;
- }
- /* However it came to be, e is the last item in the list. */
- engine_list_tail = e;
- e->next = NULL;
- return 1;
- }
- static int engine_list_remove(ENGINE *e)
- {
- ENGINE *iterator;
- if (e == NULL) {
- ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- /* We need to check that e is in our linked list! */
- iterator = engine_list_head;
- while (iterator && (iterator != e))
- iterator = iterator->next;
- if (iterator == NULL) {
- ERR_raise(ERR_LIB_ENGINE, ENGINE_R_ENGINE_IS_NOT_IN_LIST);
- return 0;
- }
- /* un-link e from the chain. */
- if (e->next)
- e->next->prev = e->prev;
- if (e->prev)
- e->prev->next = e->next;
- /* Correct our head/tail if necessary. */
- if (engine_list_head == e)
- engine_list_head = e->next;
- if (engine_list_tail == e)
- engine_list_tail = e->prev;
- engine_free_util(e, 0);
- return 1;
- }
- /* Add engine to dynamic engine list. */
- int engine_add_dynamic_id(ENGINE *e, ENGINE_DYNAMIC_ID dynamic_id,
- int not_locked)
- {
- int result = 0;
- ENGINE *iterator = NULL;
- if (e == NULL)
- return 0;
- if (e->dynamic_id == NULL && dynamic_id == NULL)
- return 0;
- if (not_locked && !CRYPTO_THREAD_write_lock(global_engine_lock))
- return 0;
- if (dynamic_id != NULL) {
- iterator = engine_dyn_list_head;
- while (iterator != NULL) {
- if (iterator->dynamic_id == dynamic_id)
- goto err;
- iterator = iterator->next;
- }
- if (e->dynamic_id != NULL)
- goto err;
- e->dynamic_id = dynamic_id;
- }
- if (engine_dyn_list_head == NULL) {
- /* We are adding to an empty list. */
- if (engine_dyn_list_tail != NULL)
- goto err;
- engine_dyn_list_head = e;
- e->prev_dyn = NULL;
- } else {
- /* We are adding to the tail of an existing list. */
- if (engine_dyn_list_tail == NULL
- || engine_dyn_list_tail->next_dyn != NULL)
- goto err;
- engine_dyn_list_tail->next_dyn = e;
- e->prev_dyn = engine_dyn_list_tail;
- }
- engine_dyn_list_tail = e;
- e->next_dyn = NULL;
- result = 1;
- err:
- if (not_locked)
- CRYPTO_THREAD_unlock(global_engine_lock);
- return result;
- }
- /* Remove engine from dynamic engine list. */
- void engine_remove_dynamic_id(ENGINE *e, int not_locked)
- {
- if (e == NULL || e->dynamic_id == NULL)
- return;
- if (not_locked && !CRYPTO_THREAD_write_lock(global_engine_lock))
- return;
- e->dynamic_id = NULL;
- /* un-link e from the chain. */
- if (e->next_dyn != NULL)
- e->next_dyn->prev_dyn = e->prev_dyn;
- if (e->prev_dyn != NULL)
- e->prev_dyn->next_dyn = e->next_dyn;
- /* Correct our head/tail if necessary. */
- if (engine_dyn_list_head == e)
- engine_dyn_list_head = e->next_dyn;
- if (engine_dyn_list_tail == e)
- engine_dyn_list_tail = e->prev_dyn;
- if (not_locked)
- CRYPTO_THREAD_unlock(global_engine_lock);
- }
- /* Get the first/last "ENGINE" type available. */
- ENGINE *ENGINE_get_first(void)
- {
- ENGINE *ret;
- if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
- /* Maybe this should be raised in do_engine_lock_init() */
- ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
- return NULL;
- }
- if (!CRYPTO_THREAD_write_lock(global_engine_lock))
- return NULL;
- ret = engine_list_head;
- if (ret) {
- int ref;
- if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) {
- ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
- return NULL;
- }
- ENGINE_REF_PRINT(ret, 0, 1);
- }
- CRYPTO_THREAD_unlock(global_engine_lock);
- return ret;
- }
- ENGINE *ENGINE_get_last(void)
- {
- ENGINE *ret;
- if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
- /* Maybe this should be raised in do_engine_lock_init() */
- ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
- return NULL;
- }
- if (!CRYPTO_THREAD_write_lock(global_engine_lock))
- return NULL;
- ret = engine_list_tail;
- if (ret) {
- int ref;
- if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) {
- ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
- return NULL;
- }
- ENGINE_REF_PRINT(ret, 0, 1);
- }
- CRYPTO_THREAD_unlock(global_engine_lock);
- return ret;
- }
- /* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */
- ENGINE *ENGINE_get_next(ENGINE *e)
- {
- ENGINE *ret = NULL;
- if (e == NULL) {
- ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
- return NULL;
- }
- if (!CRYPTO_THREAD_write_lock(global_engine_lock))
- return NULL;
- ret = e->next;
- if (ret) {
- int ref;
- /* Return a valid structural reference to the next ENGINE */
- if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) {
- ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
- return NULL;
- }
- ENGINE_REF_PRINT(ret, 0, 1);
- }
- CRYPTO_THREAD_unlock(global_engine_lock);
- /* Release the structural reference to the previous ENGINE */
- ENGINE_free(e);
- return ret;
- }
- ENGINE *ENGINE_get_prev(ENGINE *e)
- {
- ENGINE *ret = NULL;
- if (e == NULL) {
- ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
- return NULL;
- }
- if (!CRYPTO_THREAD_write_lock(global_engine_lock))
- return NULL;
- ret = e->prev;
- if (ret) {
- int ref;
- /* Return a valid structural reference to the next ENGINE */
- if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) {
- ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
- return NULL;
- }
- ENGINE_REF_PRINT(ret, 0, 1);
- }
- CRYPTO_THREAD_unlock(global_engine_lock);
- /* Release the structural reference to the previous ENGINE */
- ENGINE_free(e);
- return ret;
- }
- /* Add another "ENGINE" type into the list. */
- int ENGINE_add(ENGINE *e)
- {
- int to_return = 1;
- if (e == NULL) {
- ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- if ((e->id == NULL) || (e->name == NULL)) {
- ERR_raise(ERR_LIB_ENGINE, ENGINE_R_ID_OR_NAME_MISSING);
- return 0;
- }
- if (!CRYPTO_THREAD_write_lock(global_engine_lock))
- return 0;
- if (!engine_list_add(e)) {
- ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
- to_return = 0;
- }
- CRYPTO_THREAD_unlock(global_engine_lock);
- return to_return;
- }
- /* Remove an existing "ENGINE" type from the array. */
- int ENGINE_remove(ENGINE *e)
- {
- int to_return = 1;
- if (e == NULL) {
- ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- if (!CRYPTO_THREAD_write_lock(global_engine_lock))
- return 0;
- if (!engine_list_remove(e)) {
- ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
- to_return = 0;
- }
- CRYPTO_THREAD_unlock(global_engine_lock);
- return to_return;
- }
- static void engine_cpy(ENGINE *dest, const ENGINE *src)
- {
- dest->id = src->id;
- dest->name = src->name;
- dest->rsa_meth = src->rsa_meth;
- #ifndef OPENSSL_NO_DSA
- dest->dsa_meth = src->dsa_meth;
- #endif
- #ifndef OPENSSL_NO_DH
- dest->dh_meth = src->dh_meth;
- #endif
- #ifndef OPENSSL_NO_EC
- dest->ec_meth = src->ec_meth;
- #endif
- dest->rand_meth = src->rand_meth;
- dest->ciphers = src->ciphers;
- dest->digests = src->digests;
- dest->pkey_meths = src->pkey_meths;
- dest->destroy = src->destroy;
- dest->init = src->init;
- dest->finish = src->finish;
- dest->ctrl = src->ctrl;
- dest->load_privkey = src->load_privkey;
- dest->load_pubkey = src->load_pubkey;
- dest->cmd_defns = src->cmd_defns;
- dest->flags = src->flags;
- dest->dynamic_id = src->dynamic_id;
- engine_add_dynamic_id(dest, NULL, 0);
- }
- ENGINE *ENGINE_by_id(const char *id)
- {
- ENGINE *iterator;
- char *load_dir = NULL;
- if (id == NULL) {
- ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
- return NULL;
- }
- ENGINE_load_builtin_engines();
- if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
- /* Maybe this should be raised in do_engine_lock_init() */
- ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
- return NULL;
- }
- if (!CRYPTO_THREAD_write_lock(global_engine_lock))
- return NULL;
- iterator = engine_list_head;
- while (iterator && (strcmp(id, iterator->id) != 0))
- iterator = iterator->next;
- if (iterator != NULL) {
- /*
- * We need to return a structural reference. If this is an ENGINE
- * type that returns copies, make a duplicate - otherwise increment
- * the existing ENGINE's reference count.
- */
- if (iterator->flags & ENGINE_FLAGS_BY_ID_COPY) {
- ENGINE *cp = ENGINE_new();
- if (cp == NULL)
- iterator = NULL;
- else {
- engine_cpy(cp, iterator);
- iterator = cp;
- }
- } else {
- int ref;
- if (!CRYPTO_UP_REF(&iterator->struct_ref, &ref)) {
- CRYPTO_THREAD_unlock(global_engine_lock);
- ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
- return NULL;
- }
- ENGINE_REF_PRINT(iterator, 0, 1);
- }
- }
- CRYPTO_THREAD_unlock(global_engine_lock);
- if (iterator != NULL)
- return iterator;
- /*
- * Prevent infinite recursion if we're looking for the dynamic engine.
- */
- if (strcmp(id, "dynamic")) {
- if ((load_dir = ossl_safe_getenv("OPENSSL_ENGINES")) == NULL)
- load_dir = ENGINESDIR;
- iterator = ENGINE_by_id("dynamic");
- if (!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) ||
- !ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) ||
- !ENGINE_ctrl_cmd_string(iterator, "DIR_ADD",
- load_dir, 0) ||
- !ENGINE_ctrl_cmd_string(iterator, "LIST_ADD", "1", 0) ||
- !ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0))
- goto notfound;
- return iterator;
- }
- notfound:
- ENGINE_free(iterator);
- ERR_raise_data(ERR_LIB_ENGINE, ENGINE_R_NO_SUCH_ENGINE, "id=%s", id);
- return NULL;
- /* EEK! Experimental code ends */
- }
- int ENGINE_up_ref(ENGINE *e)
- {
- int i;
- if (e == NULL) {
- ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
- return 0;
- }
- CRYPTO_UP_REF(&e->struct_ref, &i);
- return 1;
- }
|