1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include <stdlib.h> 11e1051a39Sopenharmony_ci#include "crypto/cryptlib.h" 12e1051a39Sopenharmony_ci#include "internal/thread_once.h" 13e1051a39Sopenharmony_ci 14e1051a39Sopenharmony_ciint ossl_do_ex_data_init(OSSL_LIB_CTX *ctx) 15e1051a39Sopenharmony_ci{ 16e1051a39Sopenharmony_ci OSSL_EX_DATA_GLOBAL *global = ossl_lib_ctx_get_ex_data_global(ctx); 17e1051a39Sopenharmony_ci 18e1051a39Sopenharmony_ci if (global == NULL) 19e1051a39Sopenharmony_ci return 0; 20e1051a39Sopenharmony_ci 21e1051a39Sopenharmony_ci global->ex_data_lock = CRYPTO_THREAD_lock_new(); 22e1051a39Sopenharmony_ci return global->ex_data_lock != NULL; 23e1051a39Sopenharmony_ci} 24e1051a39Sopenharmony_ci 25e1051a39Sopenharmony_ci/* 26e1051a39Sopenharmony_ci * Return the EX_CALLBACKS from the |ex_data| array that corresponds to 27e1051a39Sopenharmony_ci * a given class. On success, *holds the lock.* 28e1051a39Sopenharmony_ci * The |global| parameter is assumed to be non null (checked by the caller). 29e1051a39Sopenharmony_ci */ 30e1051a39Sopenharmony_cistatic EX_CALLBACKS *get_and_lock(OSSL_EX_DATA_GLOBAL *global, int class_index) 31e1051a39Sopenharmony_ci{ 32e1051a39Sopenharmony_ci EX_CALLBACKS *ip; 33e1051a39Sopenharmony_ci 34e1051a39Sopenharmony_ci if (class_index < 0 || class_index >= CRYPTO_EX_INDEX__COUNT) { 35e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 36e1051a39Sopenharmony_ci return NULL; 37e1051a39Sopenharmony_ci } 38e1051a39Sopenharmony_ci 39e1051a39Sopenharmony_ci if (global->ex_data_lock == NULL) { 40e1051a39Sopenharmony_ci /* 41e1051a39Sopenharmony_ci * If we get here, someone (who?) cleaned up the lock, so just 42e1051a39Sopenharmony_ci * treat it as an error. 43e1051a39Sopenharmony_ci */ 44e1051a39Sopenharmony_ci return NULL; 45e1051a39Sopenharmony_ci } 46e1051a39Sopenharmony_ci 47e1051a39Sopenharmony_ci if (!CRYPTO_THREAD_write_lock(global->ex_data_lock)) 48e1051a39Sopenharmony_ci return NULL; 49e1051a39Sopenharmony_ci ip = &global->ex_data[class_index]; 50e1051a39Sopenharmony_ci return ip; 51e1051a39Sopenharmony_ci} 52e1051a39Sopenharmony_ci 53e1051a39Sopenharmony_cistatic void cleanup_cb(EX_CALLBACK *funcs) 54e1051a39Sopenharmony_ci{ 55e1051a39Sopenharmony_ci OPENSSL_free(funcs); 56e1051a39Sopenharmony_ci} 57e1051a39Sopenharmony_ci 58e1051a39Sopenharmony_ci/* 59e1051a39Sopenharmony_ci * Release all "ex_data" state to prevent memory leaks. This can't be made 60e1051a39Sopenharmony_ci * thread-safe without overhauling a lot of stuff, and shouldn't really be 61e1051a39Sopenharmony_ci * called under potential race-conditions anyway (it's for program shutdown 62e1051a39Sopenharmony_ci * after all). 63e1051a39Sopenharmony_ci */ 64e1051a39Sopenharmony_civoid ossl_crypto_cleanup_all_ex_data_int(OSSL_LIB_CTX *ctx) 65e1051a39Sopenharmony_ci{ 66e1051a39Sopenharmony_ci int i; 67e1051a39Sopenharmony_ci OSSL_EX_DATA_GLOBAL *global = ossl_lib_ctx_get_ex_data_global(ctx); 68e1051a39Sopenharmony_ci 69e1051a39Sopenharmony_ci if (global == NULL) 70e1051a39Sopenharmony_ci return; 71e1051a39Sopenharmony_ci 72e1051a39Sopenharmony_ci for (i = 0; i < CRYPTO_EX_INDEX__COUNT; ++i) { 73e1051a39Sopenharmony_ci EX_CALLBACKS *ip = &global->ex_data[i]; 74e1051a39Sopenharmony_ci 75e1051a39Sopenharmony_ci sk_EX_CALLBACK_pop_free(ip->meth, cleanup_cb); 76e1051a39Sopenharmony_ci ip->meth = NULL; 77e1051a39Sopenharmony_ci } 78e1051a39Sopenharmony_ci 79e1051a39Sopenharmony_ci CRYPTO_THREAD_lock_free(global->ex_data_lock); 80e1051a39Sopenharmony_ci global->ex_data_lock = NULL; 81e1051a39Sopenharmony_ci} 82e1051a39Sopenharmony_ci 83e1051a39Sopenharmony_ci 84e1051a39Sopenharmony_ci/* 85e1051a39Sopenharmony_ci * Unregister a new index by replacing the callbacks with no-ops. 86e1051a39Sopenharmony_ci * Any in-use instances are leaked. 87e1051a39Sopenharmony_ci */ 88e1051a39Sopenharmony_cistatic void dummy_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, 89e1051a39Sopenharmony_ci long argl, void *argp) 90e1051a39Sopenharmony_ci{ 91e1051a39Sopenharmony_ci} 92e1051a39Sopenharmony_ci 93e1051a39Sopenharmony_cistatic void dummy_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, 94e1051a39Sopenharmony_ci long argl, void *argp) 95e1051a39Sopenharmony_ci{ 96e1051a39Sopenharmony_ci} 97e1051a39Sopenharmony_ci 98e1051a39Sopenharmony_cistatic int dummy_dup(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from, 99e1051a39Sopenharmony_ci void **from_d, int idx, 100e1051a39Sopenharmony_ci long argl, void *argp) 101e1051a39Sopenharmony_ci{ 102e1051a39Sopenharmony_ci return 1; 103e1051a39Sopenharmony_ci} 104e1051a39Sopenharmony_ci 105e1051a39Sopenharmony_ciint ossl_crypto_free_ex_index_ex(OSSL_LIB_CTX *ctx, int class_index, int idx) 106e1051a39Sopenharmony_ci{ 107e1051a39Sopenharmony_ci EX_CALLBACKS *ip; 108e1051a39Sopenharmony_ci EX_CALLBACK *a; 109e1051a39Sopenharmony_ci int toret = 0; 110e1051a39Sopenharmony_ci OSSL_EX_DATA_GLOBAL *global = ossl_lib_ctx_get_ex_data_global(ctx); 111e1051a39Sopenharmony_ci 112e1051a39Sopenharmony_ci if (global == NULL) 113e1051a39Sopenharmony_ci return 0; 114e1051a39Sopenharmony_ci 115e1051a39Sopenharmony_ci ip = get_and_lock(global, class_index); 116e1051a39Sopenharmony_ci if (ip == NULL) 117e1051a39Sopenharmony_ci return 0; 118e1051a39Sopenharmony_ci 119e1051a39Sopenharmony_ci if (idx < 0 || idx >= sk_EX_CALLBACK_num(ip->meth)) 120e1051a39Sopenharmony_ci goto err; 121e1051a39Sopenharmony_ci a = sk_EX_CALLBACK_value(ip->meth, idx); 122e1051a39Sopenharmony_ci if (a == NULL) 123e1051a39Sopenharmony_ci goto err; 124e1051a39Sopenharmony_ci a->new_func = dummy_new; 125e1051a39Sopenharmony_ci a->dup_func = dummy_dup; 126e1051a39Sopenharmony_ci a->free_func = dummy_free; 127e1051a39Sopenharmony_ci toret = 1; 128e1051a39Sopenharmony_cierr: 129e1051a39Sopenharmony_ci CRYPTO_THREAD_unlock(global->ex_data_lock); 130e1051a39Sopenharmony_ci return toret; 131e1051a39Sopenharmony_ci} 132e1051a39Sopenharmony_ci 133e1051a39Sopenharmony_ciint CRYPTO_free_ex_index(int class_index, int idx) 134e1051a39Sopenharmony_ci{ 135e1051a39Sopenharmony_ci return ossl_crypto_free_ex_index_ex(NULL, class_index, idx); 136e1051a39Sopenharmony_ci} 137e1051a39Sopenharmony_ci 138e1051a39Sopenharmony_ci/* 139e1051a39Sopenharmony_ci * Register a new index. 140e1051a39Sopenharmony_ci */ 141e1051a39Sopenharmony_ciint ossl_crypto_get_ex_new_index_ex(OSSL_LIB_CTX *ctx, int class_index, 142e1051a39Sopenharmony_ci long argl, void *argp, 143e1051a39Sopenharmony_ci CRYPTO_EX_new *new_func, 144e1051a39Sopenharmony_ci CRYPTO_EX_dup *dup_func, 145e1051a39Sopenharmony_ci CRYPTO_EX_free *free_func, 146e1051a39Sopenharmony_ci int priority) 147e1051a39Sopenharmony_ci{ 148e1051a39Sopenharmony_ci int toret = -1; 149e1051a39Sopenharmony_ci EX_CALLBACK *a; 150e1051a39Sopenharmony_ci EX_CALLBACKS *ip; 151e1051a39Sopenharmony_ci OSSL_EX_DATA_GLOBAL *global = ossl_lib_ctx_get_ex_data_global(ctx); 152e1051a39Sopenharmony_ci 153e1051a39Sopenharmony_ci if (global == NULL) 154e1051a39Sopenharmony_ci return -1; 155e1051a39Sopenharmony_ci 156e1051a39Sopenharmony_ci ip = get_and_lock(global, class_index); 157e1051a39Sopenharmony_ci if (ip == NULL) 158e1051a39Sopenharmony_ci return -1; 159e1051a39Sopenharmony_ci 160e1051a39Sopenharmony_ci if (ip->meth == NULL) { 161e1051a39Sopenharmony_ci ip->meth = sk_EX_CALLBACK_new_null(); 162e1051a39Sopenharmony_ci /* We push an initial value on the stack because the SSL 163e1051a39Sopenharmony_ci * "app_data" routines use ex_data index zero. See RT 3710. */ 164e1051a39Sopenharmony_ci if (ip->meth == NULL 165e1051a39Sopenharmony_ci || !sk_EX_CALLBACK_push(ip->meth, NULL)) { 166e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); 167e1051a39Sopenharmony_ci goto err; 168e1051a39Sopenharmony_ci } 169e1051a39Sopenharmony_ci } 170e1051a39Sopenharmony_ci 171e1051a39Sopenharmony_ci a = (EX_CALLBACK *)OPENSSL_malloc(sizeof(*a)); 172e1051a39Sopenharmony_ci if (a == NULL) { 173e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); 174e1051a39Sopenharmony_ci goto err; 175e1051a39Sopenharmony_ci } 176e1051a39Sopenharmony_ci a->argl = argl; 177e1051a39Sopenharmony_ci a->argp = argp; 178e1051a39Sopenharmony_ci a->new_func = new_func; 179e1051a39Sopenharmony_ci a->dup_func = dup_func; 180e1051a39Sopenharmony_ci a->free_func = free_func; 181e1051a39Sopenharmony_ci a->priority = priority; 182e1051a39Sopenharmony_ci 183e1051a39Sopenharmony_ci if (!sk_EX_CALLBACK_push(ip->meth, NULL)) { 184e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); 185e1051a39Sopenharmony_ci OPENSSL_free(a); 186e1051a39Sopenharmony_ci goto err; 187e1051a39Sopenharmony_ci } 188e1051a39Sopenharmony_ci toret = sk_EX_CALLBACK_num(ip->meth) - 1; 189e1051a39Sopenharmony_ci (void)sk_EX_CALLBACK_set(ip->meth, toret, a); 190e1051a39Sopenharmony_ci 191e1051a39Sopenharmony_ci err: 192e1051a39Sopenharmony_ci CRYPTO_THREAD_unlock(global->ex_data_lock); 193e1051a39Sopenharmony_ci return toret; 194e1051a39Sopenharmony_ci} 195e1051a39Sopenharmony_ci 196e1051a39Sopenharmony_ciint CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, 197e1051a39Sopenharmony_ci CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 198e1051a39Sopenharmony_ci CRYPTO_EX_free *free_func) 199e1051a39Sopenharmony_ci{ 200e1051a39Sopenharmony_ci return ossl_crypto_get_ex_new_index_ex(NULL, class_index, argl, argp, 201e1051a39Sopenharmony_ci new_func, dup_func, free_func, 0); 202e1051a39Sopenharmony_ci} 203e1051a39Sopenharmony_ci 204e1051a39Sopenharmony_ci/* 205e1051a39Sopenharmony_ci * Initialise a new CRYPTO_EX_DATA for use in a particular class - including 206e1051a39Sopenharmony_ci * calling new() callbacks for each index in the class used by this variable 207e1051a39Sopenharmony_ci * Thread-safe by copying a class's array of "EX_CALLBACK" entries 208e1051a39Sopenharmony_ci * in the lock, then using them outside the lock. Note this only applies 209e1051a39Sopenharmony_ci * to the global "ex_data" state (ie. class definitions), not 'ad' itself. 210e1051a39Sopenharmony_ci */ 211e1051a39Sopenharmony_ciint ossl_crypto_new_ex_data_ex(OSSL_LIB_CTX *ctx, int class_index, void *obj, 212e1051a39Sopenharmony_ci CRYPTO_EX_DATA *ad) 213e1051a39Sopenharmony_ci{ 214e1051a39Sopenharmony_ci int mx, i; 215e1051a39Sopenharmony_ci void *ptr; 216e1051a39Sopenharmony_ci EX_CALLBACK **storage = NULL; 217e1051a39Sopenharmony_ci EX_CALLBACK *stack[10]; 218e1051a39Sopenharmony_ci EX_CALLBACKS *ip; 219e1051a39Sopenharmony_ci OSSL_EX_DATA_GLOBAL *global = ossl_lib_ctx_get_ex_data_global(ctx); 220e1051a39Sopenharmony_ci 221e1051a39Sopenharmony_ci if (global == NULL) 222e1051a39Sopenharmony_ci return 0; 223e1051a39Sopenharmony_ci 224e1051a39Sopenharmony_ci ip = get_and_lock(global, class_index); 225e1051a39Sopenharmony_ci if (ip == NULL) 226e1051a39Sopenharmony_ci return 0; 227e1051a39Sopenharmony_ci 228e1051a39Sopenharmony_ci ad->ctx = ctx; 229e1051a39Sopenharmony_ci ad->sk = NULL; 230e1051a39Sopenharmony_ci mx = sk_EX_CALLBACK_num(ip->meth); 231e1051a39Sopenharmony_ci if (mx > 0) { 232e1051a39Sopenharmony_ci if (mx < (int)OSSL_NELEM(stack)) 233e1051a39Sopenharmony_ci storage = stack; 234e1051a39Sopenharmony_ci else 235e1051a39Sopenharmony_ci storage = OPENSSL_malloc(sizeof(*storage) * mx); 236e1051a39Sopenharmony_ci if (storage != NULL) 237e1051a39Sopenharmony_ci for (i = 0; i < mx; i++) 238e1051a39Sopenharmony_ci storage[i] = sk_EX_CALLBACK_value(ip->meth, i); 239e1051a39Sopenharmony_ci } 240e1051a39Sopenharmony_ci CRYPTO_THREAD_unlock(global->ex_data_lock); 241e1051a39Sopenharmony_ci 242e1051a39Sopenharmony_ci if (mx > 0 && storage == NULL) { 243e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); 244e1051a39Sopenharmony_ci return 0; 245e1051a39Sopenharmony_ci } 246e1051a39Sopenharmony_ci for (i = 0; i < mx; i++) { 247e1051a39Sopenharmony_ci if (storage[i] != NULL && storage[i]->new_func != NULL) { 248e1051a39Sopenharmony_ci ptr = CRYPTO_get_ex_data(ad, i); 249e1051a39Sopenharmony_ci storage[i]->new_func(obj, ptr, ad, i, 250e1051a39Sopenharmony_ci storage[i]->argl, storage[i]->argp); 251e1051a39Sopenharmony_ci } 252e1051a39Sopenharmony_ci } 253e1051a39Sopenharmony_ci if (storage != stack) 254e1051a39Sopenharmony_ci OPENSSL_free(storage); 255e1051a39Sopenharmony_ci return 1; 256e1051a39Sopenharmony_ci} 257e1051a39Sopenharmony_ci 258e1051a39Sopenharmony_ciint CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) 259e1051a39Sopenharmony_ci{ 260e1051a39Sopenharmony_ci return ossl_crypto_new_ex_data_ex(NULL, class_index, obj, ad); 261e1051a39Sopenharmony_ci} 262e1051a39Sopenharmony_ci 263e1051a39Sopenharmony_ci/* 264e1051a39Sopenharmony_ci * Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks 265e1051a39Sopenharmony_ci * for each index in the class used by this variable 266e1051a39Sopenharmony_ci */ 267e1051a39Sopenharmony_ciint CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, 268e1051a39Sopenharmony_ci const CRYPTO_EX_DATA *from) 269e1051a39Sopenharmony_ci{ 270e1051a39Sopenharmony_ci int mx, j, i; 271e1051a39Sopenharmony_ci void *ptr; 272e1051a39Sopenharmony_ci EX_CALLBACK *stack[10]; 273e1051a39Sopenharmony_ci EX_CALLBACK **storage = NULL; 274e1051a39Sopenharmony_ci EX_CALLBACKS *ip; 275e1051a39Sopenharmony_ci int toret = 0; 276e1051a39Sopenharmony_ci OSSL_EX_DATA_GLOBAL *global; 277e1051a39Sopenharmony_ci 278e1051a39Sopenharmony_ci to->ctx = from->ctx; 279e1051a39Sopenharmony_ci if (from->sk == NULL) 280e1051a39Sopenharmony_ci /* Nothing to copy over */ 281e1051a39Sopenharmony_ci return 1; 282e1051a39Sopenharmony_ci 283e1051a39Sopenharmony_ci global = ossl_lib_ctx_get_ex_data_global(from->ctx); 284e1051a39Sopenharmony_ci if (global == NULL) 285e1051a39Sopenharmony_ci return 0; 286e1051a39Sopenharmony_ci 287e1051a39Sopenharmony_ci ip = get_and_lock(global, class_index); 288e1051a39Sopenharmony_ci if (ip == NULL) 289e1051a39Sopenharmony_ci return 0; 290e1051a39Sopenharmony_ci 291e1051a39Sopenharmony_ci mx = sk_EX_CALLBACK_num(ip->meth); 292e1051a39Sopenharmony_ci j = sk_void_num(from->sk); 293e1051a39Sopenharmony_ci if (j < mx) 294e1051a39Sopenharmony_ci mx = j; 295e1051a39Sopenharmony_ci if (mx > 0) { 296e1051a39Sopenharmony_ci if (mx < (int)OSSL_NELEM(stack)) 297e1051a39Sopenharmony_ci storage = stack; 298e1051a39Sopenharmony_ci else 299e1051a39Sopenharmony_ci storage = OPENSSL_malloc(sizeof(*storage) * mx); 300e1051a39Sopenharmony_ci if (storage != NULL) 301e1051a39Sopenharmony_ci for (i = 0; i < mx; i++) 302e1051a39Sopenharmony_ci storage[i] = sk_EX_CALLBACK_value(ip->meth, i); 303e1051a39Sopenharmony_ci } 304e1051a39Sopenharmony_ci CRYPTO_THREAD_unlock(global->ex_data_lock); 305e1051a39Sopenharmony_ci 306e1051a39Sopenharmony_ci if (mx == 0) 307e1051a39Sopenharmony_ci return 1; 308e1051a39Sopenharmony_ci if (storage == NULL) { 309e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); 310e1051a39Sopenharmony_ci return 0; 311e1051a39Sopenharmony_ci } 312e1051a39Sopenharmony_ci /* 313e1051a39Sopenharmony_ci * Make sure the ex_data stack is at least |mx| elements long to avoid 314e1051a39Sopenharmony_ci * issues in the for loop that follows; so go get the |mx|'th element 315e1051a39Sopenharmony_ci * (if it does not exist CRYPTO_get_ex_data() returns NULL), and assign 316e1051a39Sopenharmony_ci * to itself. This is normally a no-op; but ensures the stack is the 317e1051a39Sopenharmony_ci * proper size 318e1051a39Sopenharmony_ci */ 319e1051a39Sopenharmony_ci if (!CRYPTO_set_ex_data(to, mx - 1, CRYPTO_get_ex_data(to, mx - 1))) 320e1051a39Sopenharmony_ci goto err; 321e1051a39Sopenharmony_ci 322e1051a39Sopenharmony_ci for (i = 0; i < mx; i++) { 323e1051a39Sopenharmony_ci ptr = CRYPTO_get_ex_data(from, i); 324e1051a39Sopenharmony_ci if (storage[i] != NULL && storage[i]->dup_func != NULL) 325e1051a39Sopenharmony_ci if (!storage[i]->dup_func(to, from, &ptr, i, 326e1051a39Sopenharmony_ci storage[i]->argl, storage[i]->argp)) 327e1051a39Sopenharmony_ci goto err; 328e1051a39Sopenharmony_ci CRYPTO_set_ex_data(to, i, ptr); 329e1051a39Sopenharmony_ci } 330e1051a39Sopenharmony_ci toret = 1; 331e1051a39Sopenharmony_ci err: 332e1051a39Sopenharmony_ci if (storage != stack) 333e1051a39Sopenharmony_ci OPENSSL_free(storage); 334e1051a39Sopenharmony_ci return toret; 335e1051a39Sopenharmony_ci} 336e1051a39Sopenharmony_ci 337e1051a39Sopenharmony_cistruct ex_callback_entry { 338e1051a39Sopenharmony_ci const EX_CALLBACK *excb; 339e1051a39Sopenharmony_ci int index; 340e1051a39Sopenharmony_ci}; 341e1051a39Sopenharmony_ci 342e1051a39Sopenharmony_cistatic int ex_callback_compare(const void *a, const void *b) 343e1051a39Sopenharmony_ci{ 344e1051a39Sopenharmony_ci const struct ex_callback_entry *ap = (const struct ex_callback_entry *)a; 345e1051a39Sopenharmony_ci const struct ex_callback_entry *bp = (const struct ex_callback_entry *)b; 346e1051a39Sopenharmony_ci 347e1051a39Sopenharmony_ci if (ap->excb == bp->excb) 348e1051a39Sopenharmony_ci return 0; 349e1051a39Sopenharmony_ci 350e1051a39Sopenharmony_ci if (ap->excb == NULL) 351e1051a39Sopenharmony_ci return 1; 352e1051a39Sopenharmony_ci if (bp->excb == NULL) 353e1051a39Sopenharmony_ci return -1; 354e1051a39Sopenharmony_ci if (ap->excb->priority == bp->excb->priority) 355e1051a39Sopenharmony_ci return 0; 356e1051a39Sopenharmony_ci return ap->excb->priority > bp->excb->priority ? -1 : 1; 357e1051a39Sopenharmony_ci} 358e1051a39Sopenharmony_ci 359e1051a39Sopenharmony_ci/* 360e1051a39Sopenharmony_ci * Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for 361e1051a39Sopenharmony_ci * each index in the class used by this variable 362e1051a39Sopenharmony_ci */ 363e1051a39Sopenharmony_civoid CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) 364e1051a39Sopenharmony_ci{ 365e1051a39Sopenharmony_ci int mx, i; 366e1051a39Sopenharmony_ci EX_CALLBACKS *ip; 367e1051a39Sopenharmony_ci void *ptr; 368e1051a39Sopenharmony_ci const EX_CALLBACK *f; 369e1051a39Sopenharmony_ci struct ex_callback_entry stack[10]; 370e1051a39Sopenharmony_ci struct ex_callback_entry *storage = NULL; 371e1051a39Sopenharmony_ci OSSL_EX_DATA_GLOBAL *global = ossl_lib_ctx_get_ex_data_global(ad->ctx); 372e1051a39Sopenharmony_ci 373e1051a39Sopenharmony_ci if (global == NULL) 374e1051a39Sopenharmony_ci goto err; 375e1051a39Sopenharmony_ci 376e1051a39Sopenharmony_ci ip = get_and_lock(global, class_index); 377e1051a39Sopenharmony_ci if (ip == NULL) 378e1051a39Sopenharmony_ci goto err; 379e1051a39Sopenharmony_ci 380e1051a39Sopenharmony_ci mx = sk_EX_CALLBACK_num(ip->meth); 381e1051a39Sopenharmony_ci if (mx > 0) { 382e1051a39Sopenharmony_ci if (mx < (int)OSSL_NELEM(stack)) 383e1051a39Sopenharmony_ci storage = stack; 384e1051a39Sopenharmony_ci else 385e1051a39Sopenharmony_ci storage = OPENSSL_malloc(sizeof(*storage) * mx); 386e1051a39Sopenharmony_ci if (storage != NULL) 387e1051a39Sopenharmony_ci for (i = 0; i < mx; i++) { 388e1051a39Sopenharmony_ci storage[i].excb = sk_EX_CALLBACK_value(ip->meth, i); 389e1051a39Sopenharmony_ci storage[i].index = i; 390e1051a39Sopenharmony_ci } 391e1051a39Sopenharmony_ci } 392e1051a39Sopenharmony_ci CRYPTO_THREAD_unlock(global->ex_data_lock); 393e1051a39Sopenharmony_ci 394e1051a39Sopenharmony_ci if (storage != NULL) { 395e1051a39Sopenharmony_ci /* Sort according to priority. High priority first */ 396e1051a39Sopenharmony_ci qsort(storage, mx, sizeof(*storage), ex_callback_compare); 397e1051a39Sopenharmony_ci for (i = 0; i < mx; i++) { 398e1051a39Sopenharmony_ci f = storage[i].excb; 399e1051a39Sopenharmony_ci 400e1051a39Sopenharmony_ci if (f != NULL && f->free_func != NULL) { 401e1051a39Sopenharmony_ci ptr = CRYPTO_get_ex_data(ad, storage[i].index); 402e1051a39Sopenharmony_ci f->free_func(obj, ptr, ad, storage[i].index, f->argl, f->argp); 403e1051a39Sopenharmony_ci } 404e1051a39Sopenharmony_ci } 405e1051a39Sopenharmony_ci } 406e1051a39Sopenharmony_ci 407e1051a39Sopenharmony_ci if (storage != stack) 408e1051a39Sopenharmony_ci OPENSSL_free(storage); 409e1051a39Sopenharmony_ci err: 410e1051a39Sopenharmony_ci sk_void_free(ad->sk); 411e1051a39Sopenharmony_ci ad->sk = NULL; 412e1051a39Sopenharmony_ci ad->ctx = NULL; 413e1051a39Sopenharmony_ci} 414e1051a39Sopenharmony_ci 415e1051a39Sopenharmony_ci/* 416e1051a39Sopenharmony_ci * Allocate a given CRYPTO_EX_DATA item using the class specific allocation 417e1051a39Sopenharmony_ci * function 418e1051a39Sopenharmony_ci */ 419e1051a39Sopenharmony_ciint CRYPTO_alloc_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad, 420e1051a39Sopenharmony_ci int idx) 421e1051a39Sopenharmony_ci{ 422e1051a39Sopenharmony_ci void *curval; 423e1051a39Sopenharmony_ci 424e1051a39Sopenharmony_ci curval = CRYPTO_get_ex_data(ad, idx); 425e1051a39Sopenharmony_ci /* Already there, no need to allocate */ 426e1051a39Sopenharmony_ci if (curval != NULL) 427e1051a39Sopenharmony_ci return 1; 428e1051a39Sopenharmony_ci 429e1051a39Sopenharmony_ci return ossl_crypto_alloc_ex_data_intern(class_index, obj, ad, idx); 430e1051a39Sopenharmony_ci} 431e1051a39Sopenharmony_ci 432e1051a39Sopenharmony_ciint ossl_crypto_alloc_ex_data_intern(int class_index, void *obj, 433e1051a39Sopenharmony_ci CRYPTO_EX_DATA *ad, int idx) 434e1051a39Sopenharmony_ci{ 435e1051a39Sopenharmony_ci EX_CALLBACK *f; 436e1051a39Sopenharmony_ci EX_CALLBACKS *ip; 437e1051a39Sopenharmony_ci OSSL_EX_DATA_GLOBAL *global; 438e1051a39Sopenharmony_ci 439e1051a39Sopenharmony_ci global = ossl_lib_ctx_get_ex_data_global(ad->ctx); 440e1051a39Sopenharmony_ci if (global == NULL) 441e1051a39Sopenharmony_ci return 0; 442e1051a39Sopenharmony_ci 443e1051a39Sopenharmony_ci ip = get_and_lock(global, class_index); 444e1051a39Sopenharmony_ci if (ip == NULL) 445e1051a39Sopenharmony_ci return 0; 446e1051a39Sopenharmony_ci f = sk_EX_CALLBACK_value(ip->meth, idx); 447e1051a39Sopenharmony_ci CRYPTO_THREAD_unlock(global->ex_data_lock); 448e1051a39Sopenharmony_ci 449e1051a39Sopenharmony_ci /* 450e1051a39Sopenharmony_ci * This should end up calling CRYPTO_set_ex_data(), which allocates 451e1051a39Sopenharmony_ci * everything necessary to support placing the new data in the right spot. 452e1051a39Sopenharmony_ci */ 453e1051a39Sopenharmony_ci if (f->new_func == NULL) 454e1051a39Sopenharmony_ci return 0; 455e1051a39Sopenharmony_ci 456e1051a39Sopenharmony_ci f->new_func(obj, NULL, ad, idx, f->argl, f->argp); 457e1051a39Sopenharmony_ci 458e1051a39Sopenharmony_ci return 1; 459e1051a39Sopenharmony_ci} 460e1051a39Sopenharmony_ci 461e1051a39Sopenharmony_ci/* 462e1051a39Sopenharmony_ci * For a given CRYPTO_EX_DATA variable, set the value corresponding to a 463e1051a39Sopenharmony_ci * particular index in the class used by this variable 464e1051a39Sopenharmony_ci */ 465e1051a39Sopenharmony_ciint CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val) 466e1051a39Sopenharmony_ci{ 467e1051a39Sopenharmony_ci int i; 468e1051a39Sopenharmony_ci 469e1051a39Sopenharmony_ci if (ad->sk == NULL) { 470e1051a39Sopenharmony_ci if ((ad->sk = sk_void_new_null()) == NULL) { 471e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); 472e1051a39Sopenharmony_ci return 0; 473e1051a39Sopenharmony_ci } 474e1051a39Sopenharmony_ci } 475e1051a39Sopenharmony_ci 476e1051a39Sopenharmony_ci for (i = sk_void_num(ad->sk); i <= idx; ++i) { 477e1051a39Sopenharmony_ci if (!sk_void_push(ad->sk, NULL)) { 478e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); 479e1051a39Sopenharmony_ci return 0; 480e1051a39Sopenharmony_ci } 481e1051a39Sopenharmony_ci } 482e1051a39Sopenharmony_ci if (sk_void_set(ad->sk, idx, val) != val) { 483e1051a39Sopenharmony_ci /* Probably the index is out of bounds */ 484e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 485e1051a39Sopenharmony_ci return 0; 486e1051a39Sopenharmony_ci } 487e1051a39Sopenharmony_ci return 1; 488e1051a39Sopenharmony_ci} 489e1051a39Sopenharmony_ci 490e1051a39Sopenharmony_ci/* 491e1051a39Sopenharmony_ci * For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a 492e1051a39Sopenharmony_ci * particular index in the class used by this variable 493e1051a39Sopenharmony_ci */ 494e1051a39Sopenharmony_civoid *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx) 495e1051a39Sopenharmony_ci{ 496e1051a39Sopenharmony_ci if (ad->sk == NULL || idx >= sk_void_num(ad->sk)) 497e1051a39Sopenharmony_ci return NULL; 498e1051a39Sopenharmony_ci return sk_void_value(ad->sk, idx); 499e1051a39Sopenharmony_ci} 500e1051a39Sopenharmony_ci 501e1051a39Sopenharmony_ciOSSL_LIB_CTX *ossl_crypto_ex_data_get_ossl_lib_ctx(const CRYPTO_EX_DATA *ad) 502e1051a39Sopenharmony_ci{ 503e1051a39Sopenharmony_ci return ad->ctx; 504e1051a39Sopenharmony_ci} 505