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