Coverage Report

Created: 2024-05-21 06:33

/src/openssl/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
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
            ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
247
0
            return NULL;
248
0
        }
249
0
        ENGINE_REF_PRINT(ret, 0, 1);
250
0
    }
251
0
    CRYPTO_THREAD_unlock(global_engine_lock);
252
0
    return ret;
253
0
}
254
255
ENGINE *ENGINE_get_last(void)
256
0
{
257
0
    ENGINE *ret;
258
259
0
    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
260
        /* Maybe this should be raised in do_engine_lock_init() */
261
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
262
0
        return NULL;
263
0
    }
264
265
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
266
0
        return NULL;
267
0
    ret = engine_list_tail;
268
0
    if (ret) {
269
0
        int ref;
270
271
0
        if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) {
272
0
            ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
273
0
            return NULL;
274
0
        }
275
0
        ENGINE_REF_PRINT(ret, 0, 1);
276
0
    }
277
0
    CRYPTO_THREAD_unlock(global_engine_lock);
278
0
    return ret;
279
0
}
280
281
/* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */
282
ENGINE *ENGINE_get_next(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->next;
292
0
    if (ret) {
293
0
        int ref;
294
295
        /* Return a valid structural reference to the next ENGINE */
296
0
        if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) {
297
0
            ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
298
0
            return NULL;
299
0
        }
300
0
        ENGINE_REF_PRINT(ret, 0, 1);
301
0
    }
302
0
    CRYPTO_THREAD_unlock(global_engine_lock);
303
    /* Release the structural reference to the previous ENGINE */
304
0
    ENGINE_free(e);
305
0
    return ret;
306
0
}
307
308
ENGINE *ENGINE_get_prev(ENGINE *e)
309
0
{
310
0
    ENGINE *ret = NULL;
311
0
    if (e == NULL) {
312
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
313
0
        return NULL;
314
0
    }
315
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
316
0
        return NULL;
317
0
    ret = e->prev;
318
0
    if (ret) {
319
0
        int ref;
320
321
        /* Return a valid structural reference to the next ENGINE */
322
0
        if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) {
323
0
            ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
324
0
            return NULL;
325
0
        }
326
0
        ENGINE_REF_PRINT(ret, 0, 1);
327
0
    }
328
0
    CRYPTO_THREAD_unlock(global_engine_lock);
329
    /* Release the structural reference to the previous ENGINE */
330
0
    ENGINE_free(e);
331
0
    return ret;
332
0
}
333
334
/* Add another "ENGINE" type into the list. */
335
int ENGINE_add(ENGINE *e)
336
0
{
337
0
    int to_return = 1;
338
0
    if (e == NULL) {
339
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
340
0
        return 0;
341
0
    }
342
0
    if ((e->id == NULL) || (e->name == NULL)) {
343
0
        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_ID_OR_NAME_MISSING);
344
0
        return 0;
345
0
    }
346
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
347
0
        return 0;
348
0
    if (!engine_list_add(e)) {
349
0
        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
350
0
        to_return = 0;
351
0
    }
352
0
    CRYPTO_THREAD_unlock(global_engine_lock);
353
0
    return to_return;
354
0
}
355
356
/* Remove an existing "ENGINE" type from the array. */
357
int ENGINE_remove(ENGINE *e)
358
0
{
359
0
    int to_return = 1;
360
0
    if (e == NULL) {
361
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
362
0
        return 0;
363
0
    }
364
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
365
0
        return 0;
366
0
    if (!engine_list_remove(e)) {
367
0
        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
368
0
        to_return = 0;
369
0
    }
370
0
    CRYPTO_THREAD_unlock(global_engine_lock);
371
0
    return to_return;
372
0
}
373
374
static void engine_cpy(ENGINE *dest, const ENGINE *src)
375
0
{
376
0
    dest->id = src->id;
377
0
    dest->name = src->name;
378
0
    dest->rsa_meth = src->rsa_meth;
379
0
#ifndef OPENSSL_NO_DSA
380
0
    dest->dsa_meth = src->dsa_meth;
381
0
#endif
382
0
#ifndef OPENSSL_NO_DH
383
0
    dest->dh_meth = src->dh_meth;
384
0
#endif
385
0
#ifndef OPENSSL_NO_EC
386
0
    dest->ec_meth = src->ec_meth;
387
0
#endif
388
0
    dest->rand_meth = src->rand_meth;
389
0
    dest->ciphers = src->ciphers;
390
0
    dest->digests = src->digests;
391
0
    dest->pkey_meths = src->pkey_meths;
392
0
    dest->destroy = src->destroy;
393
0
    dest->init = src->init;
394
0
    dest->finish = src->finish;
395
0
    dest->ctrl = src->ctrl;
396
0
    dest->load_privkey = src->load_privkey;
397
0
    dest->load_pubkey = src->load_pubkey;
398
0
    dest->cmd_defns = src->cmd_defns;
399
0
    dest->flags = src->flags;
400
0
    dest->dynamic_id = src->dynamic_id;
401
0
    engine_add_dynamic_id(dest, NULL, 0);
402
0
}
403
404
ENGINE *ENGINE_by_id(const char *id)
405
0
{
406
0
    ENGINE *iterator;
407
0
    char *load_dir = NULL;
408
0
    if (id == NULL) {
409
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
410
0
        return NULL;
411
0
    }
412
0
    ENGINE_load_builtin_engines();
413
414
0
    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
415
        /* Maybe this should be raised in do_engine_lock_init() */
416
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
417
0
        return NULL;
418
0
    }
419
420
0
    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
421
0
        return NULL;
422
0
    iterator = engine_list_head;
423
0
    while (iterator && (strcmp(id, iterator->id) != 0))
424
0
        iterator = iterator->next;
425
0
    if (iterator != NULL) {
426
        /*
427
         * We need to return a structural reference. If this is an ENGINE
428
         * type that returns copies, make a duplicate - otherwise increment
429
         * the existing ENGINE's reference count.
430
         */
431
0
        if (iterator->flags & ENGINE_FLAGS_BY_ID_COPY) {
432
0
            ENGINE *cp = ENGINE_new();
433
0
            if (cp == NULL)
434
0
                iterator = NULL;
435
0
            else {
436
0
                engine_cpy(cp, iterator);
437
0
                iterator = cp;
438
0
            }
439
0
        } else {
440
0
            int ref;
441
442
0
            if (!CRYPTO_UP_REF(&iterator->struct_ref, &ref)) {
443
0
                CRYPTO_THREAD_unlock(global_engine_lock);
444
0
                ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB);
445
0
                return NULL;
446
0
            }
447
0
            ENGINE_REF_PRINT(iterator, 0, 1);
448
0
        }
449
0
    }
450
0
    CRYPTO_THREAD_unlock(global_engine_lock);
451
0
    if (iterator != NULL)
452
0
        return iterator;
453
    /*
454
     * Prevent infinite recursion if we're looking for the dynamic engine.
455
     */
456
0
    if (strcmp(id, "dynamic")) {
457
0
        if ((load_dir = ossl_safe_getenv("OPENSSL_ENGINES")) == NULL)
458
0
            load_dir = ENGINESDIR;
459
0
        iterator = ENGINE_by_id("dynamic");
460
0
        if (!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) ||
461
0
            !ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) ||
462
0
            !ENGINE_ctrl_cmd_string(iterator, "DIR_ADD",
463
0
                                    load_dir, 0) ||
464
0
            !ENGINE_ctrl_cmd_string(iterator, "LIST_ADD", "1", 0) ||
465
0
            !ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0))
466
0
            goto notfound;
467
0
        return iterator;
468
0
    }
469
0
 notfound:
470
0
    ENGINE_free(iterator);
471
0
    ERR_raise_data(ERR_LIB_ENGINE, ENGINE_R_NO_SUCH_ENGINE, "id=%s", id);
472
0
    return NULL;
473
    /* EEK! Experimental code ends */
474
0
}
475
476
int ENGINE_up_ref(ENGINE *e)
477
0
{
478
0
    int i;
479
0
    if (e == NULL) {
480
0
        ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
481
0
        return 0;
482
0
    }
483
0
    CRYPTO_UP_REF(&e->struct_ref, &i);
484
0
    return 1;
485
0
}