1139804Simp/*
248391Speter * Copyright 2001-2023 The OpenSSL Project Authors. All Rights Reserved.
348391Speter * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
448391Speter *
548391Speter * Licensed under the Apache License 2.0 (the "License").  You may not use
648391Speter * this file except in compliance with the License.  You can obtain a copy
748391Speter * in the file LICENSE in the source distribution or at
848391Speter * https://www.openssl.org/source/license.html
948391Speter */
1048391Speter
1148391Speter/* We need to use some engine deprecated APIs */
1248391Speter#define OPENSSL_SUPPRESS_DEPRECATED
1348391Speter
1448391Speter#include "eng_local.h"
1548391Speter
1648391Speter/*
1748391Speter * The linked-list of pointers to engine types. engine_list_head incorporates
1848391Speter * an implicit structural reference but engine_list_tail does not - the
1948391Speter * latter is a computational optimization and only points to something that
2048391Speter * is already pointed to by its predecessor in the list (or engine_list_head
2148391Speter * itself). In the same way, the use of the "prev" pointer in each ENGINE is
2248391Speter * to save excessive list iteration, it doesn't correspond to an extra
2348391Speter * structural reference. Hence, engine_list_head, and each non-null "next"
2448391Speter * pointer account for the list itself assuming exactly 1 structural
2548391Speter * reference on each list member.
2648391Speter */
27116182Sobrienstatic ENGINE *engine_list_head = NULL;
28116182Sobrienstatic ENGINE *engine_list_tail = NULL;
29116182Sobrien
3048391Speter/*
3148391Speter * The linked list of currently loaded dynamic engines.
3248391Speter */
3370317Sjakestatic ENGINE *engine_dyn_list_head = NULL;
3474927Sjhbstatic ENGINE *engine_dyn_list_tail = NULL;
3574927Sjhb
3655722Simp/*
3755539Sluoqi * This cleanup function is only needed internally. If it should be called,
3874927Sjhb * we register it with the "engine_cleanup_int()" stack to be called during
3948391Speter * cleanup.
4048391Speter */
41166188Sjeff
42173004Sjulianstatic void engine_list_cleanup(void)
43173004Sjulian{
4448391Speter    ENGINE *iterator = engine_list_head;
4548391Speter
4648391Speter    while (iterator != NULL) {
4748391Speter        ENGINE_remove(iterator);
4848391Speter        iterator = engine_list_head;
4948391Speter    }
5048391Speter    return;
5148391Speter}
5248391Speter
5348391Speter/*
5448391Speter * These static functions starting with a lower case "engine_" always take
5548391Speter * place when global_engine_lock has been locked up.
5648391Speter */
5748391Speterstatic int engine_list_add(ENGINE *e)
5848391Speter{
5948391Speter    int conflict = 0;
6048391Speter    ENGINE *iterator = NULL;
61172836Sjulian
62104354Sscottl    if (e == NULL) {
6348391Speter        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
6448391Speter        return 0;
6548391Speter    }
6648391Speter    iterator = engine_list_head;
6748391Speter    while (iterator && !conflict) {
6865557Sjasone        conflict = (strcmp(iterator->id, e->id) == 0);
6948391Speter        iterator = iterator->next;
7065557Sjasone    }
7165557Sjasone    if (conflict) {
7265557Sjasone        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_CONFLICTING_ENGINE_ID);
7365557Sjasone        return 0;
7465557Sjasone    }
7565557Sjasone    if (engine_list_head == NULL) {
7648391Speter        /* We are adding to an empty list. */
7748391Speter        if (engine_list_tail) {
78172836Sjulian            ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
79104354Sscottl            return 0;
8048391Speter        }
8148391Speter        /*
8248391Speter         * The first time the list allocates, we should register the cleanup.
83103216Sjulian         */
8448391Speter        if (!engine_cleanup_add_last(engine_list_cleanup)) {
8548391Speter            ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
86114434Sdes            return 0;
87172836Sjulian        }
8865557Sjasone        engine_list_head = e;
8990375Speter        e->prev = NULL;
90104354Sscottl    } else {
9148391Speter        /* We are adding to the tail of an existing list. */
9248391Speter        if ((engine_list_tail == NULL) || (engine_list_tail->next != NULL)) {
9348391Speter            ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
9448391Speter            return 0;
9548391Speter        }
9648391Speter        engine_list_tail->next = e;
9748391Speter        e->prev = engine_list_tail;
9848391Speter    }
9971559Sjhb    /*
100173004Sjulian     * Having the engine in the list assumes a structural reference.
10171559Sjhb     */
102173004Sjulian    e->struct_ref++;
103114983Sjhb    ENGINE_REF_PRINT(e, 0, 1);
104114983Sjhb    /* However it came to be, e is the last item in the list. */
105114983Sjhb    engine_list_tail = e;
10671559Sjhb    e->next = NULL;
10748391Speter    return 1;
10848391Speter}
10948391Speter
11048391Speterstatic int engine_list_remove(ENGINE *e)
11148391Speter{
112173004Sjulian    ENGINE *iterator;
113173004Sjulian
114173004Sjulian    if (e == NULL) {
115173004Sjulian        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
11648391Speter        return 0;
11748391Speter    }
118103216Sjulian    /* We need to check that e is in our linked list! */
119103216Sjulian    iterator = engine_list_head;
12048391Speter    while (iterator && (iterator != e))
12169657Sjhb        iterator = iterator->next;
12269657Sjhb    if (iterator == NULL) {
123170307Sjeff        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_ENGINE_IS_NOT_IN_LIST);
124166188Sjeff        return 0;
125170307Sjeff    }
12669657Sjhb    /* un-link e from the chain. */
12769657Sjhb    if (e->next)
12848391Speter        e->next->prev = e->prev;
12948391Speter    if (e->prev)
13048391Speter        e->prev->next = e->next;
13148391Speter    /* Correct our head/tail if necessary. */
132172836Sjulian    if (engine_list_head == e)
13348391Speter        engine_list_head = e->next;
13486293Speter    if (engine_list_tail == e)
13586293Speter        engine_list_tail = e->prev;
13670317Sjake    engine_free_util(e, 0);
13786293Speter    return 1;
13886293Speter}
139155400Sjhb
140155400Sjhb/* Add engine to dynamic engine list. */
141155400Sjhbint engine_add_dynamic_id(ENGINE *e, ENGINE_DYNAMIC_ID dynamic_id,
142155400Sjhb                          int not_locked)
143155400Sjhb{
14474927Sjhb    int result = 0;
14586292Sdillon    ENGINE *iterator = NULL;
14686292Sdillon
14786292Sdillon    if (e == NULL)
14874927Sjhb        return 0;
149155400Sjhb
150155400Sjhb    if (e->dynamic_id == NULL && dynamic_id == NULL)
151155400Sjhb        return 0;
152155400Sjhb
153155400Sjhb    if (not_locked && !CRYPTO_THREAD_write_lock(global_engine_lock))
154155400Sjhb        return 0;
155155400Sjhb
15686293Speter    if (dynamic_id != NULL) {
15748391Speter        iterator = engine_dyn_list_head;
15848391Speter        while (iterator != NULL) {
15955539Sluoqi            if (iterator->dynamic_id == dynamic_id)
16055539Sluoqi                goto err;
16155539Sluoqi            iterator = iterator->next;
16255539Sluoqi        }
16355539Sluoqi        if (e->dynamic_id != NULL)
164172836Sjulian            goto err;
16555539Sluoqi        e->dynamic_id = dynamic_id;
16655539Sluoqi    }
16755539Sluoqi
168104306Sjmallett    if (engine_dyn_list_head == NULL) {
16955539Sluoqi        /* We are adding to an empty list. */
17073911Sjhb        if (engine_dyn_list_tail != NULL)
17173911Sjhb            goto err;
17273911Sjhb        engine_dyn_list_head = e;
17355539Sluoqi        e->prev_dyn = NULL;
17473911Sjhb    } else {
175104306Sjmallett        /* We are adding to the tail of an existing list. */
17688160Speter        if (engine_dyn_list_tail == NULL
177173004Sjulian            || engine_dyn_list_tail->next_dyn != NULL)
17855539Sluoqi            goto err;
17955539Sluoqi        engine_dyn_list_tail->next_dyn = e;
18055539Sluoqi        e->prev_dyn = engine_dyn_list_tail;
181172836Sjulian    }
18255539Sluoqi
18355539Sluoqi    engine_dyn_list_tail = e;
18455539Sluoqi    e->next_dyn = NULL;
18555539Sluoqi    result = 1;
18655539Sluoqi
18773911Sjhb err:
18873911Sjhb    if (not_locked)
18973911Sjhb        CRYPTO_THREAD_unlock(global_engine_lock);
19055539Sluoqi    return result;
19173911Sjhb}
192104306Sjmallett
19373911Sjhb/* Remove engine from dynamic engine list. */
194104306Sjmallettvoid engine_remove_dynamic_id(ENGINE *e, int not_locked)
19555539Sluoqi{
19655539Sluoqi    if (e == NULL || e->dynamic_id == NULL)
19755539Sluoqi        return;
19855539Sluoqi
199172836Sjulian    if (not_locked && !CRYPTO_THREAD_write_lock(global_engine_lock))
20055539Sluoqi        return;
20173911Sjhb
202104306Sjmallett    e->dynamic_id = NULL;
203104306Sjmallett
204173004Sjulian    /* un-link e from the chain. */
20555539Sluoqi    if (e->next_dyn != NULL)
20673911Sjhb        e->next_dyn->prev_dyn = e->prev_dyn;
20755539Sluoqi    if (e->prev_dyn != NULL)
208173004Sjulian        e->prev_dyn->next_dyn = e->next_dyn;
209173004Sjulian    /* Correct our head/tail if necessary. */
210173004Sjulian    if (engine_dyn_list_head == e)
211173004Sjulian        engine_dyn_list_head = e->next_dyn;
212173004Sjulian    if (engine_dyn_list_tail == e)
213173004Sjulian        engine_dyn_list_tail = e->prev_dyn;
214173004Sjulian
215173004Sjulian    if (not_locked)
216173004Sjulian        CRYPTO_THREAD_unlock(global_engine_lock);
217173004Sjulian}
218173004Sjulian
219173004Sjulian/* Get the first/last "ENGINE" type available. */
220173004SjulianENGINE *ENGINE_get_first(void)
221173004Sjulian{
222173004Sjulian    ENGINE *ret;
223173004Sjulian
224173004Sjulian    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
225173004Sjulian        ERR_raise(ERR_LIB_ENGINE, ERR_R_MALLOC_FAILURE);
226173004Sjulian        return NULL;
227173004Sjulian    }
228173004Sjulian
229173004Sjulian    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
230173004Sjulian        return NULL;
231173004Sjulian    ret = engine_list_head;
232173004Sjulian    if (ret) {
233173004Sjulian        ret->struct_ref++;
234173004Sjulian        ENGINE_REF_PRINT(ret, 0, 1);
235173004Sjulian    }
236173004Sjulian    CRYPTO_THREAD_unlock(global_engine_lock);
237173004Sjulian    return ret;
238173004Sjulian}
239173004Sjulian
240173004SjulianENGINE *ENGINE_get_last(void)
241173004Sjulian{
242173004Sjulian    ENGINE *ret;
243173004Sjulian
244173004Sjulian    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
245173004Sjulian        ERR_raise(ERR_LIB_ENGINE, ERR_R_MALLOC_FAILURE);
246173004Sjulian        return NULL;
247173004Sjulian    }
248173004Sjulian
249173004Sjulian    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
250173052Sjulian        return NULL;
251173004Sjulian    ret = engine_list_tail;
252173004Sjulian    if (ret) {
253173004Sjulian        ret->struct_ref++;
254173004Sjulian        ENGINE_REF_PRINT(ret, 0, 1);
255173052Sjulian    }
256173004Sjulian    CRYPTO_THREAD_unlock(global_engine_lock);
257173004Sjulian    return ret;
258173052Sjulian}
259196730Skib
260173004Sjulian/* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */
261173004SjulianENGINE *ENGINE_get_next(ENGINE *e)
262173004Sjulian{
263173004Sjulian    ENGINE *ret = NULL;
264173004Sjulian    if (e == NULL) {
265173004Sjulian        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
266173004Sjulian        return NULL;
267173004Sjulian    }
268173004Sjulian    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
269173004Sjulian        return NULL;
270173004Sjulian    ret = e->next;
271173004Sjulian    if (ret) {
272173004Sjulian        /* Return a valid structural reference to the next ENGINE */
273173004Sjulian        ret->struct_ref++;
274173004Sjulian        ENGINE_REF_PRINT(ret, 0, 1);
275173004Sjulian    }
276173004Sjulian    CRYPTO_THREAD_unlock(global_engine_lock);
277173004Sjulian    /* Release the structural reference to the previous ENGINE */
278173004Sjulian    ENGINE_free(e);
279173004Sjulian    return ret;
280173004Sjulian}
281173004Sjulian
282173004SjulianENGINE *ENGINE_get_prev(ENGINE *e)
283173004Sjulian{
284173004Sjulian    ENGINE *ret = NULL;
285173004Sjulian    if (e == NULL) {
286173004Sjulian        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
287173004Sjulian        return NULL;
288173004Sjulian    }
289173004Sjulian    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
290173004Sjulian        return NULL;
291173004Sjulian    ret = e->prev;
292173004Sjulian    if (ret) {
293173004Sjulian        /* Return a valid structural reference to the next ENGINE */
294173004Sjulian        ret->struct_ref++;
295173004Sjulian        ENGINE_REF_PRINT(ret, 0, 1);
296173004Sjulian    }
297173004Sjulian    CRYPTO_THREAD_unlock(global_engine_lock);
298173004Sjulian    /* Release the structural reference to the previous ENGINE */
299173004Sjulian    ENGINE_free(e);
300173004Sjulian    return ret;
301173004Sjulian}
302173004Sjulian
303173004Sjulian/* Add another "ENGINE" type into the list. */
304173004Sjulianint ENGINE_add(ENGINE *e)
305173004Sjulian{
306173004Sjulian    int to_return = 1;
307173004Sjulian    if (e == NULL) {
308173004Sjulian        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
309173004Sjulian        return 0;
310173004Sjulian    }
311173031Sjulian    if ((e->id == NULL) || (e->name == NULL)) {
312173004Sjulian        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_ID_OR_NAME_MISSING);
313173658Sjhb        return 0;
314173658Sjhb    }
315204087Sattilio    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
316204087Sattilio        return 0;
317173658Sjhb    if (!engine_list_add(e)) {
318173052Sjulian        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
319204087Sattilio        to_return = 0;
320204089Sattilio    }
321204087Sattilio    CRYPTO_THREAD_unlock(global_engine_lock);
322204087Sattilio    return to_return;
323173658Sjhb}
324204087Sattilio
325204087Sattilio/* Remove an existing "ENGINE" type from the array. */
326173658Sjhbint ENGINE_remove(ENGINE *e)
327173004Sjulian{
328173004Sjulian    int to_return = 1;
329173004Sjulian    if (e == NULL) {
330173004Sjulian        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
331173004Sjulian        return 0;
332173004Sjulian    }
333173004Sjulian    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
334173004Sjulian        return 0;
335173004Sjulian    if (!engine_list_remove(e)) {
336173004Sjulian        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
337202933Sattilio        to_return = 0;
338202933Sattilio    }
339202933Sattilio    CRYPTO_THREAD_unlock(global_engine_lock);
340202933Sattilio    return to_return;
341202933Sattilio}
342204088Sattilio
343202933Sattiliostatic void engine_cpy(ENGINE *dest, const ENGINE *src)
344204088Sattilio{
345202933Sattilio    dest->id = src->id;
346202933Sattilio    dest->name = src->name;
347173004Sjulian    dest->rsa_meth = src->rsa_meth;
348202933Sattilio#ifndef OPENSSL_NO_DSA
349202933Sattilio    dest->dsa_meth = src->dsa_meth;
350202933Sattilio#endif
351202933Sattilio#ifndef OPENSSL_NO_DH
352202933Sattilio    dest->dh_meth = src->dh_meth;
353202933Sattilio#endif
354202933Sattilio#ifndef OPENSSL_NO_EC
355173004Sjulian    dest->ec_meth = src->ec_meth;
356173004Sjulian#endif
357173004Sjulian    dest->rand_meth = src->rand_meth;
358202933Sattilio    dest->ciphers = src->ciphers;
359202933Sattilio    dest->digests = src->digests;
360173004Sjulian    dest->pkey_meths = src->pkey_meths;
361173004Sjulian    dest->destroy = src->destroy;
362173004Sjulian    dest->init = src->init;
363202933Sattilio    dest->finish = src->finish;
364173004Sjulian    dest->ctrl = src->ctrl;
365173004Sjulian    dest->load_privkey = src->load_privkey;
366173004Sjulian    dest->load_pubkey = src->load_pubkey;
367173004Sjulian    dest->cmd_defns = src->cmd_defns;
368202933Sattilio    dest->flags = src->flags;
369202933Sattilio    dest->dynamic_id = src->dynamic_id;
370202933Sattilio    engine_add_dynamic_id(dest, NULL, 0);
371202933Sattilio}
372202933Sattilio
373204088SattilioENGINE *ENGINE_by_id(const char *id)
374202933Sattilio{
375204088Sattilio    ENGINE *iterator;
376202933Sattilio    char *load_dir = NULL;
377202933Sattilio    if (id == NULL) {
378173004Sjulian        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
379202933Sattilio        return NULL;
380202933Sattilio    }
381173004Sjulian    ENGINE_load_builtin_engines();
382173004Sjulian
383173004Sjulian    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
384202933Sattilio        ERR_raise(ERR_LIB_ENGINE, ERR_R_MALLOC_FAILURE);
385202933Sattilio        return NULL;
386173004Sjulian    }
387173004Sjulian
388173004Sjulian    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
389173004Sjulian        return NULL;
390173004Sjulian    iterator = engine_list_head;
391173004Sjulian    while (iterator && (strcmp(id, iterator->id) != 0))
392173004Sjulian        iterator = iterator->next;
393173004Sjulian    if (iterator != NULL) {
394202933Sattilio        /*
395173004Sjulian         * We need to return a structural reference. If this is an ENGINE
396202933Sattilio         * type that returns copies, make a duplicate - otherwise increment
397202933Sattilio         * the existing ENGINE's reference count.
398202933Sattilio         */
399202933Sattilio        if (iterator->flags & ENGINE_FLAGS_BY_ID_COPY) {
400202933Sattilio            ENGINE *cp = ENGINE_new();
401202933Sattilio            if (cp == NULL)
402202933Sattilio                iterator = NULL;
403202933Sattilio            else {
404202933Sattilio                engine_cpy(cp, iterator);
405202933Sattilio                iterator = cp;
406202933Sattilio            }
407202933Sattilio        } else {
408202933Sattilio            iterator->struct_ref++;
409202933Sattilio            ENGINE_REF_PRINT(iterator, 0, 1);
410202933Sattilio        }
411173004Sjulian    }
412173004Sjulian    CRYPTO_THREAD_unlock(global_engine_lock);
413202933Sattilio    if (iterator != NULL)
414173004Sjulian        return iterator;
415202933Sattilio    /*
416173004Sjulian     * Prevent infinite recursion if we're looking for the dynamic engine.
417173004Sjulian     */
418173004Sjulian    if (strcmp(id, "dynamic")) {
419173004Sjulian        if ((load_dir = ossl_safe_getenv("OPENSSL_ENGINES")) == NULL)
420173004Sjulian            load_dir = ENGINESDIR;
421173004Sjulian        iterator = ENGINE_by_id("dynamic");
422173004Sjulian        if (!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) ||
423173004Sjulian            !ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) ||
424173004Sjulian            !ENGINE_ctrl_cmd_string(iterator, "DIR_ADD",
425173004Sjulian                                    load_dir, 0) ||
426173004Sjulian            !ENGINE_ctrl_cmd_string(iterator, "LIST_ADD", "1", 0) ||
427173004Sjulian            !ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0))
428173004Sjulian            goto notfound;
429173004Sjulian        return iterator;
430173004Sjulian    }
431173004Sjulian notfound:
432173004Sjulian    ENGINE_free(iterator);
433173004Sjulian    ERR_raise_data(ERR_LIB_ENGINE, ENGINE_R_NO_SUCH_ENGINE, "id=%s", id);
434178682Sjulian    return NULL;
435178682Sjulian    /* EEK! Experimental code ends */
436173004Sjulian}
437173004Sjulian
438173004Sjulianint ENGINE_up_ref(ENGINE *e)
439173004Sjulian{
440173004Sjulian    int i;
441173004Sjulian    if (e == NULL) {
442173004Sjulian        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
443173004Sjulian        return 0;
444173004Sjulian    }
445173004Sjulian    CRYPTO_UP_REF(&e->struct_ref, &i, global_engine_lock);
446173004Sjulian    return 1;
447173004Sjulian}
448