Coverage Report

Created: 2023-09-25 06:45

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