Coverage Report

Created: 2026-06-16 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/crypto/property/property.c
Line
Count
Source
1
/*
2
 * Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved.
3
 * Copyright (c) 2019, 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
#include <string.h>
12
#include <stdio.h>
13
#include <stdarg.h>
14
#include <openssl/crypto.h>
15
#include <openssl/provider.h>
16
#include "internal/property.h"
17
#include "internal/provider.h"
18
#include "internal/hashfunc.h"
19
#include "internal/tsan_assist.h"
20
#include "internal/threads_common.h"
21
#include "internal/list.h"
22
#include "internal/time.h"
23
#include <openssl/lhash.h>
24
#include <openssl/rand.h>
25
#include <openssl/trace.h>
26
#include "crypto/sparse_array.h"
27
#include "property_local.h"
28
#include "crypto/context.h"
29
30
/*
31
 * The shard count was determined through performance testing with the evp_fetch
32
 * tool on an Intel Xeon Gold 6248R CPU @ 3.00GHz. Testing showed that 4 shards
33
 * delivered the best performance for 16 or
34
 * more threads, and close to best performance at below 16 threads.
35
 */
36
#ifndef NUM_SHARDS_BITS
37
174k
#define NUM_SHARDS_BITS 2
38
#endif
39
88.4k
#define NUM_SHARDS (1 << NUM_SHARDS_BITS)
40
41
#ifndef MAX_CACHE_LINES_BITS
42
85.5k
#define MAX_CACHE_LINES_BITS 3
43
#endif
44
85.5k
#define MAX_CACHE_LINES (1 << MAX_CACHE_LINES_BITS)
45
46
typedef struct {
47
    void *method;
48
    int (*up_ref)(void *);
49
    void (*free)(void *);
50
} METHOD;
51
52
typedef struct {
53
    const OSSL_PROVIDER *provider;
54
    OSSL_PROPERTY_LIST *properties;
55
    METHOD method;
56
} IMPLEMENTATION;
57
58
DEFINE_STACK_OF(IMPLEMENTATION)
59
60
typedef struct query_st {
61
    struct query_st *next; /* list pointer for lookup table */
62
    void *saptr; /* pointer to our owning STORED_ALGORITHM */
63
    int nid; /* nid of this query */
64
    int archived; /* Mark entry as no longer findable */
65
    OSSL_PROVIDER *prov; /*provider this belongs to */
66
    uint64_t prop_hash; /* hash of the property string */
67
    METHOD method; /* METHOD for this query */
68
} QUERY;
69
70
typedef struct {
71
    int nid;
72
    STACK_OF(IMPLEMENTATION) *impls;
73
} ALGORITHM;
74
75
typedef struct {
76
    SPARSE_ARRAY_OF(ALGORITHM) * algs;
77
78
    QUERY *cache_lists[MAX_CACHE_LINES];
79
    QUERY *archive;
80
81
    /*
82
     * Lock to protect each shard of |algs| from concurrent writing,
83
     * when individual implementations or queries are inserted.  This is used
84
     * by the appropriate functions here.
85
     */
86
    CRYPTO_RWLOCK *lock;
87
    CRYPTO_RWLOCK *alock;
88
89
    /* query cache specific values */
90
91
} STORED_ALGORITHMS;
92
93
static int ossl_method_store_atomic_insert_to_list(STORED_ALGORITHMS *sa, QUERY *new);
94
static int ossl_method_store_atomic_archive(STORED_ALGORITHMS *sa, QUERY *old);
95
static QUERY *ossl_method_store_atomic_find_in_list(STORED_ALGORITHMS *sa, int nid,
96
    OSSL_PROVIDER *prov, uint64_t prop_hash);
97
static void ossl_cache_lists_flush(STORED_ALGORITHMS *sa);
98
static void ossl_cache_lists_free(STORED_ALGORITHMS *sa);
99
static void ossl_method_store_atomic_clean_archive(STORED_ALGORITHMS *sa);
100
101
struct ossl_method_store_st {
102
    OSSL_LIB_CTX *ctx;
103
    STORED_ALGORITHMS *algs;
104
    /*
105
     * Lock to reserve the whole store.  This is used when fetching a set
106
     * of algorithms, via these functions, found in crypto/core_fetch.c:
107
     * ossl_method_construct_reserve_store()
108
     * ossl_method_construct_unreserve_store()
109
     */
110
    CRYPTO_RWLOCK *biglock;
111
};
112
113
DEFINE_SPARSE_ARRAY_OF(ALGORITHM);
114
115
DEFINE_STACK_OF(ALGORITHM)
116
117
typedef struct ossl_global_properties_st {
118
    OSSL_PROPERTY_LIST *list;
119
#ifndef FIPS_MODULE
120
    unsigned int no_mirrored : 1;
121
#endif
122
} OSSL_GLOBAL_PROPERTIES;
123
124
88.1k
#define stored_algs_shard(store, nid) (&(store)->algs[(nid) & (NUM_SHARDS - 1)])
125
126
static void ossl_method_cache_flush_alg(STORED_ALGORITHMS *sa,
127
    ALGORITHM *alg);
128
static void ossl_method_cache_flush(STORED_ALGORITHMS *sa, int nid);
129
130
/* Global properties are stored per library context */
131
void ossl_ctx_global_properties_free(void *vglobp)
132
0
{
133
0
    OSSL_GLOBAL_PROPERTIES *globp = vglobp;
134
135
0
    if (globp != NULL) {
136
0
        ossl_property_free(globp->list);
137
0
        OPENSSL_free(globp);
138
0
    }
139
0
}
140
141
void *ossl_ctx_global_properties_new(OSSL_LIB_CTX *ctx)
142
16
{
143
16
    return OPENSSL_zalloc(sizeof(OSSL_GLOBAL_PROPERTIES));
144
16
}
145
146
OSSL_PROPERTY_LIST **ossl_ctx_global_properties(OSSL_LIB_CTX *libctx,
147
    ossl_unused int loadconfig)
148
85
{
149
85
    OSSL_GLOBAL_PROPERTIES *globp;
150
151
85
#if !defined(FIPS_MODULE) && !defined(OPENSSL_NO_AUTOLOAD_CONFIG)
152
85
    if (loadconfig && !OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL))
153
0
        return NULL;
154
85
#endif
155
85
    globp = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES);
156
157
85
    return globp != NULL ? &globp->list : NULL;
158
85
}
159
160
#ifndef FIPS_MODULE
161
int ossl_global_properties_no_mirrored(OSSL_LIB_CTX *libctx)
162
0
{
163
0
    OSSL_GLOBAL_PROPERTIES *globp
164
0
        = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES);
165
166
0
    return globp != NULL && globp->no_mirrored ? 1 : 0;
167
0
}
168
169
void ossl_global_properties_stop_mirroring(OSSL_LIB_CTX *libctx)
170
0
{
171
0
    OSSL_GLOBAL_PROPERTIES *globp
172
0
        = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES);
173
174
0
    if (globp != NULL)
175
0
        globp->no_mirrored = 1;
176
0
}
177
#endif
178
179
static int ossl_method_up_ref(METHOD *method)
180
88.1k
{
181
88.1k
    return (*method->up_ref)(method->method);
182
88.1k
}
183
184
static void ossl_method_free(METHOD *method)
185
0
{
186
0
    (*method->free)(method->method);
187
0
}
188
189
static __owur int ossl_property_read_lock(STORED_ALGORITHMS *p)
190
85
{
191
85
    return p != NULL ? CRYPTO_THREAD_read_lock(p->lock) : 0;
192
85
}
193
194
static __owur int ossl_property_write_lock(STORED_ALGORITHMS *p)
195
2.64k
{
196
2.64k
    return p != NULL ? CRYPTO_THREAD_write_lock(p->lock) : 0;
197
2.64k
}
198
199
static int ossl_property_unlock(STORED_ALGORITHMS *p)
200
2.72k
{
201
2.72k
    return p != 0 ? CRYPTO_THREAD_unlock(p->lock) : 0;
202
2.72k
}
203
204
static void impl_free(IMPLEMENTATION *impl)
205
0
{
206
0
    if (impl != NULL) {
207
0
        ossl_method_free(&impl->method);
208
0
        OPENSSL_free(impl);
209
0
    }
210
0
}
211
212
static ossl_inline void impl_cache_free_unlinked(QUERY *elem)
213
0
{
214
0
    if (elem != NULL) {
215
0
        ossl_method_free(&elem->method);
216
0
        OPENSSL_free(elem);
217
0
    }
218
0
}
219
220
static void impl_cache_flush_alg(ALGORITHM *alg, STORED_ALGORITHMS *sa)
221
0
{
222
0
    QUERY *q;
223
0
    int i;
224
225
    /*
226
     * Instead of iterating over the hashtable with the
227
     * ossl_ht_foreach_until function, we just traverse the
228
     * linked list, as it much faster this way, as we avoid having
229
     * to visit lots of potentially empty nodes
230
     */
231
0
    for (i = 0; i < MAX_CACHE_LINES; i++) {
232
0
        if (!CRYPTO_atomic_load_ptr((void **)&sa->cache_lists[i], (void **)&q, sa->alock))
233
0
            return;
234
0
        while (q != NULL) {
235
0
            if (q->nid == alg->nid)
236
0
                ossl_method_store_atomic_archive(sa, q);
237
0
            if (!CRYPTO_atomic_load_ptr((void **)&q->next, (void **)&q, sa->alock))
238
0
                return;
239
0
        }
240
0
    }
241
0
}
242
243
static void alg_cleanup(ossl_uintmax_t idx, ALGORITHM *a, void *arg)
244
0
{
245
0
    STORED_ALGORITHMS *sa = arg;
246
247
0
    if (a != NULL) {
248
0
        sk_IMPLEMENTATION_pop_free(a->impls, &impl_free);
249
0
        OPENSSL_free(a);
250
0
    }
251
0
    if (sa != NULL)
252
0
        ossl_sa_ALGORITHM_set(sa->algs, idx, NULL);
253
0
}
254
255
static void stored_algs_free(STORED_ALGORITHMS *sa)
256
0
{
257
0
    if (sa == NULL)
258
0
        return;
259
260
0
    for (int i = 0; i < NUM_SHARDS; ++i) {
261
0
        ossl_sa_ALGORITHM_doall_arg(sa[i].algs, &alg_cleanup, &sa[i]);
262
0
        ossl_sa_ALGORITHM_free(sa[i].algs);
263
0
        ossl_cache_lists_free(&sa[i]);
264
0
        CRYPTO_THREAD_lock_free(sa[i].lock);
265
0
        CRYPTO_THREAD_lock_free(sa[i].alock);
266
0
    }
267
268
0
    OPENSSL_free(sa);
269
0
}
270
271
static STORED_ALGORITHMS *stored_algs_new(OSSL_LIB_CTX *ctx)
272
64
{
273
64
    STORED_ALGORITHMS *ret;
274
275
64
    ret = OPENSSL_calloc(NUM_SHARDS, sizeof(STORED_ALGORITHMS));
276
64
    if (ret == NULL)
277
0
        return NULL;
278
279
320
    for (int i = 0; i < NUM_SHARDS; ++i) {
280
256
        ret[i].algs = ossl_sa_ALGORITHM_new();
281
256
        if (ret[i].algs == NULL)
282
0
            goto err;
283
284
256
        ret[i].lock = CRYPTO_THREAD_lock_new();
285
256
        if (ret[i].lock == NULL)
286
0
            goto err;
287
256
        ret[i].alock = CRYPTO_THREAD_lock_new();
288
256
        if (ret[i].alock == NULL)
289
0
            goto err;
290
256
    }
291
292
64
    return ret;
293
294
0
err:
295
0
    stored_algs_free(ret);
296
297
0
    return NULL;
298
64
}
299
300
/*
301
 * The OSSL_LIB_CTX param here allows access to underlying property data needed
302
 * for computation
303
 */
304
OSSL_METHOD_STORE *ossl_method_store_new(OSSL_LIB_CTX *ctx)
305
64
{
306
64
    OSSL_METHOD_STORE *res;
307
308
64
    res = OPENSSL_zalloc(sizeof(*res));
309
64
    if (res != NULL) {
310
64
        res->ctx = ctx;
311
64
        if ((res->algs = stored_algs_new(ctx)) == NULL
312
64
            || (res->biglock = CRYPTO_THREAD_lock_new()) == NULL) {
313
0
            ossl_method_store_free(res);
314
0
            return NULL;
315
0
        }
316
64
    }
317
64
    return res;
318
64
}
319
320
void ossl_method_store_free(OSSL_METHOD_STORE *store)
321
0
{
322
0
    if (store == NULL)
323
0
        return;
324
325
0
    stored_algs_free(store->algs);
326
0
    CRYPTO_THREAD_lock_free(store->biglock);
327
0
    OPENSSL_free(store);
328
0
}
329
330
int ossl_method_lock_store(OSSL_METHOD_STORE *store)
331
85
{
332
85
    return store != NULL ? CRYPTO_THREAD_write_lock(store->biglock) : 0;
333
85
}
334
335
int ossl_method_unlock_store(OSSL_METHOD_STORE *store)
336
85
{
337
85
    return store != NULL ? CRYPTO_THREAD_unlock(store->biglock) : 0;
338
85
}
339
340
static ALGORITHM *ossl_method_store_retrieve(STORED_ALGORITHMS *sa, int nid)
341
5.36k
{
342
5.36k
    return ossl_sa_ALGORITHM_get(sa->algs, nid);
343
5.36k
}
344
345
static int ossl_method_store_insert(STORED_ALGORITHMS *sa, ALGORITHM *alg)
346
2.64k
{
347
2.64k
    return ossl_sa_ALGORITHM_set(sa->algs, alg->nid, alg);
348
2.64k
}
349
350
/**
351
 * @brief Adds a method to the specified method store.
352
 *
353
 * This function adds a new method to the provided method store, associating it
354
 * with a specified id, properties, and provider. The method is stored with
355
 * reference count and destruction callbacks.
356
 *
357
 * @param store Pointer to the OSSL_METHOD_STORE where the method will be added.
358
 *              Must be non-null.
359
 * @param prov Pointer to the OSSL_PROVIDER for the provider of the method.
360
 *             Must be non-null.
361
 * @param nid (identifier) associated with the method, must be > 0
362
 * @param properties String containing properties of the method.
363
 * @param method Pointer to the method to be added.
364
 * @param method_up_ref Function pointer for incrementing the method ref count.
365
 * @param method_destruct Function pointer for destroying the method.
366
 *
367
 * @return 1 if the method is successfully added, 0 on failure.
368
 *
369
 * If tracing is enabled, a message is printed indicating that the method is
370
 * being added to the method store.
371
 *
372
 * NOTE: The nid parameter here is _not_ a nid in the sense of the NID_* macros.
373
 * It is an internal unique identifier.
374
 */
375
int ossl_method_store_add(OSSL_METHOD_STORE *store, const OSSL_PROVIDER *prov,
376
    int nid, const char *properties, void *method,
377
    int (*method_up_ref)(void *),
378
    void (*method_destruct)(void *))
379
2.64k
{
380
2.64k
    STORED_ALGORITHMS *sa;
381
2.64k
    ALGORITHM *alg = NULL;
382
2.64k
    IMPLEMENTATION *impl;
383
2.64k
    int ret = 0;
384
2.64k
    int i;
385
386
2.64k
    if (nid <= 0 || method == NULL || store == NULL)
387
0
        return 0;
388
389
2.64k
    if (properties == NULL)
390
0
        properties = "";
391
392
2.64k
    if (!ossl_assert(prov != NULL))
393
0
        return 0;
394
395
    /* Create new entry */
396
2.64k
    impl = OPENSSL_malloc(sizeof(*impl));
397
2.64k
    if (impl == NULL)
398
0
        return 0;
399
2.64k
    impl->method.method = method;
400
2.64k
    impl->method.up_ref = method_up_ref;
401
2.64k
    impl->method.free = method_destruct;
402
2.64k
    if (!ossl_method_up_ref(&impl->method)) {
403
0
        OPENSSL_free(impl);
404
0
        return 0;
405
0
    }
406
2.64k
    impl->provider = prov;
407
408
2.64k
    sa = stored_algs_shard(store, nid);
409
410
    /* Insert into the hash table if required */
411
2.64k
    if (!ossl_property_write_lock(sa)) {
412
0
        impl_free(impl);
413
0
        return 0;
414
0
    }
415
416
    /*
417
     * Flush the alg cache of any implementation that already exists
418
     * for this id.
419
     * This is done to ensure that on the next lookup we go through the
420
     * provider comparison in ossl_method_store_fetch.  If we don't do this
421
     * then this new method won't be given a chance to get selected.
422
     * NOTE: This doesn't actually remove the method from the backing store
423
     * It just ensures that we query the backing store when (re)-adding a
424
     * method to the algorithm cache, in case the one selected by the next
425
     * query selects a different implementation
426
     */
427
2.64k
    ossl_method_cache_flush(sa, nid);
428
429
    /*
430
     * Parse the properties associated with this method, and convert it to a
431
     * property list stored against the implementation for later comparison
432
     * during fetch operations
433
     */
434
2.64k
    if ((impl->properties = ossl_prop_defn_get(store->ctx, properties)) == NULL) {
435
16
        impl->properties = ossl_parse_property(store->ctx, properties);
436
16
        if (impl->properties == NULL)
437
0
            goto err;
438
16
        if (!ossl_prop_defn_set(store->ctx, properties, &impl->properties)) {
439
0
            ossl_property_free(impl->properties);
440
0
            impl->properties = NULL;
441
0
            goto err;
442
0
        }
443
16
    }
444
445
    /*
446
     * Check if we have an algorithm cache already for this nid.  If so use
447
     * it, otherwise, create it, and insert it into the store
448
     */
449
2.64k
    alg = ossl_method_store_retrieve(sa, nid);
450
2.64k
    if (alg == NULL) {
451
2.64k
        if ((alg = OPENSSL_zalloc(sizeof(*alg))) == NULL
452
2.64k
            || (alg->impls = sk_IMPLEMENTATION_new_null()) == NULL)
453
0
            goto err;
454
2.64k
        alg->nid = nid;
455
2.64k
        if (!ossl_method_store_insert(sa, alg))
456
0
            goto err;
457
2.64k
        OSSL_TRACE2(QUERY, "Inserted an alg with nid %d into the stored algorithms %p\n",
458
2.64k
            nid, (void *)sa);
459
2.64k
    }
460
461
    /* Push onto stack if there isn't one there already */
462
2.64k
    for (i = 0; i < sk_IMPLEMENTATION_num(alg->impls); i++) {
463
0
        const IMPLEMENTATION *tmpimpl = sk_IMPLEMENTATION_value(alg->impls, i);
464
465
0
        if (tmpimpl->provider == impl->provider
466
0
            && tmpimpl->properties == impl->properties)
467
0
            break;
468
0
    }
469
470
2.64k
    if (i == sk_IMPLEMENTATION_num(alg->impls)
471
2.64k
        && sk_IMPLEMENTATION_push(alg->impls, impl)) {
472
2.64k
        ret = 1;
473
2.64k
#ifndef FIPS_MODULE
474
2.64k
        OSSL_TRACE_BEGIN(QUERY)
475
0
        {
476
0
            BIO_printf(trc_out, "Adding to method store "
477
0
                                "nid: %d\nproperties: %s\nprovider: %s\n",
478
0
                nid, properties,
479
0
                ossl_provider_name(prov) == NULL ? "none" : ossl_provider_name(prov));
480
0
        }
481
2.64k
        OSSL_TRACE_END(QUERY);
482
2.64k
#endif
483
2.64k
    }
484
2.64k
    ossl_property_unlock(sa);
485
2.64k
    if (ret == 0)
486
0
        impl_free(impl);
487
2.64k
    return ret;
488
489
0
err:
490
0
    ossl_property_unlock(sa);
491
0
    alg_cleanup(0, alg, NULL);
492
0
    impl_free(impl);
493
0
    return 0;
494
2.64k
}
495
496
int ossl_method_store_remove(OSSL_METHOD_STORE *store, int nid,
497
    const void *method)
498
0
{
499
0
    ALGORITHM *alg = NULL;
500
0
    STORED_ALGORITHMS *sa;
501
0
    int i;
502
503
0
    if (nid <= 0 || method == NULL || store == NULL)
504
0
        return 0;
505
506
0
    sa = stored_algs_shard(store, nid);
507
0
    if (!ossl_property_write_lock(sa))
508
0
        return 0;
509
0
    ossl_method_cache_flush(sa, nid);
510
0
    ossl_method_store_atomic_clean_archive(sa);
511
0
    alg = ossl_method_store_retrieve(sa, nid);
512
0
    if (alg == NULL) {
513
0
        ossl_property_unlock(sa);
514
0
        return 0;
515
0
    }
516
517
    /*
518
     * A sorting find then a delete could be faster but these stacks should be
519
     * relatively small, so we avoid the overhead.  Sorting could also surprise
520
     * users when result orderings change (even though they are not guaranteed).
521
     */
522
0
    for (i = 0; i < sk_IMPLEMENTATION_num(alg->impls); i++) {
523
0
        IMPLEMENTATION *impl = sk_IMPLEMENTATION_value(alg->impls, i);
524
525
0
        if (impl->method.method == method) {
526
0
            impl_free(impl);
527
0
            (void)sk_IMPLEMENTATION_delete(alg->impls, i);
528
0
            ossl_property_unlock(sa);
529
0
            return 1;
530
0
        }
531
0
    }
532
0
    ossl_property_unlock(sa);
533
0
    return 0;
534
0
}
535
536
struct alg_cleanup_by_provider_data_st {
537
    STORED_ALGORITHMS *sa;
538
    const OSSL_PROVIDER *prov;
539
};
540
541
/**
542
 * @brief Cleans up implementations of an algorithm associated with a provider.
543
 *
544
 * This function removes all implementations of a specified algorithm that are
545
 * associated with a given provider. The function walks through the stack of
546
 * implementations backwards to handle deletions without affecting indexing.
547
 *
548
 * @param idx Index of the algorithm (unused in this function).
549
 * @param alg Pointer to the ALGORITHM structure containing the implementations.
550
 * @param arg Pointer to the data containing the provider information.
551
 *
552
 * If tracing is enabled, messages are printed indicating the removal of each
553
 * implementation and its properties. If any implementation is removed, the
554
 * associated cache is flushed.
555
 */
556
static void
557
alg_cleanup_by_provider(ossl_uintmax_t idx, ALGORITHM *alg, void *arg)
558
0
{
559
0
    struct alg_cleanup_by_provider_data_st *data = arg;
560
0
    int i, count;
561
562
    /*
563
     * We walk the stack backwards, to avoid having to deal with stack shifts
564
     * caused by deletion
565
     */
566
0
    for (count = 0, i = sk_IMPLEMENTATION_num(alg->impls); i-- > 0;) {
567
0
        IMPLEMENTATION *impl = sk_IMPLEMENTATION_value(alg->impls, i);
568
569
0
        if (impl->provider == data->prov) {
570
0
#ifndef FIPS_MODULE
571
0
            OSSL_TRACE_BEGIN(QUERY)
572
0
            {
573
0
                char buf[512];
574
0
                size_t size;
575
576
0
                size = ossl_property_list_to_string(NULL, impl->properties, buf,
577
0
                    sizeof(buf));
578
0
                BIO_printf(trc_out, "Removing implementation from "
579
0
                                    "query cache\nproperties %s\nprovider %s\n",
580
0
                    size == 0 ? "none" : buf,
581
0
                    ossl_provider_name(impl->provider) == NULL ? "none" : ossl_provider_name(impl->provider));
582
0
            }
583
0
            OSSL_TRACE_END(QUERY);
584
0
#endif
585
586
0
            (void)sk_IMPLEMENTATION_delete(alg->impls, i);
587
0
            count++;
588
0
            impl_free(impl);
589
0
        }
590
0
    }
591
592
    /*
593
     * If we removed any implementation, we also clear the whole associated
594
     * cache, 'cause that's the sensible thing to do.
595
     * There's no point flushing the cache entries where we didn't remove
596
     * any implementation, though.
597
     */
598
0
    if (count > 0)
599
0
        ossl_method_cache_flush_alg(data->sa, alg);
600
0
}
601
602
int ossl_method_store_remove_all_provided(OSSL_METHOD_STORE *store,
603
    const OSSL_PROVIDER *prov)
604
0
{
605
0
    struct alg_cleanup_by_provider_data_st data;
606
607
0
    for (int k = 0; k < NUM_SHARDS; ++k) {
608
0
        STORED_ALGORITHMS *sa = &store->algs[k];
609
610
0
        if (!ossl_property_write_lock(sa))
611
0
            return 0;
612
0
        data.prov = prov;
613
0
        data.sa = sa;
614
0
        ossl_sa_ALGORITHM_doall_arg(sa->algs, &alg_cleanup_by_provider, &data);
615
0
        ossl_method_store_atomic_clean_archive(sa);
616
0
        ossl_property_unlock(sa);
617
0
    }
618
0
    return 1;
619
0
}
620
621
static void alg_do_one(ALGORITHM *alg, IMPLEMENTATION *impl,
622
    void (*fn)(int id, void *method, void *fnarg),
623
    void *fnarg)
624
0
{
625
0
    fn(alg->nid, impl->method.method, fnarg);
626
0
}
627
628
static void alg_copy(ossl_uintmax_t idx, ALGORITHM *alg, void *arg)
629
0
{
630
0
    STACK_OF(ALGORITHM) *newalg = arg;
631
632
0
    alg = OPENSSL_memdup(alg, sizeof(ALGORITHM));
633
0
    if (alg == NULL)
634
0
        return;
635
636
0
    alg->impls = sk_IMPLEMENTATION_dup(alg->impls);
637
638
0
    (void)sk_ALGORITHM_push(newalg, alg);
639
0
}
640
641
static void del_tmpalg(ALGORITHM *alg)
642
0
{
643
0
    sk_IMPLEMENTATION_free(alg->impls);
644
0
    OPENSSL_free(alg);
645
0
}
646
647
void ossl_method_store_do_all(OSSL_METHOD_STORE *store,
648
    void (*fn)(int id, void *method, void *fnarg),
649
    void *fnarg)
650
0
{
651
0
    int i, j;
652
0
    int numalgs, numimps;
653
0
    STACK_OF(ALGORITHM) *tmpalgs;
654
0
    ALGORITHM *alg;
655
656
0
    if (store == NULL)
657
0
        return;
658
659
0
    for (int k = 0; k < NUM_SHARDS; ++k) {
660
0
        STORED_ALGORITHMS *sa = &store->algs[k];
661
662
0
        if (!ossl_property_read_lock(sa))
663
0
            return;
664
665
0
        tmpalgs = sk_ALGORITHM_new_reserve(NULL,
666
0
            (int)ossl_sa_ALGORITHM_num(sa->algs));
667
0
        if (tmpalgs == NULL) {
668
0
            ossl_property_unlock(sa);
669
0
            return;
670
0
        }
671
672
0
        ossl_sa_ALGORITHM_doall_arg(sa->algs, alg_copy, tmpalgs);
673
0
        ossl_property_unlock(sa);
674
0
        numalgs = sk_ALGORITHM_num(tmpalgs);
675
0
        for (i = 0; i < numalgs; i++) {
676
0
            alg = sk_ALGORITHM_value(tmpalgs, i);
677
0
            numimps = sk_IMPLEMENTATION_num(alg->impls);
678
0
            for (j = 0; j < numimps; j++)
679
0
                alg_do_one(alg, sk_IMPLEMENTATION_value(alg->impls, j), fn, fnarg);
680
0
        }
681
0
        sk_ALGORITHM_pop_free(tmpalgs, del_tmpalg);
682
0
    }
683
0
}
684
685
/**
686
 * @brief Fetches a method from the method store matching the given properties.
687
 *
688
 * This function searches the method store for an implementation of a specified
689
 * method, identified by its id (nid), and matching the given property query. If
690
 * successful, it returns the method and its associated provider.
691
 *
692
 * @param store Pointer to the OSSL_METHOD_STORE from which to fetch the method.
693
 *              Must be non-null.
694
 * @param nid (identifier) of the method to be fetched. Must be > 0
695
 * @param prop_query String containing the property query to match against.
696
 * @param prov_rw Pointer to the OSSL_PROVIDER to restrict the search to, or
697
 *                to receive the matched provider.
698
 * @param method Pointer to receive the fetched method. Must be non-null.
699
 *
700
 * @return 1 if the method is successfully fetched, 0 on failure.
701
 *
702
 * If tracing is enabled, a message is printed indicating the property query and
703
 * the resolved provider.
704
 *
705
 * NOTE: The nid parameter here is _not_ a NID in the sense of the NID_* macros.
706
 * It is a unique internal identifier value.
707
 */
708
int ossl_method_store_fetch(OSSL_METHOD_STORE *store,
709
    int nid, const char *prop_query,
710
    const OSSL_PROVIDER **prov_rw, void **method)
711
85
{
712
85
    OSSL_PROPERTY_LIST **plp;
713
85
    ALGORITHM *alg;
714
85
    IMPLEMENTATION *impl, *best_impl = NULL;
715
85
    OSSL_PROPERTY_LIST *pq = NULL, *p2 = NULL;
716
85
    const OSSL_PROVIDER *prov = prov_rw != NULL ? *prov_rw : NULL;
717
85
    int ret = 0;
718
85
    int j, best = -1, score, optional;
719
85
    STORED_ALGORITHMS *sa;
720
721
85
    if (nid <= 0 || method == NULL || store == NULL)
722
0
        return 0;
723
724
85
#if !defined(FIPS_MODULE) && !defined(OPENSSL_NO_AUTOLOAD_CONFIG)
725
85
    if (ossl_lib_ctx_is_default(store->ctx)
726
85
        && !OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL))
727
0
        return 0;
728
85
#endif
729
730
85
    sa = stored_algs_shard(store, nid);
731
732
    /* This only needs to be a read lock, because the query won't create anything */
733
85
    if (!ossl_property_read_lock(sa))
734
0
        return 0;
735
736
85
    OSSL_TRACE2(QUERY, "Retrieving by nid %d from stored algorithms %p\n",
737
85
        nid, (void *)sa);
738
85
    alg = ossl_method_store_retrieve(sa, nid);
739
85
    if (alg == NULL) {
740
0
        ossl_property_unlock(sa);
741
0
        OSSL_TRACE2(QUERY, "Failed to retrieve by nid %d from stored algorithms %p\n",
742
0
            nid, (void *)sa);
743
0
        return 0;
744
0
    }
745
85
    OSSL_TRACE2(QUERY, "Retrieved by nid %d from stored algorithms %p\n",
746
85
        nid, (void *)sa);
747
748
    /*
749
     * If a property query string is provided, convert it to an
750
     * OSSL_PROPERTY_LIST structure
751
     */
752
85
    if (prop_query != NULL)
753
85
        p2 = pq = ossl_parse_query(store->ctx, prop_query, 0);
754
755
    /*
756
     * If the library context has default properties specified
757
     * then merge those with the properties passed to this function
758
     */
759
85
    plp = ossl_ctx_global_properties(store->ctx, 0);
760
85
    if (plp != NULL && *plp != NULL) {
761
0
        if (pq == NULL) {
762
0
            pq = *plp;
763
0
        } else {
764
0
            p2 = ossl_property_merge(pq, *plp);
765
0
            ossl_property_free(pq);
766
0
            if (p2 == NULL)
767
0
                goto fin;
768
0
            pq = p2;
769
0
        }
770
0
    }
771
772
    /*
773
     * Search for a provider that provides this implementation.
774
     * If the requested provider is NULL, then any provider will do,
775
     * otherwise we should try to find the one that matches the requested
776
     * provider.  Note that providers are given implicit preference via the
777
     * ordering of the implementation stack
778
     */
779
85
    if (pq == NULL) {
780
0
        for (j = 0; j < sk_IMPLEMENTATION_num(alg->impls); j++) {
781
0
            impl = sk_IMPLEMENTATION_value(alg->impls, j);
782
0
            if (impl != NULL
783
0
                && (prov == NULL || impl->provider == prov)) {
784
0
                best_impl = impl;
785
0
                ret = 1;
786
0
                break;
787
0
            }
788
0
        }
789
0
        goto fin;
790
0
    }
791
792
    /*
793
     * If there are optional properties specified
794
     * then run the search again, and select the provider that matches the
795
     * most options
796
     */
797
85
    optional = ossl_property_has_optional(pq);
798
85
    for (j = 0; j < sk_IMPLEMENTATION_num(alg->impls); j++) {
799
85
        impl = sk_IMPLEMENTATION_value(alg->impls, j);
800
85
        if (impl != NULL
801
85
            && (prov == NULL || impl->provider == prov)) {
802
85
            score = ossl_property_match_count(pq, impl->properties);
803
85
            if (score > best) {
804
85
                best_impl = impl;
805
85
                best = score;
806
85
                ret = 1;
807
85
                if (!optional)
808
85
                    goto fin;
809
85
            }
810
85
        }
811
85
    }
812
85
fin:
813
85
    if (ret && ossl_method_up_ref(&best_impl->method)) {
814
85
        *method = best_impl->method.method;
815
85
        if (prov_rw != NULL)
816
85
            *prov_rw = best_impl->provider;
817
85
    } else {
818
0
        ret = 0;
819
0
    }
820
821
85
#ifndef FIPS_MODULE
822
85
    OSSL_TRACE_BEGIN(QUERY)
823
0
    {
824
0
        char buf[512];
825
0
        size_t size;
826
827
0
        size = ossl_property_list_to_string(NULL, pq, buf, 512);
828
0
        BIO_printf(trc_out, "method store query with properties %s "
829
0
                            "resolves to provider %s\n",
830
0
            size == 0 ? "none" : buf,
831
0
            best_impl == NULL ? "none" : ossl_provider_name(best_impl->provider));
832
0
    }
833
85
    OSSL_TRACE_END(QUERY);
834
85
#endif
835
836
85
    ossl_property_unlock(sa);
837
85
    ossl_property_free(p2);
838
85
    return ret;
839
85
}
840
841
static void ossl_method_cache_flush_alg(STORED_ALGORITHMS *sa,
842
    ALGORITHM *alg)
843
0
{
844
0
    impl_cache_flush_alg(alg, sa);
845
0
}
846
847
static void ossl_method_cache_flush(STORED_ALGORITHMS *sa, int nid)
848
2.64k
{
849
2.64k
    ALGORITHM *alg = ossl_method_store_retrieve(sa, nid);
850
851
2.64k
    if (alg != NULL)
852
0
        ossl_method_cache_flush_alg(sa, alg);
853
2.64k
}
854
855
static void ossl_cache_lists_flush(STORED_ALGORITHMS *sa)
856
0
{
857
0
    int i;
858
0
    QUERY *idx, *idxn;
859
860
0
    for (i = 0; i < MAX_CACHE_LINES; i++) {
861
0
        if (!CRYPTO_atomic_load_ptr((void **)&sa->cache_lists[i], (void **)&idx, sa->alock))
862
0
            break;
863
0
        while (idx != NULL) {
864
0
            if (!CRYPTO_atomic_load_ptr((void **)&idx->next, (void **)&idxn, sa->alock))
865
0
                break;
866
0
            ossl_method_store_atomic_archive(sa, idx);
867
0
            idx = idxn;
868
0
        }
869
0
    }
870
0
}
871
872
static void ossl_cache_lists_free(STORED_ALGORITHMS *sa)
873
0
{
874
0
    int i;
875
0
    QUERY *idx, *idxn;
876
877
0
    for (i = 0; i < MAX_CACHE_LINES; i++) {
878
0
        if (!CRYPTO_atomic_load_ptr((void **)&sa->cache_lists[i], (void **)&idx, sa->alock))
879
0
            return;
880
0
        while (idx != NULL) {
881
0
            if (!CRYPTO_atomic_load_ptr((void **)&idx->next, (void **)&idxn, sa->alock))
882
0
                return;
883
0
            impl_cache_free_unlinked(idx);
884
0
            idx = idxn;
885
0
        }
886
0
    }
887
888
0
    if (!CRYPTO_atomic_load_ptr((void **)&sa->archive, (void **)&idx, sa->alock))
889
0
        return;
890
0
    while (idx != NULL) {
891
0
        if (!CRYPTO_atomic_load_ptr((void **)&idx->next, (void **)&idxn, sa->alock))
892
0
            return;
893
0
        impl_cache_free_unlinked(idx);
894
0
        idx = idxn;
895
0
    }
896
0
}
897
898
int ossl_method_store_cache_flush_all(OSSL_METHOD_STORE *store)
899
0
{
900
0
    for (int i = 0; i < NUM_SHARDS; ++i) {
901
0
        STORED_ALGORITHMS *sa = &store->algs[i];
902
903
0
        if (!ossl_property_write_lock(sa))
904
0
            return 0;
905
0
        ossl_cache_lists_flush(sa);
906
0
        ossl_method_store_atomic_clean_archive(sa);
907
0
        ossl_property_unlock(sa);
908
0
    }
909
910
0
    return 1;
911
0
}
912
913
static ossl_inline int ossl_method_store_cache_get_atomic(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov,
914
    int nid, const char *prop_query, STORED_ALGORITHMS *sa, void **method)
915
85.3k
{
916
85.3k
    uint64_t prop_hash;
917
85.3k
    QUERY *r = NULL;
918
85.3k
    int res = 0;
919
920
85.3k
    prop_hash = ossl_fnv1a_hash((uint8_t *)prop_query, strlen(prop_query));
921
922
85.3k
    r = ossl_method_store_atomic_find_in_list(sa, nid, prov, prop_hash);
923
924
85.3k
    if (r != NULL && ossl_method_up_ref(&r->method)) {
925
85.2k
        *method = r->method.method;
926
85.2k
        res = 1;
927
85.2k
    }
928
929
85.3k
    return res;
930
85.3k
}
931
932
int ossl_method_store_cache_get(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov,
933
    int nid, const char *prop_query, void **method)
934
85.3k
{
935
85.3k
    int ret;
936
85.3k
    STORED_ALGORITHMS *sa;
937
938
85.3k
    if (nid <= 0 || store == NULL || prop_query == NULL)
939
0
        return 0;
940
941
85.3k
    sa = stored_algs_shard(store, nid);
942
943
    /*
944
     * Do an atomic linked list walk to search for our entry
945
     */
946
85.3k
    ret = ossl_method_store_cache_get_atomic(store, prov, nid, prop_query, sa,
947
85.3k
        method);
948
949
85.3k
    return ret;
950
85.3k
}
951
952
static int ossl_method_store_atomic_archive(STORED_ALGORITHMS *sa, QUERY *old)
953
0
{
954
0
    if (!CRYPTO_atomic_store_int(&old->archived, 1, sa->alock))
955
0
        return 0;
956
0
    return 1;
957
0
}
958
959
static ossl_inline int ossl_method_store_put_in_archive(STORED_ALGORITHMS *sa, QUERY *old)
960
0
{
961
    /*
962
     * point the item we're remoing's next pointer to the top of the archive list
963
     */
964
0
    if (!CRYPTO_atomic_load_ptr((void **)&sa->archive, (void **)&old->next, sa->alock))
965
0
        return 0;
966
    /*
967
     * And update the head of the archive list to be our new entry
968
     */
969
0
    if (!CRYPTO_atomic_store_ptr((void **)&sa->archive, (void **)&old, sa->alock))
970
0
        return 0;
971
0
    return 1;
972
0
}
973
974
/*
975
 * Migrate archived items to the archive list.  Must be done with the property write
976
 * lock held
977
 */
978
static void ossl_method_store_atomic_clean_archive(STORED_ALGORITHMS *sa)
979
0
{
980
0
    QUERY *idx, *idxn;
981
0
    int archived;
982
0
    int i;
983
0
    int lock_failed;
984
985
    /*
986
     * For each of our linked lists
987
     */
988
0
    for (i = 0; i < MAX_CACHE_LINES; i++) {
989
0
    restart_list:
990
        /*
991
         * Get the head of the list
992
         */
993
0
        if (!CRYPTO_atomic_load_ptr((void **)&sa->cache_lists[i], (void **)&idx, sa->alock))
994
0
            continue;
995
        /*
996
         * If its NULL, the list is currently empty, move on to the next one
997
         */
998
0
        if (idx == NULL)
999
0
            continue;
1000
        /*
1001
         * Get its archived value
1002
         */
1003
0
        if (!CRYPTO_atomic_load_int(&idx->archived, &archived, sa->alock))
1004
0
            continue;
1005
        /*
1006
         * Also fetch its next pointer to idxn
1007
         */
1008
0
        if (!CRYPTO_atomic_load_ptr((void **)&idx->next, (void **)&idxn, sa->alock))
1009
0
            continue;
1010
        /*
1011
         * If its been archived, we want to move it to the archive list
1012
         */
1013
0
        if (archived == 1) {
1014
            /*
1015
             * We know this is the current list head we're working with
1016
             * so store the next pointer to be the new list head
1017
             */
1018
0
            if (!CRYPTO_atomic_cmp_exch_ptr((void **)&sa->cache_lists[i], (void **)&idx, idxn, sa->alock,
1019
0
                    &lock_failed)) {
1020
0
                if (lock_failed)
1021
0
                    continue;
1022
0
                else
1023
0
                    goto restart_list;
1024
0
            }
1025
1026
0
            if (!ossl_method_store_put_in_archive(sa, idx))
1027
0
                continue;
1028
0
            goto restart_list;
1029
0
        }
1030
1031
        /*
1032
         * At this point our state is:
1033
         * idx - points to an element in cache_lists[i]
1034
         * idxn points to the next entry (i.e. idx->next)
1035
         */
1036
0
        while (idx != NULL) {
1037
            /*
1038
             * We know idx isn't archived, so we start looking at idxn
1039
             */
1040
0
            if (idxn != NULL) {
1041
                /*
1042
                 * if its not NULL, see if its archived
1043
                 */
1044
0
                if (!CRYPTO_atomic_load_int(&idxn->archived, &archived, sa->alock))
1045
0
                    break;
1046
                /*
1047
                 * If it is, remove it
1048
                 */
1049
0
                if (archived == 1) {
1050
                    /*
1051
                     * Start by making idx skip idxn in the list
1052
                     */
1053
0
                    if (!CRYPTO_atomic_load_ptr((void **)&idxn->next, (void **)&idx->next, sa->alock))
1054
0
                        break;
1055
1056
0
                    if (!ossl_method_store_put_in_archive(sa, idxn))
1057
0
                        break;
1058
1059
                    /*
1060
                     * Idx just got a new next pointer above, so just update idxn, so we are sure that idx
1061
                     * still isn't archived
1062
                     */
1063
0
                    if (!CRYPTO_atomic_load_ptr((void **)&idx->next, (void **)&idxn, sa->alock))
1064
0
                        break;
1065
0
                } else {
1066
                    /*
1067
                     * idxn wasn't archived, so we need to advance both pointers here
1068
                     */
1069
0
                    idx = idxn;
1070
0
                    if (!CRYPTO_atomic_load_ptr((void **)&idx->next, (void **)&idxn, sa->alock))
1071
0
                        break;
1072
0
                }
1073
0
            } else {
1074
                /*
1075
                 * idxn is NULL, that means we're at the end of the list.
1076
                 * Just advance idx to idxn and the loop will break on the next iteration
1077
                 */
1078
0
                idx = idxn;
1079
0
            }
1080
0
        }
1081
0
    }
1082
0
}
1083
1084
static QUERY *ossl_method_store_atomic_find_in_list(STORED_ALGORITHMS *sa, int nid,
1085
    OSSL_PROVIDER *prov, uint64_t prop_hash)
1086
85.4k
{
1087
85.4k
    int nididx = (nid >> NUM_SHARDS_BITS) & (MAX_CACHE_LINES - 1);
1088
85.4k
    int archived;
1089
85.4k
    QUERY *idx;
1090
85.4k
    QUERY *ret = NULL;
1091
1092
85.4k
    if (!CRYPTO_atomic_load_ptr((void **)&sa->cache_lists[nididx], (void **)&idx, sa->alock))
1093
0
        goto out;
1094
1095
109k
    while (idx != NULL) {
1096
108k
        if (!CRYPTO_atomic_load_int(&idx->archived, &archived, sa->alock))
1097
0
            goto out;
1098
108k
        if (archived == 0 && idx->nid == nid && idx->prop_hash == prop_hash && idx->prov == prov) {
1099
85.2k
            ret = idx;
1100
85.2k
            break;
1101
85.2k
        }
1102
23.5k
        if (!CRYPTO_atomic_load_ptr((void **)&idx->next, (void **)&idx, sa->alock))
1103
0
            goto out;
1104
23.5k
    }
1105
85.4k
out:
1106
85.4k
    return ret;
1107
85.4k
}
1108
1109
static int ossl_method_store_atomic_insert_to_list(STORED_ALGORITHMS *sa, QUERY *new)
1110
170
{
1111
170
    int nid = (new->nid >> NUM_SHARDS_BITS) & (MAX_CACHE_LINES - 1);
1112
170
    QUERY *headptr;
1113
170
    int ret = 0;
1114
170
    int lock_failed;
1115
1116
170
    if (!CRYPTO_atomic_load_ptr((void **)&sa->cache_lists[nid], (void **)&headptr, sa->alock))
1117
0
        goto out;
1118
170
try_again:
1119
170
    if (!CRYPTO_atomic_store_ptr((void **)&new->next, (void **)&headptr, sa->alock))
1120
0
        goto out;
1121
170
    if (!CRYPTO_atomic_cmp_exch_ptr((void **)&sa->cache_lists[nid], (void **)&headptr, new, sa->alock,
1122
170
            &lock_failed)) {
1123
0
        if (lock_failed == 1)
1124
0
            goto out;
1125
0
        goto try_again;
1126
0
    }
1127
170
    ret = 1;
1128
170
out:
1129
170
    return ret;
1130
170
}
1131
1132
static ossl_inline int ossl_method_store_cache_set_atomic(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov,
1133
    int nid, const char *prop_query, STORED_ALGORITHMS *sa, void *method,
1134
    int (*method_up_ref)(void *),
1135
    void (*method_destruct)(void *))
1136
85
{
1137
85
    QUERY *p = NULL;
1138
85
    uint64_t prop_hash = ossl_fnv1a_hash((uint8_t *)prop_query, strlen(prop_query));
1139
85
    int res = 1;
1140
1141
85
    if (method == NULL) {
1142
0
        p = ossl_method_store_atomic_find_in_list(sa, nid, prov, prop_hash);
1143
0
        if (p != NULL)
1144
0
            ossl_method_store_atomic_archive(sa, p);
1145
0
        goto end;
1146
0
    }
1147
1148
85
    p = ossl_method_store_atomic_find_in_list(sa, nid, prov, prop_hash);
1149
85
    if (p != NULL) {
1150
0
        ossl_method_store_atomic_archive(sa, p);
1151
0
        p = ossl_method_store_atomic_find_in_list(sa, nid, NULL, prop_hash);
1152
0
        if (p != NULL)
1153
0
            ossl_method_store_atomic_archive(sa, p);
1154
0
    }
1155
85
    p = OPENSSL_malloc(sizeof(*p));
1156
85
    if (p != NULL) {
1157
85
        TSAN_BENIGN(p, "Unpublished value is safe on subsequent read");
1158
85
        p->saptr = sa;
1159
85
        p->nid = nid;
1160
85
        p->prov = prov;
1161
85
        p->archived = 0;
1162
85
        p->prop_hash = prop_hash;
1163
85
        p->method.method = method;
1164
85
        p->method.up_ref = method_up_ref;
1165
85
        p->method.free = method_destruct;
1166
85
        if (!ossl_method_up_ref(&p->method))
1167
0
            goto err;
1168
1169
85
        if (!ossl_method_store_atomic_insert_to_list(sa, p)) {
1170
0
            ossl_method_free(&p->method);
1171
0
            goto err;
1172
0
        }
1173
1174
        /*
1175
         * We also want to add this method into the cache against a key computed _only_
1176
         * from nid and property query.  This lets us match in the event someone does a lookup
1177
         * against a NULL provider (i.e. the "any provided alg will do" match
1178
         */
1179
85
        p = OPENSSL_memdup(p, sizeof(*p));
1180
85
        if (p == NULL)
1181
0
            goto err;
1182
85
        TSAN_BENIGN(p, "Unpublished value is safe on subsequent read");
1183
85
        p->prov = NULL;
1184
85
        if (!ossl_method_up_ref(&p->method))
1185
0
            goto err;
1186
85
        if (!ossl_method_store_atomic_insert_to_list(sa, p)) {
1187
0
            ossl_method_free(&p->method);
1188
0
            goto err;
1189
0
        }
1190
1191
85
        goto end;
1192
85
    }
1193
0
err:
1194
0
    res = 0;
1195
0
    OPENSSL_free(p);
1196
85
end:
1197
85
    return res;
1198
0
}
1199
1200
int ossl_method_store_cache_set(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov,
1201
    int nid, const char *prop_query, void *method,
1202
    int (*method_up_ref)(void *),
1203
    void (*method_destruct)(void *))
1204
85
{
1205
85
    STORED_ALGORITHMS *sa;
1206
85
    int res = 1;
1207
1208
85
    if (nid <= 0 || store == NULL || prop_query == NULL)
1209
0
        return 0;
1210
1211
85
    if (!ossl_assert(prov != NULL))
1212
0
        return 0;
1213
1214
85
    sa = stored_algs_shard(store, nid);
1215
1216
    /*
1217
     * Do an atomic insert into the appropriate cache linked list
1218
     */
1219
85
    res = ossl_method_store_cache_set_atomic(store, prov, nid, prop_query, sa, method,
1220
85
        method_up_ref, method_destruct);
1221
1222
85
    return res;
1223
85
}