Coverage Report

Created: 2025-06-13 06:58

/src/openssl32/crypto/engine/eng_list.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2001-2024 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
0
    int ref;
62
63
0
    if (e == NULL) {
64
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
65
0
        return 0;
66
0
    }
67
0
    iterator = engine_list_head;
68
0
    while (iterator && !conflict) {
69
0
        conflict = (strcmp(iterator->id, e->id) == 0);
70
0
        iterator = iterator->next;
71
0
    }
72
0
    if (conflict) {
73
0
        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_CONFLICTING_ENGINE_ID);
74
0
        return 0;
75
0
    }
76
77
    /*
78
     * Having the engine in the list assumes a structural reference.
79
     */
80
0
    if (!CRYPTO_UP_REF(&e->struct_ref, &ref)) {
81
0
            ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
82
0
            return 0;
83
0
    }
84
0
    ENGINE_REF_PRINT(e, 0, 1);
85
0
    if (engine_list_head == NULL) {
86
        /* We are adding to an empty list. */
87
0
        if (engine_list_tail != NULL) {
88
0
            CRYPTO_DOWN_REF(&e->struct_ref, &ref);
89
0
            ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
90
0
            return 0;
91
0
        }
92
        /*
93
         * The first time the list allocates, we should register the cleanup.
94
         */
95
0
        if (!engine_cleanup_add_last(engine_list_cleanup)) {
96
0
            CRYPTO_DOWN_REF(&e->struct_ref, &ref);
97
0
            ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
98
0
            return 0;
99
0
        }
100
0
        engine_list_head = e;
101
0
        e->prev = NULL;
102
0
    } else {
103
        /* We are adding to the tail of an existing list. */
104
0
        if ((engine_list_tail == NULL) || (engine_list_tail->next != NULL)) {
105
0
            CRYPTO_DOWN_REF(&e->struct_ref, &ref);
106
0
            ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
107
0
            return 0;
108
0
        }
109
0
        engine_list_tail->next = e;
110
0
        e->prev = engine_list_tail;
111
0
    }
112
113
    /* However it came to be, e is the last item in the list. */
114
0
    engine_list_tail = e;
115
0
    e->next = NULL;
116
0
    return 1;
117
0
}
118
119
static int engine_list_remove(ENGINE *e)
120
0
{
121
0
    ENGINE *iterator;
122
123
0
    if (e == NULL) {
124
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
125
0
        return 0;
126
0
    }
127
    /* We need to check that e is in our linked list! */
128
0
    iterator = engine_list_head;
129
0
    while (iterator && (iterator != e))
130
0
        iterator = iterator->next;
131
0
    if (iterator == NULL) {
132
0
        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_ENGINE_IS_NOT_IN_LIST);
133
0
        return 0;
134
0
    }
135
    /* un-link e from the chain. */
136
0
    if (e->next)
137
0
        e->next->prev = e->prev;
138
0
    if (e->prev)
139
0
        e->prev->next = e->next;
140
    /* Correct our head/tail if necessary. */
141
0
    if (engine_list_head == e)
142
0
        engine_list_head = e->next;
143
0
    if (engine_list_tail == e)
144
0
        engine_list_tail = e->prev;
145
0
    engine_free_util(e, 0);
146
0
    return 1;
147
0
}
148
149
/* Add engine to dynamic engine list. */
150
int engine_add_dynamic_id(ENGINE *e, ENGINE_DYNAMIC_ID dynamic_id,
151
                          int not_locked)
152
0
{
153
0
    int result = 0;
154
0
    ENGINE *iterator = NULL;
155
156
0
    if (e == NULL)
157
0
        return 0;
158
159
0
    if (e->dynamic_id == NULL && dynamic_id == NULL)
160
0
        return 0;
161
162
0
    if (not_locked && !CRYPTO_THREAD_write_lock(global_engine_lock))
163
0
        return 0;
164
165
0
    if (dynamic_id != NULL) {
166
0
        iterator = engine_dyn_list_head;
167
0
        while (iterator != NULL) {
168
0
            if (iterator->dynamic_id == dynamic_id)
169
0
                goto err;
170
0
            iterator = iterator->next;
171
0
        }
172
0
        if (e->dynamic_id != NULL)
173
0
            goto err;
174
0
        e->dynamic_id = dynamic_id;
175
0
    }
176
177
0
    if (engine_dyn_list_head == NULL) {
178
        /* We are adding to an empty list. */
179
0
        if (engine_dyn_list_tail != NULL)
180
0
            goto err;
181
0
        engine_dyn_list_head = e;
182
0
        e->prev_dyn = NULL;
183
0
    } else {
184
        /* We are adding to the tail of an existing list. */
185
0
        if (engine_dyn_list_tail == NULL
186
0
            || engine_dyn_list_tail->next_dyn != NULL)
187
0
            goto err;
188
0
        engine_dyn_list_tail->next_dyn = e;
189
0
        e->prev_dyn = engine_dyn_list_tail;
190
0
    }
191
192
0
    engine_dyn_list_tail = e;
193
0
    e->next_dyn = NULL;
194
0
    result = 1;
195
196
0
 err:
197
0
    if (not_locked)
198
0
        CRYPTO_THREAD_unlock(global_engine_lock);
199
0
    return result;
200
0
}
201
202
/* Remove engine from dynamic engine list. */
203
void engine_remove_dynamic_id(ENGINE *e, int not_locked)
204
0
{
205
0
    if (e == NULL || e->dynamic_id == NULL)
206
0
        return;
207
208
0
    if (not_locked && !CRYPTO_THREAD_write_lock(global_engine_lock))
209
0
        return;
210
211
0
    e->dynamic_id = NULL;
212
213
    /* un-link e from the chain. */
214
0
    if (e->next_dyn != NULL)
215
0
        e->next_dyn->prev_dyn = e->prev_dyn;
216
0
    if (e->prev_dyn != NULL)
217
0
        e->prev_dyn->next_dyn = e->next_dyn;
218
    /* Correct our head/tail if necessary. */
219
0
    if (engine_dyn_list_head == e)
220
0
        engine_dyn_list_head = e->next_dyn;
221
0
    if (engine_dyn_list_tail == e)
222
0
        engine_dyn_list_tail = e->prev_dyn;
223
224
0
    if (not_locked)
225
0
        CRYPTO_THREAD_unlock(global_engine_lock);
226
0
}
227
228
/* Get the first/last "ENGINE" type available. */
229
ENGINE *ENGINE_get_first(void)
230
0
{
231
0
    ENGINE *ret;
232
233
0
    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
234
        /* Maybe this should be raised in do_engine_lock_init() */
235
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
236
0
        return NULL;
237
0
    }
238
239
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
240
0
        return NULL;
241
0
    ret = engine_list_head;
242
0
    if (ret) {
243
0
        int ref;
244
245
0
        if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) {
246
0
            CRYPTO_THREAD_unlock(global_engine_lock);
247
0
            ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
248
0
            return NULL;
249
0
        }
250
0
        ENGINE_REF_PRINT(ret, 0, 1);
251
0
    }
252
0
    CRYPTO_THREAD_unlock(global_engine_lock);
253
0
    return ret;
254
0
}
255
256
ENGINE *ENGINE_get_last(void)
257
0
{
258
0
    ENGINE *ret;
259
260
0
    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
261
        /* Maybe this should be raised in do_engine_lock_init() */
262
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
263
0
        return NULL;
264
0
    }
265
266
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
267
0
        return NULL;
268
0
    ret = engine_list_tail;
269
0
    if (ret) {
270
0
        int ref;
271
272
0
        if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) {
273
0
            CRYPTO_THREAD_unlock(global_engine_lock);
274
0
            ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
275
0
            return NULL;
276
0
        }
277
0
        ENGINE_REF_PRINT(ret, 0, 1);
278
0
    }
279
0
    CRYPTO_THREAD_unlock(global_engine_lock);
280
0
    return ret;
281
0
}
282
283
/* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */
284
ENGINE *ENGINE_get_next(ENGINE *e)
285
0
{
286
0
    ENGINE *ret = NULL;
287
0
    if (e == NULL) {
288
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
289
0
        return NULL;
290
0
    }
291
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
292
0
        return NULL;
293
0
    ret = e->next;
294
0
    if (ret) {
295
0
        int ref;
296
297
        /* Return a valid structural reference to the next ENGINE */
298
0
        if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) {
299
0
            CRYPTO_THREAD_unlock(global_engine_lock);
300
0
            ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
301
0
            return NULL;
302
0
        }
303
0
        ENGINE_REF_PRINT(ret, 0, 1);
304
0
    }
305
0
    CRYPTO_THREAD_unlock(global_engine_lock);
306
    /* Release the structural reference to the previous ENGINE */
307
0
    ENGINE_free(e);
308
0
    return ret;
309
0
}
310
311
ENGINE *ENGINE_get_prev(ENGINE *e)
312
0
{
313
0
    ENGINE *ret = NULL;
314
0
    if (e == NULL) {
315
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
316
0
        return NULL;
317
0
    }
318
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
319
0
        return NULL;
320
0
    ret = e->prev;
321
0
    if (ret) {
322
0
        int ref;
323
324
        /* Return a valid structural reference to the next ENGINE */
325
0
        if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) {
326
0
            CRYPTO_THREAD_unlock(global_engine_lock);
327
0
            ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
328
0
            return NULL;
329
0
        }
330
0
        ENGINE_REF_PRINT(ret, 0, 1);
331
0
    }
332
0
    CRYPTO_THREAD_unlock(global_engine_lock);
333
    /* Release the structural reference to the previous ENGINE */
334
0
    ENGINE_free(e);
335
0
    return ret;
336
0
}
337
338
/* Add another "ENGINE" type into the list. */
339
int ENGINE_add(ENGINE *e)
340
0
{
341
0
    int to_return = 1;
342
0
    if (e == NULL) {
343
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
344
0
        return 0;
345
0
    }
346
0
    if ((e->id == NULL) || (e->name == NULL)) {
347
0
        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_ID_OR_NAME_MISSING);
348
0
        return 0;
349
0
    }
350
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
351
0
        return 0;
352
0
    if (!engine_list_add(e)) {
353
0
        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
354
0
        to_return = 0;
355
0
    }
356
0
    CRYPTO_THREAD_unlock(global_engine_lock);
357
0
    return to_return;
358
0
}
359
360
/* Remove an existing "ENGINE" type from the array. */
361
int ENGINE_remove(ENGINE *e)
362
0
{
363
0
    int to_return = 1;
364
0
    if (e == NULL) {
365
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
366
0
        return 0;
367
0
    }
368
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
369
0
        return 0;
370
0
    if (!engine_list_remove(e)) {
371
0
        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
372
0
        to_return = 0;
373
0
    }
374
0
    CRYPTO_THREAD_unlock(global_engine_lock);
375
0
    return to_return;
376
0
}
377
378
static void engine_cpy(ENGINE *dest, const ENGINE *src)
379
0
{
380
0
    dest->id = src->id;
381
0
    dest->name = src->name;
382
0
    dest->rsa_meth = src->rsa_meth;
383
0
#ifndef OPENSSL_NO_DSA
384
0
    dest->dsa_meth = src->dsa_meth;
385
0
#endif
386
0
#ifndef OPENSSL_NO_DH
387
0
    dest->dh_meth = src->dh_meth;
388
0
#endif
389
0
#ifndef OPENSSL_NO_EC
390
0
    dest->ec_meth = src->ec_meth;
391
0
#endif
392
0
    dest->rand_meth = src->rand_meth;
393
0
    dest->ciphers = src->ciphers;
394
0
    dest->digests = src->digests;
395
0
    dest->pkey_meths = src->pkey_meths;
396
0
    dest->destroy = src->destroy;
397
0
    dest->init = src->init;
398
0
    dest->finish = src->finish;
399
0
    dest->ctrl = src->ctrl;
400
0
    dest->load_privkey = src->load_privkey;
401
0
    dest->load_pubkey = src->load_pubkey;
402
0
    dest->cmd_defns = src->cmd_defns;
403
0
    dest->flags = src->flags;
404
0
    dest->dynamic_id = src->dynamic_id;
405
0
    engine_add_dynamic_id(dest, NULL, 0);
406
0
}
407
408
ENGINE *ENGINE_by_id(const char *id)
409
0
{
410
0
    ENGINE *iterator;
411
0
    char *load_dir = NULL;
412
0
    if (id == NULL) {
413
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
414
0
        return NULL;
415
0
    }
416
0
    ENGINE_load_builtin_engines();
417
418
0
    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
419
        /* Maybe this should be raised in do_engine_lock_init() */
420
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
421
0
        return NULL;
422
0
    }
423
424
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
425
0
        return NULL;
426
0
    iterator = engine_list_head;
427
0
    while (iterator && (strcmp(id, iterator->id) != 0))
428
0
        iterator = iterator->next;
429
0
    if (iterator != NULL) {
430
        /*
431
         * We need to return a structural reference. If this is an ENGINE
432
         * type that returns copies, make a duplicate - otherwise increment
433
         * the existing ENGINE's reference count.
434
         */
435
0
        if (iterator->flags & ENGINE_FLAGS_BY_ID_COPY) {
436
0
            ENGINE *cp = ENGINE_new();
437
0
            if (cp == NULL)
438
0
                iterator = NULL;
439
0
            else {
440
0
                engine_cpy(cp, iterator);
441
0
                iterator = cp;
442
0
            }
443
0
        } else {
444
0
            int ref;
445
446
0
            if (!CRYPTO_UP_REF(&iterator->struct_ref, &ref)) {
447
0
                CRYPTO_THREAD_unlock(global_engine_lock);
448
0
                ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
449
0
                return NULL;
450
0
            }
451
0
            ENGINE_REF_PRINT(iterator, 0, 1);
452
0
        }
453
0
    }
454
0
    CRYPTO_THREAD_unlock(global_engine_lock);
455
0
    if (iterator != NULL)
456
0
        return iterator;
457
    /*
458
     * Prevent infinite recursion if we're looking for the dynamic engine.
459
     */
460
0
    if (strcmp(id, "dynamic")) {
461
0
        if ((load_dir = ossl_safe_getenv("OPENSSL_ENGINES")) == NULL)
462
0
            load_dir = ENGINESDIR;
463
0
        iterator = ENGINE_by_id("dynamic");
464
0
        if (!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) ||
465
0
            !ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) ||
466
0
            !ENGINE_ctrl_cmd_string(iterator, "DIR_ADD",
467
0
                                    load_dir, 0) ||
468
0
            !ENGINE_ctrl_cmd_string(iterator, "LIST_ADD", "1", 0) ||
469
0
            !ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0))
470
0
            goto notfound;
471
0
        return iterator;
472
0
    }
473
0
 notfound:
474
0
    ENGINE_free(iterator);
475
0
    ERR_raise_data(ERR_LIB_ENGINE, ENGINE_R_NO_SUCH_ENGINE, "id=%s", id);
476
0
    return NULL;
477
    /* EEK! Experimental code ends */
478
0
}
479
480
int ENGINE_up_ref(ENGINE *e)
481
0
{
482
0
    int i;
483
0
    if (e == NULL) {
484
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
485
0
        return 0;
486
0
    }
487
0
    CRYPTO_UP_REF(&e->struct_ref, &i);
488
0
    return 1;
489
0
}