11cb0ef41Sopenharmony_ci/*
21cb0ef41Sopenharmony_ci * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
31cb0ef41Sopenharmony_ci *
41cb0ef41Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
51cb0ef41Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
61cb0ef41Sopenharmony_ci * in the file LICENSE in the source distribution or at
71cb0ef41Sopenharmony_ci * https://www.openssl.org/source/license.html
81cb0ef41Sopenharmony_ci */
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci#include <stdlib.h>
111cb0ef41Sopenharmony_ci#include "crypto/cryptlib.h"
121cb0ef41Sopenharmony_ci#include "internal/thread_once.h"
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ciint ossl_do_ex_data_init(OSSL_LIB_CTX *ctx)
151cb0ef41Sopenharmony_ci{
161cb0ef41Sopenharmony_ci    OSSL_EX_DATA_GLOBAL *global = ossl_lib_ctx_get_ex_data_global(ctx);
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ci    if (global == NULL)
191cb0ef41Sopenharmony_ci        return 0;
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci    global->ex_data_lock = CRYPTO_THREAD_lock_new();
221cb0ef41Sopenharmony_ci    return global->ex_data_lock != NULL;
231cb0ef41Sopenharmony_ci}
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci/*
261cb0ef41Sopenharmony_ci * Return the EX_CALLBACKS from the |ex_data| array that corresponds to
271cb0ef41Sopenharmony_ci * a given class.  On success, *holds the lock.*
281cb0ef41Sopenharmony_ci * The |global| parameter is assumed to be non null (checked by the caller).
291cb0ef41Sopenharmony_ci */
301cb0ef41Sopenharmony_cistatic EX_CALLBACKS *get_and_lock(OSSL_EX_DATA_GLOBAL *global, int class_index)
311cb0ef41Sopenharmony_ci{
321cb0ef41Sopenharmony_ci    EX_CALLBACKS *ip;
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci    if (class_index < 0 || class_index >= CRYPTO_EX_INDEX__COUNT) {
351cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
361cb0ef41Sopenharmony_ci        return NULL;
371cb0ef41Sopenharmony_ci    }
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci    if (global->ex_data_lock == NULL) {
401cb0ef41Sopenharmony_ci        /*
411cb0ef41Sopenharmony_ci         * If we get here, someone (who?) cleaned up the lock, so just
421cb0ef41Sopenharmony_ci         * treat it as an error.
431cb0ef41Sopenharmony_ci         */
441cb0ef41Sopenharmony_ci         return NULL;
451cb0ef41Sopenharmony_ci    }
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci    if (!CRYPTO_THREAD_write_lock(global->ex_data_lock))
481cb0ef41Sopenharmony_ci        return NULL;
491cb0ef41Sopenharmony_ci    ip = &global->ex_data[class_index];
501cb0ef41Sopenharmony_ci    return ip;
511cb0ef41Sopenharmony_ci}
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_cistatic void cleanup_cb(EX_CALLBACK *funcs)
541cb0ef41Sopenharmony_ci{
551cb0ef41Sopenharmony_ci    OPENSSL_free(funcs);
561cb0ef41Sopenharmony_ci}
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci/*
591cb0ef41Sopenharmony_ci * Release all "ex_data" state to prevent memory leaks. This can't be made
601cb0ef41Sopenharmony_ci * thread-safe without overhauling a lot of stuff, and shouldn't really be
611cb0ef41Sopenharmony_ci * called under potential race-conditions anyway (it's for program shutdown
621cb0ef41Sopenharmony_ci * after all).
631cb0ef41Sopenharmony_ci */
641cb0ef41Sopenharmony_civoid ossl_crypto_cleanup_all_ex_data_int(OSSL_LIB_CTX *ctx)
651cb0ef41Sopenharmony_ci{
661cb0ef41Sopenharmony_ci    int i;
671cb0ef41Sopenharmony_ci    OSSL_EX_DATA_GLOBAL *global = ossl_lib_ctx_get_ex_data_global(ctx);
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci    if (global == NULL)
701cb0ef41Sopenharmony_ci        return;
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci    for (i = 0; i < CRYPTO_EX_INDEX__COUNT; ++i) {
731cb0ef41Sopenharmony_ci        EX_CALLBACKS *ip = &global->ex_data[i];
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci        sk_EX_CALLBACK_pop_free(ip->meth, cleanup_cb);
761cb0ef41Sopenharmony_ci        ip->meth = NULL;
771cb0ef41Sopenharmony_ci    }
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci    CRYPTO_THREAD_lock_free(global->ex_data_lock);
801cb0ef41Sopenharmony_ci    global->ex_data_lock = NULL;
811cb0ef41Sopenharmony_ci}
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci/*
851cb0ef41Sopenharmony_ci * Unregister a new index by replacing the callbacks with no-ops.
861cb0ef41Sopenharmony_ci * Any in-use instances are leaked.
871cb0ef41Sopenharmony_ci */
881cb0ef41Sopenharmony_cistatic void dummy_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
891cb0ef41Sopenharmony_ci                     long argl, void *argp)
901cb0ef41Sopenharmony_ci{
911cb0ef41Sopenharmony_ci}
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_cistatic void dummy_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
941cb0ef41Sopenharmony_ci                       long argl, void *argp)
951cb0ef41Sopenharmony_ci{
961cb0ef41Sopenharmony_ci}
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_cistatic int dummy_dup(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from,
991cb0ef41Sopenharmony_ci                     void **from_d, int idx,
1001cb0ef41Sopenharmony_ci                     long argl, void *argp)
1011cb0ef41Sopenharmony_ci{
1021cb0ef41Sopenharmony_ci    return 1;
1031cb0ef41Sopenharmony_ci}
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ciint ossl_crypto_free_ex_index_ex(OSSL_LIB_CTX *ctx, int class_index, int idx)
1061cb0ef41Sopenharmony_ci{
1071cb0ef41Sopenharmony_ci    EX_CALLBACKS *ip;
1081cb0ef41Sopenharmony_ci    EX_CALLBACK *a;
1091cb0ef41Sopenharmony_ci    int toret = 0;
1101cb0ef41Sopenharmony_ci    OSSL_EX_DATA_GLOBAL *global = ossl_lib_ctx_get_ex_data_global(ctx);
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci    if (global == NULL)
1131cb0ef41Sopenharmony_ci        return 0;
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci    ip = get_and_lock(global, class_index);
1161cb0ef41Sopenharmony_ci    if (ip == NULL)
1171cb0ef41Sopenharmony_ci        return 0;
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci    if (idx < 0 || idx >= sk_EX_CALLBACK_num(ip->meth))
1201cb0ef41Sopenharmony_ci        goto err;
1211cb0ef41Sopenharmony_ci    a = sk_EX_CALLBACK_value(ip->meth, idx);
1221cb0ef41Sopenharmony_ci    if (a == NULL)
1231cb0ef41Sopenharmony_ci        goto err;
1241cb0ef41Sopenharmony_ci    a->new_func = dummy_new;
1251cb0ef41Sopenharmony_ci    a->dup_func = dummy_dup;
1261cb0ef41Sopenharmony_ci    a->free_func = dummy_free;
1271cb0ef41Sopenharmony_ci    toret = 1;
1281cb0ef41Sopenharmony_cierr:
1291cb0ef41Sopenharmony_ci    CRYPTO_THREAD_unlock(global->ex_data_lock);
1301cb0ef41Sopenharmony_ci    return toret;
1311cb0ef41Sopenharmony_ci}
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ciint CRYPTO_free_ex_index(int class_index, int idx)
1341cb0ef41Sopenharmony_ci{
1351cb0ef41Sopenharmony_ci    return ossl_crypto_free_ex_index_ex(NULL, class_index, idx);
1361cb0ef41Sopenharmony_ci}
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci/*
1391cb0ef41Sopenharmony_ci * Register a new index.
1401cb0ef41Sopenharmony_ci */
1411cb0ef41Sopenharmony_ciint ossl_crypto_get_ex_new_index_ex(OSSL_LIB_CTX *ctx, int class_index,
1421cb0ef41Sopenharmony_ci                                    long argl, void *argp,
1431cb0ef41Sopenharmony_ci                                    CRYPTO_EX_new *new_func,
1441cb0ef41Sopenharmony_ci                                    CRYPTO_EX_dup *dup_func,
1451cb0ef41Sopenharmony_ci                                    CRYPTO_EX_free *free_func,
1461cb0ef41Sopenharmony_ci                                    int priority)
1471cb0ef41Sopenharmony_ci{
1481cb0ef41Sopenharmony_ci    int toret = -1;
1491cb0ef41Sopenharmony_ci    EX_CALLBACK *a;
1501cb0ef41Sopenharmony_ci    EX_CALLBACKS *ip;
1511cb0ef41Sopenharmony_ci    OSSL_EX_DATA_GLOBAL *global = ossl_lib_ctx_get_ex_data_global(ctx);
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci    if (global == NULL)
1541cb0ef41Sopenharmony_ci        return -1;
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci    ip = get_and_lock(global, class_index);
1571cb0ef41Sopenharmony_ci    if (ip == NULL)
1581cb0ef41Sopenharmony_ci        return -1;
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci    if (ip->meth == NULL) {
1611cb0ef41Sopenharmony_ci        ip->meth = sk_EX_CALLBACK_new_null();
1621cb0ef41Sopenharmony_ci        /* We push an initial value on the stack because the SSL
1631cb0ef41Sopenharmony_ci         * "app_data" routines use ex_data index zero.  See RT 3710. */
1641cb0ef41Sopenharmony_ci        if (ip->meth == NULL
1651cb0ef41Sopenharmony_ci            || !sk_EX_CALLBACK_push(ip->meth, NULL)) {
1661cb0ef41Sopenharmony_ci            sk_EX_CALLBACK_free(ip->meth);
1671cb0ef41Sopenharmony_ci            ip->meth = NULL;
1681cb0ef41Sopenharmony_ci            ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
1691cb0ef41Sopenharmony_ci            goto err;
1701cb0ef41Sopenharmony_ci        }
1711cb0ef41Sopenharmony_ci    }
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ci    a = (EX_CALLBACK *)OPENSSL_malloc(sizeof(*a));
1741cb0ef41Sopenharmony_ci    if (a == NULL) {
1751cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
1761cb0ef41Sopenharmony_ci        goto err;
1771cb0ef41Sopenharmony_ci    }
1781cb0ef41Sopenharmony_ci    a->argl = argl;
1791cb0ef41Sopenharmony_ci    a->argp = argp;
1801cb0ef41Sopenharmony_ci    a->new_func = new_func;
1811cb0ef41Sopenharmony_ci    a->dup_func = dup_func;
1821cb0ef41Sopenharmony_ci    a->free_func = free_func;
1831cb0ef41Sopenharmony_ci    a->priority = priority;
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci    if (!sk_EX_CALLBACK_push(ip->meth, NULL)) {
1861cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
1871cb0ef41Sopenharmony_ci        OPENSSL_free(a);
1881cb0ef41Sopenharmony_ci        goto err;
1891cb0ef41Sopenharmony_ci    }
1901cb0ef41Sopenharmony_ci    toret = sk_EX_CALLBACK_num(ip->meth) - 1;
1911cb0ef41Sopenharmony_ci    (void)sk_EX_CALLBACK_set(ip->meth, toret, a);
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci err:
1941cb0ef41Sopenharmony_ci    CRYPTO_THREAD_unlock(global->ex_data_lock);
1951cb0ef41Sopenharmony_ci    return toret;
1961cb0ef41Sopenharmony_ci}
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ciint CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
1991cb0ef41Sopenharmony_ci                            CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
2001cb0ef41Sopenharmony_ci                            CRYPTO_EX_free *free_func)
2011cb0ef41Sopenharmony_ci{
2021cb0ef41Sopenharmony_ci    return ossl_crypto_get_ex_new_index_ex(NULL, class_index, argl, argp,
2031cb0ef41Sopenharmony_ci                                           new_func, dup_func, free_func, 0);
2041cb0ef41Sopenharmony_ci}
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci/*
2071cb0ef41Sopenharmony_ci * Initialise a new CRYPTO_EX_DATA for use in a particular class - including
2081cb0ef41Sopenharmony_ci * calling new() callbacks for each index in the class used by this variable
2091cb0ef41Sopenharmony_ci * Thread-safe by copying a class's array of "EX_CALLBACK" entries
2101cb0ef41Sopenharmony_ci * in the lock, then using them outside the lock. Note this only applies
2111cb0ef41Sopenharmony_ci * to the global "ex_data" state (ie. class definitions), not 'ad' itself.
2121cb0ef41Sopenharmony_ci */
2131cb0ef41Sopenharmony_ciint ossl_crypto_new_ex_data_ex(OSSL_LIB_CTX *ctx, int class_index, void *obj,
2141cb0ef41Sopenharmony_ci                               CRYPTO_EX_DATA *ad)
2151cb0ef41Sopenharmony_ci{
2161cb0ef41Sopenharmony_ci    int mx, i;
2171cb0ef41Sopenharmony_ci    void *ptr;
2181cb0ef41Sopenharmony_ci    EX_CALLBACK **storage = NULL;
2191cb0ef41Sopenharmony_ci    EX_CALLBACK *stack[10];
2201cb0ef41Sopenharmony_ci    EX_CALLBACKS *ip;
2211cb0ef41Sopenharmony_ci    OSSL_EX_DATA_GLOBAL *global = ossl_lib_ctx_get_ex_data_global(ctx);
2221cb0ef41Sopenharmony_ci
2231cb0ef41Sopenharmony_ci    if (global == NULL)
2241cb0ef41Sopenharmony_ci        return 0;
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci    ip = get_and_lock(global, class_index);
2271cb0ef41Sopenharmony_ci    if (ip == NULL)
2281cb0ef41Sopenharmony_ci        return 0;
2291cb0ef41Sopenharmony_ci
2301cb0ef41Sopenharmony_ci    ad->ctx = ctx;
2311cb0ef41Sopenharmony_ci    ad->sk = NULL;
2321cb0ef41Sopenharmony_ci    mx = sk_EX_CALLBACK_num(ip->meth);
2331cb0ef41Sopenharmony_ci    if (mx > 0) {
2341cb0ef41Sopenharmony_ci        if (mx < (int)OSSL_NELEM(stack))
2351cb0ef41Sopenharmony_ci            storage = stack;
2361cb0ef41Sopenharmony_ci        else
2371cb0ef41Sopenharmony_ci            storage = OPENSSL_malloc(sizeof(*storage) * mx);
2381cb0ef41Sopenharmony_ci        if (storage != NULL)
2391cb0ef41Sopenharmony_ci            for (i = 0; i < mx; i++)
2401cb0ef41Sopenharmony_ci                storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
2411cb0ef41Sopenharmony_ci    }
2421cb0ef41Sopenharmony_ci    CRYPTO_THREAD_unlock(global->ex_data_lock);
2431cb0ef41Sopenharmony_ci
2441cb0ef41Sopenharmony_ci    if (mx > 0 && storage == NULL) {
2451cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
2461cb0ef41Sopenharmony_ci        return 0;
2471cb0ef41Sopenharmony_ci    }
2481cb0ef41Sopenharmony_ci    for (i = 0; i < mx; i++) {
2491cb0ef41Sopenharmony_ci        if (storage[i] != NULL && storage[i]->new_func != NULL) {
2501cb0ef41Sopenharmony_ci            ptr = CRYPTO_get_ex_data(ad, i);
2511cb0ef41Sopenharmony_ci            storage[i]->new_func(obj, ptr, ad, i,
2521cb0ef41Sopenharmony_ci                                 storage[i]->argl, storage[i]->argp);
2531cb0ef41Sopenharmony_ci        }
2541cb0ef41Sopenharmony_ci    }
2551cb0ef41Sopenharmony_ci    if (storage != stack)
2561cb0ef41Sopenharmony_ci        OPENSSL_free(storage);
2571cb0ef41Sopenharmony_ci    return 1;
2581cb0ef41Sopenharmony_ci}
2591cb0ef41Sopenharmony_ci
2601cb0ef41Sopenharmony_ciint CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
2611cb0ef41Sopenharmony_ci{
2621cb0ef41Sopenharmony_ci    return ossl_crypto_new_ex_data_ex(NULL, class_index, obj, ad);
2631cb0ef41Sopenharmony_ci}
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_ci/*
2661cb0ef41Sopenharmony_ci * Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks
2671cb0ef41Sopenharmony_ci * for each index in the class used by this variable
2681cb0ef41Sopenharmony_ci */
2691cb0ef41Sopenharmony_ciint CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
2701cb0ef41Sopenharmony_ci                       const CRYPTO_EX_DATA *from)
2711cb0ef41Sopenharmony_ci{
2721cb0ef41Sopenharmony_ci    int mx, j, i;
2731cb0ef41Sopenharmony_ci    void *ptr;
2741cb0ef41Sopenharmony_ci    EX_CALLBACK *stack[10];
2751cb0ef41Sopenharmony_ci    EX_CALLBACK **storage = NULL;
2761cb0ef41Sopenharmony_ci    EX_CALLBACKS *ip;
2771cb0ef41Sopenharmony_ci    int toret = 0;
2781cb0ef41Sopenharmony_ci    OSSL_EX_DATA_GLOBAL *global;
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_ci    to->ctx = from->ctx;
2811cb0ef41Sopenharmony_ci    if (from->sk == NULL)
2821cb0ef41Sopenharmony_ci        /* Nothing to copy over */
2831cb0ef41Sopenharmony_ci        return 1;
2841cb0ef41Sopenharmony_ci
2851cb0ef41Sopenharmony_ci    global = ossl_lib_ctx_get_ex_data_global(from->ctx);
2861cb0ef41Sopenharmony_ci    if (global == NULL)
2871cb0ef41Sopenharmony_ci        return 0;
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_ci    ip = get_and_lock(global, class_index);
2901cb0ef41Sopenharmony_ci    if (ip == NULL)
2911cb0ef41Sopenharmony_ci        return 0;
2921cb0ef41Sopenharmony_ci
2931cb0ef41Sopenharmony_ci    mx = sk_EX_CALLBACK_num(ip->meth);
2941cb0ef41Sopenharmony_ci    j = sk_void_num(from->sk);
2951cb0ef41Sopenharmony_ci    if (j < mx)
2961cb0ef41Sopenharmony_ci        mx = j;
2971cb0ef41Sopenharmony_ci    if (mx > 0) {
2981cb0ef41Sopenharmony_ci        if (mx < (int)OSSL_NELEM(stack))
2991cb0ef41Sopenharmony_ci            storage = stack;
3001cb0ef41Sopenharmony_ci        else
3011cb0ef41Sopenharmony_ci            storage = OPENSSL_malloc(sizeof(*storage) * mx);
3021cb0ef41Sopenharmony_ci        if (storage != NULL)
3031cb0ef41Sopenharmony_ci            for (i = 0; i < mx; i++)
3041cb0ef41Sopenharmony_ci                storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
3051cb0ef41Sopenharmony_ci    }
3061cb0ef41Sopenharmony_ci    CRYPTO_THREAD_unlock(global->ex_data_lock);
3071cb0ef41Sopenharmony_ci
3081cb0ef41Sopenharmony_ci    if (mx == 0)
3091cb0ef41Sopenharmony_ci        return 1;
3101cb0ef41Sopenharmony_ci    if (storage == NULL) {
3111cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
3121cb0ef41Sopenharmony_ci        return 0;
3131cb0ef41Sopenharmony_ci    }
3141cb0ef41Sopenharmony_ci    /*
3151cb0ef41Sopenharmony_ci     * Make sure the ex_data stack is at least |mx| elements long to avoid
3161cb0ef41Sopenharmony_ci     * issues in the for loop that follows; so go get the |mx|'th element
3171cb0ef41Sopenharmony_ci     * (if it does not exist CRYPTO_get_ex_data() returns NULL), and assign
3181cb0ef41Sopenharmony_ci     * to itself. This is normally a no-op; but ensures the stack is the
3191cb0ef41Sopenharmony_ci     * proper size
3201cb0ef41Sopenharmony_ci     */
3211cb0ef41Sopenharmony_ci    if (!CRYPTO_set_ex_data(to, mx - 1, CRYPTO_get_ex_data(to, mx - 1)))
3221cb0ef41Sopenharmony_ci        goto err;
3231cb0ef41Sopenharmony_ci
3241cb0ef41Sopenharmony_ci    for (i = 0; i < mx; i++) {
3251cb0ef41Sopenharmony_ci        ptr = CRYPTO_get_ex_data(from, i);
3261cb0ef41Sopenharmony_ci        if (storage[i] != NULL && storage[i]->dup_func != NULL)
3271cb0ef41Sopenharmony_ci            if (!storage[i]->dup_func(to, from, &ptr, i,
3281cb0ef41Sopenharmony_ci                                      storage[i]->argl, storage[i]->argp))
3291cb0ef41Sopenharmony_ci                goto err;
3301cb0ef41Sopenharmony_ci        CRYPTO_set_ex_data(to, i, ptr);
3311cb0ef41Sopenharmony_ci    }
3321cb0ef41Sopenharmony_ci    toret = 1;
3331cb0ef41Sopenharmony_ci err:
3341cb0ef41Sopenharmony_ci    if (storage != stack)
3351cb0ef41Sopenharmony_ci        OPENSSL_free(storage);
3361cb0ef41Sopenharmony_ci    return toret;
3371cb0ef41Sopenharmony_ci}
3381cb0ef41Sopenharmony_ci
3391cb0ef41Sopenharmony_cistruct ex_callback_entry {
3401cb0ef41Sopenharmony_ci    const EX_CALLBACK *excb;
3411cb0ef41Sopenharmony_ci    int index;
3421cb0ef41Sopenharmony_ci};
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_cistatic int ex_callback_compare(const void *a, const void *b)
3451cb0ef41Sopenharmony_ci{
3461cb0ef41Sopenharmony_ci    const struct ex_callback_entry *ap = (const struct ex_callback_entry *)a;
3471cb0ef41Sopenharmony_ci    const struct ex_callback_entry *bp = (const struct ex_callback_entry *)b;
3481cb0ef41Sopenharmony_ci
3491cb0ef41Sopenharmony_ci    if (ap->excb == bp->excb)
3501cb0ef41Sopenharmony_ci        return 0;
3511cb0ef41Sopenharmony_ci
3521cb0ef41Sopenharmony_ci    if (ap->excb == NULL)
3531cb0ef41Sopenharmony_ci        return 1;
3541cb0ef41Sopenharmony_ci    if (bp->excb == NULL)
3551cb0ef41Sopenharmony_ci        return -1;
3561cb0ef41Sopenharmony_ci    if (ap->excb->priority == bp->excb->priority)
3571cb0ef41Sopenharmony_ci        return 0;
3581cb0ef41Sopenharmony_ci    return ap->excb->priority > bp->excb->priority ? -1 : 1;
3591cb0ef41Sopenharmony_ci}
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_ci/*
3621cb0ef41Sopenharmony_ci * Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for
3631cb0ef41Sopenharmony_ci * each index in the class used by this variable
3641cb0ef41Sopenharmony_ci */
3651cb0ef41Sopenharmony_civoid CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
3661cb0ef41Sopenharmony_ci{
3671cb0ef41Sopenharmony_ci    int mx, i;
3681cb0ef41Sopenharmony_ci    EX_CALLBACKS *ip;
3691cb0ef41Sopenharmony_ci    void *ptr;
3701cb0ef41Sopenharmony_ci    const EX_CALLBACK *f;
3711cb0ef41Sopenharmony_ci    struct ex_callback_entry stack[10];
3721cb0ef41Sopenharmony_ci    struct ex_callback_entry *storage = NULL;
3731cb0ef41Sopenharmony_ci    OSSL_EX_DATA_GLOBAL *global = ossl_lib_ctx_get_ex_data_global(ad->ctx);
3741cb0ef41Sopenharmony_ci
3751cb0ef41Sopenharmony_ci    if (global == NULL)
3761cb0ef41Sopenharmony_ci        goto err;
3771cb0ef41Sopenharmony_ci
3781cb0ef41Sopenharmony_ci    ip = get_and_lock(global, class_index);
3791cb0ef41Sopenharmony_ci    if (ip == NULL)
3801cb0ef41Sopenharmony_ci        goto err;
3811cb0ef41Sopenharmony_ci
3821cb0ef41Sopenharmony_ci    mx = sk_EX_CALLBACK_num(ip->meth);
3831cb0ef41Sopenharmony_ci    if (mx > 0) {
3841cb0ef41Sopenharmony_ci        if (mx < (int)OSSL_NELEM(stack))
3851cb0ef41Sopenharmony_ci            storage = stack;
3861cb0ef41Sopenharmony_ci        else
3871cb0ef41Sopenharmony_ci            storage = OPENSSL_malloc(sizeof(*storage) * mx);
3881cb0ef41Sopenharmony_ci        if (storage != NULL)
3891cb0ef41Sopenharmony_ci            for (i = 0; i < mx; i++) {
3901cb0ef41Sopenharmony_ci                storage[i].excb = sk_EX_CALLBACK_value(ip->meth, i);
3911cb0ef41Sopenharmony_ci                storage[i].index = i;
3921cb0ef41Sopenharmony_ci            }
3931cb0ef41Sopenharmony_ci    }
3941cb0ef41Sopenharmony_ci    CRYPTO_THREAD_unlock(global->ex_data_lock);
3951cb0ef41Sopenharmony_ci
3961cb0ef41Sopenharmony_ci    if (storage != NULL) {
3971cb0ef41Sopenharmony_ci        /* Sort according to priority. High priority first */
3981cb0ef41Sopenharmony_ci        qsort(storage, mx, sizeof(*storage), ex_callback_compare);
3991cb0ef41Sopenharmony_ci        for (i = 0; i < mx; i++) {
4001cb0ef41Sopenharmony_ci            f = storage[i].excb;
4011cb0ef41Sopenharmony_ci
4021cb0ef41Sopenharmony_ci            if (f != NULL && f->free_func != NULL) {
4031cb0ef41Sopenharmony_ci                ptr = CRYPTO_get_ex_data(ad, storage[i].index);
4041cb0ef41Sopenharmony_ci                f->free_func(obj, ptr, ad, storage[i].index, f->argl, f->argp);
4051cb0ef41Sopenharmony_ci            }
4061cb0ef41Sopenharmony_ci        }
4071cb0ef41Sopenharmony_ci    }
4081cb0ef41Sopenharmony_ci
4091cb0ef41Sopenharmony_ci    if (storage != stack)
4101cb0ef41Sopenharmony_ci        OPENSSL_free(storage);
4111cb0ef41Sopenharmony_ci err:
4121cb0ef41Sopenharmony_ci    sk_void_free(ad->sk);
4131cb0ef41Sopenharmony_ci    ad->sk = NULL;
4141cb0ef41Sopenharmony_ci    ad->ctx = NULL;
4151cb0ef41Sopenharmony_ci}
4161cb0ef41Sopenharmony_ci
4171cb0ef41Sopenharmony_ci/*
4181cb0ef41Sopenharmony_ci * Allocate a given CRYPTO_EX_DATA item using the class specific allocation
4191cb0ef41Sopenharmony_ci * function
4201cb0ef41Sopenharmony_ci */
4211cb0ef41Sopenharmony_ciint CRYPTO_alloc_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad,
4221cb0ef41Sopenharmony_ci                         int idx)
4231cb0ef41Sopenharmony_ci{
4241cb0ef41Sopenharmony_ci    void *curval;
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_ci    curval = CRYPTO_get_ex_data(ad, idx);
4271cb0ef41Sopenharmony_ci    /* Already there, no need to allocate */
4281cb0ef41Sopenharmony_ci    if (curval != NULL)
4291cb0ef41Sopenharmony_ci        return 1;
4301cb0ef41Sopenharmony_ci
4311cb0ef41Sopenharmony_ci    return ossl_crypto_alloc_ex_data_intern(class_index, obj, ad, idx);
4321cb0ef41Sopenharmony_ci}
4331cb0ef41Sopenharmony_ci
4341cb0ef41Sopenharmony_ciint ossl_crypto_alloc_ex_data_intern(int class_index, void *obj,
4351cb0ef41Sopenharmony_ci                                     CRYPTO_EX_DATA *ad, int idx)
4361cb0ef41Sopenharmony_ci{
4371cb0ef41Sopenharmony_ci    EX_CALLBACK *f;
4381cb0ef41Sopenharmony_ci    EX_CALLBACKS *ip;
4391cb0ef41Sopenharmony_ci    OSSL_EX_DATA_GLOBAL *global;
4401cb0ef41Sopenharmony_ci
4411cb0ef41Sopenharmony_ci    global = ossl_lib_ctx_get_ex_data_global(ad->ctx);
4421cb0ef41Sopenharmony_ci    if (global == NULL)
4431cb0ef41Sopenharmony_ci        return 0;
4441cb0ef41Sopenharmony_ci
4451cb0ef41Sopenharmony_ci    ip = get_and_lock(global, class_index);
4461cb0ef41Sopenharmony_ci    if (ip == NULL)
4471cb0ef41Sopenharmony_ci        return 0;
4481cb0ef41Sopenharmony_ci    f = sk_EX_CALLBACK_value(ip->meth, idx);
4491cb0ef41Sopenharmony_ci    CRYPTO_THREAD_unlock(global->ex_data_lock);
4501cb0ef41Sopenharmony_ci
4511cb0ef41Sopenharmony_ci    /*
4521cb0ef41Sopenharmony_ci     * This should end up calling CRYPTO_set_ex_data(), which allocates
4531cb0ef41Sopenharmony_ci     * everything necessary to support placing the new data in the right spot.
4541cb0ef41Sopenharmony_ci     */
4551cb0ef41Sopenharmony_ci    if (f->new_func == NULL)
4561cb0ef41Sopenharmony_ci        return 0;
4571cb0ef41Sopenharmony_ci
4581cb0ef41Sopenharmony_ci    f->new_func(obj, NULL, ad, idx, f->argl, f->argp);
4591cb0ef41Sopenharmony_ci
4601cb0ef41Sopenharmony_ci    return 1;
4611cb0ef41Sopenharmony_ci}
4621cb0ef41Sopenharmony_ci
4631cb0ef41Sopenharmony_ci/*
4641cb0ef41Sopenharmony_ci * For a given CRYPTO_EX_DATA variable, set the value corresponding to a
4651cb0ef41Sopenharmony_ci * particular index in the class used by this variable
4661cb0ef41Sopenharmony_ci */
4671cb0ef41Sopenharmony_ciint CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val)
4681cb0ef41Sopenharmony_ci{
4691cb0ef41Sopenharmony_ci    int i;
4701cb0ef41Sopenharmony_ci
4711cb0ef41Sopenharmony_ci    if (ad->sk == NULL) {
4721cb0ef41Sopenharmony_ci        if ((ad->sk = sk_void_new_null()) == NULL) {
4731cb0ef41Sopenharmony_ci            ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
4741cb0ef41Sopenharmony_ci            return 0;
4751cb0ef41Sopenharmony_ci        }
4761cb0ef41Sopenharmony_ci    }
4771cb0ef41Sopenharmony_ci
4781cb0ef41Sopenharmony_ci    for (i = sk_void_num(ad->sk); i <= idx; ++i) {
4791cb0ef41Sopenharmony_ci        if (!sk_void_push(ad->sk, NULL)) {
4801cb0ef41Sopenharmony_ci            ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
4811cb0ef41Sopenharmony_ci            return 0;
4821cb0ef41Sopenharmony_ci        }
4831cb0ef41Sopenharmony_ci    }
4841cb0ef41Sopenharmony_ci    if (sk_void_set(ad->sk, idx, val) != val) {
4851cb0ef41Sopenharmony_ci        /* Probably the index is out of bounds */
4861cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
4871cb0ef41Sopenharmony_ci        return 0;
4881cb0ef41Sopenharmony_ci    }
4891cb0ef41Sopenharmony_ci    return 1;
4901cb0ef41Sopenharmony_ci}
4911cb0ef41Sopenharmony_ci
4921cb0ef41Sopenharmony_ci/*
4931cb0ef41Sopenharmony_ci * For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a
4941cb0ef41Sopenharmony_ci * particular index in the class used by this variable
4951cb0ef41Sopenharmony_ci */
4961cb0ef41Sopenharmony_civoid *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx)
4971cb0ef41Sopenharmony_ci{
4981cb0ef41Sopenharmony_ci    if (ad->sk == NULL || idx >= sk_void_num(ad->sk))
4991cb0ef41Sopenharmony_ci        return NULL;
5001cb0ef41Sopenharmony_ci    return sk_void_value(ad->sk, idx);
5011cb0ef41Sopenharmony_ci}
5021cb0ef41Sopenharmony_ci
5031cb0ef41Sopenharmony_ciOSSL_LIB_CTX *ossl_crypto_ex_data_get_ossl_lib_ctx(const CRYPTO_EX_DATA *ad)
5041cb0ef41Sopenharmony_ci{
5051cb0ef41Sopenharmony_ci    return ad->ctx;
5061cb0ef41Sopenharmony_ci}
507