Coverage Report

Created: 2025-06-13 06:58

/src/openssl31/crypto/engine/eng_list.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2001-2023 The OpenSSL Project Authors. All Rights Reserved.
3
 * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
4
 *
5
 * Licensed under the Apache License 2.0 (the "License").  You may not use
6
 * this file except in compliance with the License.  You can obtain a copy
7
 * in the file LICENSE in the source distribution or at
8
 * https://www.openssl.org/source/license.html
9
 */
10
11
/* We need to use some engine deprecated APIs */
12
#define OPENSSL_SUPPRESS_DEPRECATED
13
14
#include "eng_local.h"
15
16
/*
17
 * The linked-list of pointers to engine types. engine_list_head incorporates
18
 * an implicit structural reference but engine_list_tail does not - the
19
 * latter is a computational optimization and only points to something that
20
 * is already pointed to by its predecessor in the list (or engine_list_head
21
 * itself). In the same way, the use of the "prev" pointer in each ENGINE is
22
 * to save excessive list iteration, it doesn't correspond to an extra
23
 * structural reference. Hence, engine_list_head, and each non-null "next"
24
 * pointer account for the list itself assuming exactly 1 structural
25
 * reference on each list member.
26
 */
27
static ENGINE *engine_list_head = NULL;
28
static ENGINE *engine_list_tail = NULL;
29
30
/*
31
 * The linked list of currently loaded dynamic engines.
32
 */
33
static ENGINE *engine_dyn_list_head = NULL;
34
static ENGINE *engine_dyn_list_tail = NULL;
35
36
/*
37
 * This cleanup function is only needed internally. If it should be called,
38
 * we register it with the "engine_cleanup_int()" stack to be called during
39
 * cleanup.
40
 */
41
42
static void engine_list_cleanup(void)
43
0
{
44
0
    ENGINE *iterator = engine_list_head;
45
46
0
    while (iterator != NULL) {
47
0
        ENGINE_remove(iterator);
48
0
        iterator = engine_list_head;
49
0
    }
50
0
    return;
51
0
}
52
53
/*
54
 * These static functions starting with a lower case "engine_" always take
55
 * place when global_engine_lock has been locked up.
56
 */
57
static int engine_list_add(ENGINE *e)
58
0
{
59
0
    int conflict = 0;
60
0
    ENGINE *iterator = NULL;
61
62
0
    if (e == NULL) {
63
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
64
0
        return 0;
65
0
    }
66
0
    iterator = engine_list_head;
67
0
    while (iterator && !conflict) {
68
0
        conflict = (strcmp(iterator->id, e->id) == 0);
69
0
        iterator = iterator->next;
70
0
    }
71
0
    if (conflict) {
72
0
        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_CONFLICTING_ENGINE_ID);
73
0
        return 0;
74
0
    }
75
0
    if (engine_list_head == NULL) {
76
        /* We are adding to an empty list. */
77
0
        if (engine_list_tail) {
78
0
            ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
79
0
            return 0;
80
0
        }
81
        /*
82
         * The first time the list allocates, we should register the cleanup.
83
         */
84
0
        if (!engine_cleanup_add_last(engine_list_cleanup)) {
85
0
            ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
86
0
            return 0;
87
0
        }
88
0
        engine_list_head = e;
89
0
        e->prev = NULL;
90
0
    } else {
91
        /* We are adding to the tail of an existing list. */
92
0
        if ((engine_list_tail == NULL) || (engine_list_tail->next != NULL)) {
93
0
            ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
94
0
            return 0;
95
0
        }
96
0
        engine_list_tail->next = e;
97
0
        e->prev = engine_list_tail;
98
0
    }
99
    /*
100
     * Having the engine in the list assumes a structural reference.
101
     */
102
0
    e->struct_ref++;
103
0
    ENGINE_REF_PRINT(e, 0, 1);
104
    /* However it came to be, e is the last item in the list. */
105
0
    engine_list_tail = e;
106
0
    e->next = NULL;
107
0
    return 1;
108
0
}
109
110
static int engine_list_remove(ENGINE *e)
111
0
{
112
0
    ENGINE *iterator;
113
114
0
    if (e == NULL) {
115
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
116
0
        return 0;
117
0
    }
118
    /* We need to check that e is in our linked list! */
119
0
    iterator = engine_list_head;
120
0
    while (iterator && (iterator != e))
121
0
        iterator = iterator->next;
122
0
    if (iterator == NULL) {
123
0
        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_ENGINE_IS_NOT_IN_LIST);
124
0
        return 0;
125
0
    }
126
    /* un-link e from the chain. */
127
0
    if (e->next)
128
0
        e->next->prev = e->prev;
129
0
    if (e->prev)
130
0
        e->prev->next = e->next;
131
    /* Correct our head/tail if necessary. */
132
0
    if (engine_list_head == e)
133
0
        engine_list_head = e->next;
134
0
    if (engine_list_tail == e)
135
0
        engine_list_tail = e->prev;
136
0
    engine_free_util(e, 0);
137
0
    return 1;
138
0
}
139
140
/* Add engine to dynamic engine list. */
141
int engine_add_dynamic_id(ENGINE *e, ENGINE_DYNAMIC_ID dynamic_id,
142
                          int not_locked)
143
0
{
144
0
    int result = 0;
145
0
    ENGINE *iterator = NULL;
146
147
0
    if (e == NULL)
148
0
        return 0;
149
150
0
    if (e->dynamic_id == NULL && dynamic_id == NULL)
151
0
        return 0;
152
153
0
    if (not_locked && !CRYPTO_THREAD_write_lock(global_engine_lock))
154
0
        return 0;
155
156
0
    if (dynamic_id != NULL) {
157
0
        iterator = engine_dyn_list_head;
158
0
        while (iterator != NULL) {
159
0
            if (iterator->dynamic_id == dynamic_id)
160
0
                goto err;
161
0
            iterator = iterator->next;
162
0
        }
163
0
        if (e->dynamic_id != NULL)
164
0
            goto err;
165
0
        e->dynamic_id = dynamic_id;
166
0
    }
167
168
0
    if (engine_dyn_list_head == NULL) {
169
        /* We are adding to an empty list. */
170
0
        if (engine_dyn_list_tail != NULL)
171
0
            goto err;
172
0
        engine_dyn_list_head = e;
173
0
        e->prev_dyn = NULL;
174
0
    } else {
175
        /* We are adding to the tail of an existing list. */
176
0
        if (engine_dyn_list_tail == NULL
177
0
            || engine_dyn_list_tail->next_dyn != NULL)
178
0
            goto err;
179
0
        engine_dyn_list_tail->next_dyn = e;
180
0
        e->prev_dyn = engine_dyn_list_tail;
181
0
    }
182
183
0
    engine_dyn_list_tail = e;
184
0
    e->next_dyn = NULL;
185
0
    result = 1;
186
187
0
 err:
188
0
    if (not_locked)
189
0
        CRYPTO_THREAD_unlock(global_engine_lock);
190
0
    return result;
191
0
}
192
193
/* Remove engine from dynamic engine list. */
194
void engine_remove_dynamic_id(ENGINE *e, int not_locked)
195
0
{
196
0
    if (e == NULL || e->dynamic_id == NULL)
197
0
        return;
198
199
0
    if (not_locked && !CRYPTO_THREAD_write_lock(global_engine_lock))
200
0
        return;
201
202
0
    e->dynamic_id = NULL;
203
204
    /* un-link e from the chain. */
205
0
    if (e->next_dyn != NULL)
206
0
        e->next_dyn->prev_dyn = e->prev_dyn;
207
0
    if (e->prev_dyn != NULL)
208
0
        e->prev_dyn->next_dyn = e->next_dyn;
209
    /* Correct our head/tail if necessary. */
210
0
    if (engine_dyn_list_head == e)
211
0
        engine_dyn_list_head = e->next_dyn;
212
0
    if (engine_dyn_list_tail == e)
213
0
        engine_dyn_list_tail = e->prev_dyn;
214
215
0
    if (not_locked)
216
0
        CRYPTO_THREAD_unlock(global_engine_lock);
217
0
}
218
219
/* Get the first/last "ENGINE" type available. */
220
ENGINE *ENGINE_get_first(void)
221
0
{
222
0
    ENGINE *ret;
223
224
0
    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
225
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_MALLOC_FAILURE);
226
0
        return NULL;
227
0
    }
228
229
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
230
0
        return NULL;
231
0
    ret = engine_list_head;
232
0
    if (ret) {
233
0
        ret->struct_ref++;
234
0
        ENGINE_REF_PRINT(ret, 0, 1);
235
0
    }
236
0
    CRYPTO_THREAD_unlock(global_engine_lock);
237
0
    return ret;
238
0
}
239
240
ENGINE *ENGINE_get_last(void)
241
0
{
242
0
    ENGINE *ret;
243
244
0
    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
245
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_MALLOC_FAILURE);
246
0
        return NULL;
247
0
    }
248
249
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
250
0
        return NULL;
251
0
    ret = engine_list_tail;
252
0
    if (ret) {
253
0
        ret->struct_ref++;
254
0
        ENGINE_REF_PRINT(ret, 0, 1);
255
0
    }
256
0
    CRYPTO_THREAD_unlock(global_engine_lock);
257
0
    return ret;
258
0
}
259
260
/* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */
261
ENGINE *ENGINE_get_next(ENGINE *e)
262
0
{
263
0
    ENGINE *ret = NULL;
264
0
    if (e == NULL) {
265
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
266
0
        return NULL;
267
0
    }
268
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
269
0
        return NULL;
270
0
    ret = e->next;
271
0
    if (ret) {
272
        /* Return a valid structural reference to the next ENGINE */
273
0
        ret->struct_ref++;
274
0
        ENGINE_REF_PRINT(ret, 0, 1);
275
0
    }
276
0
    CRYPTO_THREAD_unlock(global_engine_lock);
277
    /* Release the structural reference to the previous ENGINE */
278
0
    ENGINE_free(e);
279
0
    return ret;
280
0
}
281
282
ENGINE *ENGINE_get_prev(ENGINE *e)
283
0
{
284
0
    ENGINE *ret = NULL;
285
0
    if (e == NULL) {
286
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
287
0
        return NULL;
288
0
    }
289
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
290
0
        return NULL;
291
0
    ret = e->prev;
292
0
    if (ret) {
293
        /* Return a valid structural reference to the next ENGINE */
294
0
        ret->struct_ref++;
295
0
        ENGINE_REF_PRINT(ret, 0, 1);
296
0
    }
297
0
    CRYPTO_THREAD_unlock(global_engine_lock);
298
    /* Release the structural reference to the previous ENGINE */
299
0
    ENGINE_free(e);
300
0
    return ret;
301
0
}
302
303
/* Add another "ENGINE" type into the list. */
304
int ENGINE_add(ENGINE *e)
305
0
{
306
0
    int to_return = 1;
307
0
    if (e == NULL) {
308
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
309
0
        return 0;
310
0
    }
311
0
    if ((e->id == NULL) || (e->name == NULL)) {
312
0
        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_ID_OR_NAME_MISSING);
313
0
        return 0;
314
0
    }
315
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
316
0
        return 0;
317
0
    if (!engine_list_add(e)) {
318
0
        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
319
0
        to_return = 0;
320
0
    }
321
0
    CRYPTO_THREAD_unlock(global_engine_lock);
322
0
    return to_return;
323
0
}
324
325
/* Remove an existing "ENGINE" type from the array. */
326
int ENGINE_remove(ENGINE *e)
327
0
{
328
0
    int to_return = 1;
329
0
    if (e == NULL) {
330
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
331
0
        return 0;
332
0
    }
333
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
334
0
        return 0;
335
0
    if (!engine_list_remove(e)) {
336
0
        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
337
0
        to_return = 0;
338
0
    }
339
0
    CRYPTO_THREAD_unlock(global_engine_lock);
340
0
    return to_return;
341
0
}
342
343
static void engine_cpy(ENGINE *dest, const ENGINE *src)
344
0
{
345
0
    dest->id = src->id;
346
0
    dest->name = src->name;
347
0
    dest->rsa_meth = src->rsa_meth;
348
0
#ifndef OPENSSL_NO_DSA
349
0
    dest->dsa_meth = src->dsa_meth;
350
0
#endif
351
0
#ifndef OPENSSL_NO_DH
352
0
    dest->dh_meth = src->dh_meth;
353
0
#endif
354
0
#ifndef OPENSSL_NO_EC
355
0
    dest->ec_meth = src->ec_meth;
356
0
#endif
357
0
    dest->rand_meth = src->rand_meth;
358
0
    dest->ciphers = src->ciphers;
359
0
    dest->digests = src->digests;
360
0
    dest->pkey_meths = src->pkey_meths;
361
0
    dest->destroy = src->destroy;
362
0
    dest->init = src->init;
363
0
    dest->finish = src->finish;
364
0
    dest->ctrl = src->ctrl;
365
0
    dest->load_privkey = src->load_privkey;
366
0
    dest->load_pubkey = src->load_pubkey;
367
0
    dest->cmd_defns = src->cmd_defns;
368
0
    dest->flags = src->flags;
369
0
    dest->dynamic_id = src->dynamic_id;
370
0
    engine_add_dynamic_id(dest, NULL, 0);
371
0
}
372
373
ENGINE *ENGINE_by_id(const char *id)
374
0
{
375
0
    ENGINE *iterator;
376
0
    char *load_dir = NULL;
377
0
    if (id == NULL) {
378
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
379
0
        return NULL;
380
0
    }
381
0
    ENGINE_load_builtin_engines();
382
383
0
    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
384
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_MALLOC_FAILURE);
385
0
        return NULL;
386
0
    }
387
388
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
389
0
        return NULL;
390
0
    iterator = engine_list_head;
391
0
    while (iterator && (strcmp(id, iterator->id) != 0))
392
0
        iterator = iterator->next;
393
0
    if (iterator != NULL) {
394
        /*
395
         * We need to return a structural reference. If this is an ENGINE
396
         * type that returns copies, make a duplicate - otherwise increment
397
         * the existing ENGINE's reference count.
398
         */
399
0
        if (iterator->flags & ENGINE_FLAGS_BY_ID_COPY) {
400
0
            ENGINE *cp = ENGINE_new();
401
0
            if (cp == NULL)
402
0
                iterator = NULL;
403
0
            else {
404
0
                engine_cpy(cp, iterator);
405
0
                iterator = cp;
406
0
            }
407
0
        } else {
408
0
            iterator->struct_ref++;
409
0
            ENGINE_REF_PRINT(iterator, 0, 1);
410
0
        }
411
0
    }
412
0
    CRYPTO_THREAD_unlock(global_engine_lock);
413
0
    if (iterator != NULL)
414
0
        return iterator;
415
    /*
416
     * Prevent infinite recursion if we're looking for the dynamic engine.
417
     */
418
0
    if (strcmp(id, "dynamic")) {
419
0
        if ((load_dir = ossl_safe_getenv("OPENSSL_ENGINES")) == NULL)
420
0
            load_dir = ENGINESDIR;
421
0
        iterator = ENGINE_by_id("dynamic");
422
0
        if (!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) ||
423
0
            !ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) ||
424
0
            !ENGINE_ctrl_cmd_string(iterator, "DIR_ADD",
425
0
                                    load_dir, 0) ||
426
0
            !ENGINE_ctrl_cmd_string(iterator, "LIST_ADD", "1", 0) ||
427
0
            !ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0))
428
0
            goto notfound;
429
0
        return iterator;
430
0
    }
431
0
 notfound:
432
0
    ENGINE_free(iterator);
433
0
    ERR_raise_data(ERR_LIB_ENGINE, ENGINE_R_NO_SUCH_ENGINE, "id=%s", id);
434
0
    return NULL;
435
    /* EEK! Experimental code ends */
436
0
}
437
438
int ENGINE_up_ref(ENGINE *e)
439
0
{
440
0
    int i;
441
0
    if (e == NULL) {
442
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
443
0
        return 0;
444
0
    }
445
0
    CRYPTO_UP_REF(&e->struct_ref, &i, global_engine_lock);
446
0
    return 1;
447
0
}