summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/ex_data.c
diff options
context:
space:
mode:
authorjsing <>2024-08-02 10:48:54 +0000
committerjsing <>2024-08-02 10:48:54 +0000
commitffa17714e966833766f8f0403ac8e178f26fbbed (patch)
tree8d588376ef1f79f315be375339e9c5ea6e59bd83 /src/lib/libcrypto/ex_data.c
parentea51d67aadf6bac6328d485fa936685da3bbba4f (diff)
downloadopenbsd-ffa17714e966833766f8f0403ac8e178f26fbbed.tar.gz
openbsd-ffa17714e966833766f8f0403ac8e178f26fbbed.tar.bz2
openbsd-ffa17714e966833766f8f0403ac8e178f26fbbed.zip
Rewrite CRYPTO_EX_DATA.
CRYPTO_EX_DATA exists as a way to allow an application to attach data to various components in libcrypto and libssl. The general idea is that there are various "classes" (e.g. RSA) and an application can get an "index" (which can have new/dup/free functions provided). The application can then use the index to store a pointer to some form of data within that class, for later retrieval. However, even by OpenSSL standards, this is an insane API. The current implementation allows for data to be set without calling new, indexes can be used without allocation, new can be called without actually getting an index and dup can be called either after new or without new (see regress and RSA_get_ex_new_index(3)/CRYPTO_set_ex_data(3) for more details). On top of this, the previous "overhaul" of the code was written to be infinitely extensible. For now, the rewrite intends to maintain the existing behaviour - once we bed this down we can attempt to ratchet the API requirements and require some sort of sensible sequence. The only intentional change is that there is now a hard limit on the number of indexes that can be allocated (previously there was none, relying only on ENOMEM). ok tb@
Diffstat (limited to 'src/lib/libcrypto/ex_data.c')
-rw-r--r--src/lib/libcrypto/ex_data.c637
1 files changed, 0 insertions, 637 deletions
diff --git a/src/lib/libcrypto/ex_data.c b/src/lib/libcrypto/ex_data.c
deleted file mode 100644
index 17db16e58d..0000000000
--- a/src/lib/libcrypto/ex_data.c
+++ /dev/null
@@ -1,637 +0,0 @@
1/* $OpenBSD: ex_data.c,v 1.23 2023/07/28 10:19:20 tb Exp $ */
2
3/*
4 * Overhaul notes;
5 *
6 * This code is now *mostly* thread-safe. It is now easier to understand in what
7 * ways it is safe and in what ways it is not, which is an improvement. Firstly,
8 * all per-class stacks and index-counters for ex_data are stored in the same
9 * global LHASH table (keyed by class). This hash table uses locking for all
10 * access with the exception of CRYPTO_cleanup_all_ex_data(), which must only be
11 * called when no other threads can possibly race against it (even if it was
12 * locked, the race would mean it's possible the hash table might have been
13 * recreated after the cleanup). As classes can only be added to the hash table,
14 * and within each class, the stack of methods can only be incremented, the
15 * locking mechanics are simpler than they would otherwise be. For example, the
16 * new/dup/free ex_data functions will lock the hash table, copy the method
17 * pointers it needs from the relevant class, then unlock the hash table before
18 * actually applying those method pointers to the task of the new/dup/free
19 * operations. As they can't be removed from the method-stack, only
20 * supplemented, there's no race conditions associated with using them outside
21 * the lock. The get/set_ex_data functions are not locked because they do not
22 * involve this global state at all - they operate directly with a previously
23 * obtained per-class method index and a particular "ex_data" variable. These
24 * variables are usually instantiated per-context (eg. each RSA structure has
25 * one) so locking on read/write access to that variable can be locked locally
26 * if required (eg. using the "RSA" lock to synchronise access to a
27 * per-RSA-structure ex_data variable if required).
28 * [Geoff]
29 */
30
31/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
32 * All rights reserved.
33 *
34 * This package is an SSL implementation written
35 * by Eric Young (eay@cryptsoft.com).
36 * The implementation was written so as to conform with Netscapes SSL.
37 *
38 * This library is free for commercial and non-commercial use as long as
39 * the following conditions are aheared to. The following conditions
40 * apply to all code found in this distribution, be it the RC4, RSA,
41 * lhash, DES, etc., code; not just the SSL code. The SSL documentation
42 * included with this distribution is covered by the same copyright terms
43 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
44 *
45 * Copyright remains Eric Young's, and as such any Copyright notices in
46 * the code are not to be removed.
47 * If this package is used in a product, Eric Young should be given attribution
48 * as the author of the parts of the library used.
49 * This can be in the form of a textual message at program startup or
50 * in documentation (online or textual) provided with the package.
51 *
52 * Redistribution and use in source and binary forms, with or without
53 * modification, are permitted provided that the following conditions
54 * are met:
55 * 1. Redistributions of source code must retain the copyright
56 * notice, this list of conditions and the following disclaimer.
57 * 2. Redistributions in binary form must reproduce the above copyright
58 * notice, this list of conditions and the following disclaimer in the
59 * documentation and/or other materials provided with the distribution.
60 * 3. All advertising materials mentioning features or use of this software
61 * must display the following acknowledgement:
62 * "This product includes cryptographic software written by
63 * Eric Young (eay@cryptsoft.com)"
64 * The word 'cryptographic' can be left out if the rouines from the library
65 * being used are not cryptographic related :-).
66 * 4. If you include any Windows specific code (or a derivative thereof) from
67 * the apps directory (application code) you must include an acknowledgement:
68 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
69 *
70 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
71 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
72 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
73 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
74 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
75 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
76 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
77 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
78 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
79 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
80 * SUCH DAMAGE.
81 *
82 * The licence and distribution terms for any publically available version or
83 * derivative of this code cannot be changed. i.e. this code cannot simply be
84 * copied and put under another distribution licence
85 * [including the GNU Public Licence.]
86 */
87/* ====================================================================
88 * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
89 *
90 * Redistribution and use in source and binary forms, with or without
91 * modification, are permitted provided that the following conditions
92 * are met:
93 *
94 * 1. Redistributions of source code must retain the above copyright
95 * notice, this list of conditions and the following disclaimer.
96 *
97 * 2. Redistributions in binary form must reproduce the above copyright
98 * notice, this list of conditions and the following disclaimer in
99 * the documentation and/or other materials provided with the
100 * distribution.
101 *
102 * 3. All advertising materials mentioning features or use of this
103 * software must display the following acknowledgment:
104 * "This product includes software developed by the OpenSSL Project
105 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
106 *
107 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
108 * endorse or promote products derived from this software without
109 * prior written permission. For written permission, please contact
110 * openssl-core@openssl.org.
111 *
112 * 5. Products derived from this software may not be called "OpenSSL"
113 * nor may "OpenSSL" appear in their names without prior written
114 * permission of the OpenSSL Project.
115 *
116 * 6. Redistributions of any form whatsoever must retain the following
117 * acknowledgment:
118 * "This product includes software developed by the OpenSSL Project
119 * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
120 *
121 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
122 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
123 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
124 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
125 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
126 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
127 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
128 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
129 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
130 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
131 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
132 * OF THE POSSIBILITY OF SUCH DAMAGE.
133 * ====================================================================
134 *
135 * This product includes cryptographic software written by Eric Young
136 * (eay@cryptsoft.com). This product includes software written by Tim
137 * Hudson (tjh@cryptsoft.com).
138 *
139 */
140
141#include <openssl/err.h>
142#include <openssl/lhash.h>
143
144typedef struct crypto_ex_data_func_st {
145 long argl; /* Arbitrary long */
146 void *argp; /* Arbitrary void * */
147 CRYPTO_EX_new *new_func;
148 CRYPTO_EX_free *free_func;
149 CRYPTO_EX_dup *dup_func;
150} CRYPTO_EX_DATA_FUNCS;
151
152DECLARE_STACK_OF(CRYPTO_EX_DATA_FUNCS)
153
154#define sk_CRYPTO_EX_DATA_FUNCS_new_null() SKM_sk_new_null(CRYPTO_EX_DATA_FUNCS)
155#define sk_CRYPTO_EX_DATA_FUNCS_num(st) SKM_sk_num(CRYPTO_EX_DATA_FUNCS, (st))
156#define sk_CRYPTO_EX_DATA_FUNCS_value(st, i) SKM_sk_value(CRYPTO_EX_DATA_FUNCS, (st), (i))
157#define sk_CRYPTO_EX_DATA_FUNCS_set(st, i, val) SKM_sk_set(CRYPTO_EX_DATA_FUNCS, (st), (i), (val))
158#define sk_CRYPTO_EX_DATA_FUNCS_push(st, val) SKM_sk_push(CRYPTO_EX_DATA_FUNCS, (st), (val))
159#define sk_CRYPTO_EX_DATA_FUNCS_pop_free(st, free_func) SKM_sk_pop_free(CRYPTO_EX_DATA_FUNCS, (st), (free_func))
160
161/* An opaque type representing an implementation of "ex_data" support */
162typedef struct st_CRYPTO_EX_DATA_IMPL CRYPTO_EX_DATA_IMPL;
163
164/* What an "implementation of ex_data functionality" looks like */
165struct st_CRYPTO_EX_DATA_IMPL {
166 /*********************/
167 /* GLOBAL OPERATIONS */
168 /* Return a new class index */
169 int (*cb_new_class)(void);
170 /* Cleanup all state used by the implementation */
171 void (*cb_cleanup)(void);
172 /************************/
173 /* PER-CLASS OPERATIONS */
174 /* Get a new method index within a class */
175 int (*cb_get_new_index)(int class_index, long argl, void *argp,
176 CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
177 CRYPTO_EX_free *free_func);
178 /* Initialise a new CRYPTO_EX_DATA of a given class */
179 int (*cb_new_ex_data)(int class_index, void *obj,
180 CRYPTO_EX_DATA *ad);
181 /* Duplicate a CRYPTO_EX_DATA of a given class onto a copy */
182 int (*cb_dup_ex_data)(int class_index, CRYPTO_EX_DATA *to,
183 CRYPTO_EX_DATA *from);
184 /* Cleanup a CRYPTO_EX_DATA of a given class */
185 void (*cb_free_ex_data)(int class_index, void *obj,
186 CRYPTO_EX_DATA *ad);
187};
188
189/* The implementation we use at run-time */
190static const CRYPTO_EX_DATA_IMPL *impl = NULL;
191
192/* To call "impl" functions, use this macro rather than referring to 'impl' directly, eg.
193 * EX_IMPL(get_new_index)(...);
194*/
195#define EX_IMPL(a) impl->cb_##a
196
197/* Predeclare the "default" ex_data implementation */
198static int int_new_class(void);
199static void int_cleanup(void);
200static int int_get_new_index(int class_index, long argl, void *argp,
201 CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
202 CRYPTO_EX_free *free_func);
203static int int_new_ex_data(int class_index, void *obj,
204 CRYPTO_EX_DATA *ad);
205static int int_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
206 CRYPTO_EX_DATA *from);
207static void int_free_ex_data(int class_index, void *obj,
208 CRYPTO_EX_DATA *ad);
209
210static CRYPTO_EX_DATA_IMPL impl_default = {
211 int_new_class,
212 int_cleanup,
213 int_get_new_index,
214 int_new_ex_data,
215 int_dup_ex_data,
216 int_free_ex_data
217};
218
219/* Internal function that checks whether "impl" is set and if not, sets it to
220 * the default. */
221static void
222impl_check(void)
223{
224 CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
225 if (!impl)
226 impl = &impl_default;
227 CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
228}
229/* A macro wrapper for impl_check that first uses a non-locked test before
230 * invoking the function (which checks again inside a lock). */
231#define IMPL_CHECK if(!impl) impl_check();
232
233/****************************************************************************/
234/* Interal (default) implementation of "ex_data" support. API functions are
235 * further down. */
236
237/* The type that represents what each "class" used to implement locally. A STACK
238 * of CRYPTO_EX_DATA_FUNCS plus a index-counter. The 'class_index' is the global
239 * value representing the class that is used to distinguish these items. */
240typedef struct st_ex_class_item {
241 int class_index;
242 STACK_OF(CRYPTO_EX_DATA_FUNCS) *meth;
243 int meth_num;
244} EX_CLASS_ITEM;
245
246/* When assigning new class indexes, this is our counter */
247#define CRYPTO_EX_INDEX_USER 100
248static int ex_class = CRYPTO_EX_INDEX_USER;
249
250/* The global hash table of EX_CLASS_ITEM items */
251DECLARE_LHASH_OF(EX_CLASS_ITEM);
252static LHASH_OF(EX_CLASS_ITEM) *ex_data = NULL;
253
254/* The callbacks required in the "ex_data" hash table */
255static unsigned long
256ex_class_item_hash(const EX_CLASS_ITEM *a)
257{
258 return a->class_index;
259}
260
261static IMPLEMENT_LHASH_HASH_FN(ex_class_item, EX_CLASS_ITEM)
262
263static int
264ex_class_item_cmp(const EX_CLASS_ITEM *a, const EX_CLASS_ITEM *b)
265{
266 return a->class_index - b->class_index;
267}
268
269static IMPLEMENT_LHASH_COMP_FN(ex_class_item, EX_CLASS_ITEM)
270
271/* Internal functions used by the "impl_default" implementation to access the
272 * state */
273
274static int
275ex_data_check(void)
276{
277 int toret = 1;
278 CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
279 if (!ex_data &&
280 (ex_data = lh_EX_CLASS_ITEM_new()) == NULL)
281 toret = 0;
282 CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
283 return toret;
284}
285/* This macros helps reduce the locking from repeated checks because the
286 * ex_data_check() function checks ex_data again inside a lock. */
287#define EX_DATA_CHECK(iffail) if(!ex_data && !ex_data_check()) {iffail}
288
289/* This "inner" callback is used by the callback function that follows it */
290static void
291def_cleanup_util_cb(CRYPTO_EX_DATA_FUNCS *funcs)
292{
293 free(funcs);
294}
295
296/* This callback is used in lh_doall to destroy all EX_CLASS_ITEM values from
297 * "ex_data" prior to the ex_data hash table being itself destroyed. Doesn't do
298 * any locking. */
299static void
300def_cleanup_cb(void *a_void)
301{
302 EX_CLASS_ITEM *item = (EX_CLASS_ITEM *)a_void;
303 sk_CRYPTO_EX_DATA_FUNCS_pop_free(item->meth, def_cleanup_util_cb);
304 free(item);
305}
306
307/* Return the EX_CLASS_ITEM from the "ex_data" hash table that corresponds to a
308 * given class. Handles locking. */
309static EX_CLASS_ITEM *
310def_get_class(int class_index)
311{
312 EX_CLASS_ITEM d, *p, *gen;
313 EX_DATA_CHECK(return NULL;)
314 d.class_index = class_index;
315 if (!OPENSSL_init_crypto(0, NULL))
316 return NULL;
317 CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
318 p = lh_EX_CLASS_ITEM_retrieve(ex_data, &d);
319 if (!p) {
320 gen = malloc(sizeof(EX_CLASS_ITEM));
321 if (gen) {
322 gen->class_index = class_index;
323 gen->meth_num = 1;
324 gen->meth = sk_CRYPTO_EX_DATA_FUNCS_new_null();
325 if (!gen->meth)
326 free(gen);
327 else {
328 /* Because we're inside the ex_data lock, the
329 * return value from the insert will be NULL */
330 (void)lh_EX_CLASS_ITEM_insert(ex_data, gen);
331 p = gen;
332 }
333 }
334 }
335 CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
336 if (!p)
337 CRYPTOerror(ERR_R_MALLOC_FAILURE);
338 return p;
339}
340
341/* Add a new method to the given EX_CLASS_ITEM and return the corresponding
342 * index (or -1 for error). Handles locking. */
343static int
344def_add_index(EX_CLASS_ITEM *item, long argl, void *argp,
345 CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
346{
347 int toret = -1;
348 CRYPTO_EX_DATA_FUNCS *a = malloc(sizeof(CRYPTO_EX_DATA_FUNCS));
349
350 if (!a) {
351 CRYPTOerror(ERR_R_MALLOC_FAILURE);
352 return -1;
353 }
354 a->argl = argl;
355 a->argp = argp;
356 a->new_func = new_func;
357 a->dup_func = dup_func;
358 a->free_func = free_func;
359 CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
360 while (sk_CRYPTO_EX_DATA_FUNCS_num(item->meth) <= item->meth_num) {
361 if (!sk_CRYPTO_EX_DATA_FUNCS_push(item->meth, NULL)) {
362 CRYPTOerror(ERR_R_MALLOC_FAILURE);
363 free(a);
364 goto err;
365 }
366 }
367 toret = item->meth_num++;
368 (void)sk_CRYPTO_EX_DATA_FUNCS_set(item->meth, toret, a);
369err:
370 CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
371 return toret;
372}
373
374/**************************************************************/
375/* The functions in the default CRYPTO_EX_DATA_IMPL structure */
376
377static int
378int_new_class(void)
379{
380 int toret;
381
382 CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
383 toret = ex_class++;
384 CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
385 return toret;
386}
387
388static void
389int_cleanup(void)
390{
391 EX_DATA_CHECK(return;)
392 lh_EX_CLASS_ITEM_doall(ex_data, def_cleanup_cb);
393 lh_EX_CLASS_ITEM_free(ex_data);
394 ex_data = NULL;
395 impl = NULL;
396}
397
398static int
399int_get_new_index(int class_index, long argl, void *argp,
400 CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
401 CRYPTO_EX_free *free_func)
402{
403 EX_CLASS_ITEM *item = def_get_class(class_index);
404
405 if (!item)
406 return -1;
407 return def_add_index(item, argl, argp, new_func, dup_func, free_func);
408}
409
410/* Thread-safe by copying a class's array of "CRYPTO_EX_DATA_FUNCS" entries in
411 * the lock, then using them outside the lock. NB: Thread-safety only applies to
412 * the global "ex_data" state (ie. class definitions), not thread-safe on 'ad'
413 * itself. */
414static int
415int_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
416{
417 int mx, i;
418 void *ptr;
419 CRYPTO_EX_DATA_FUNCS **storage = NULL;
420 EX_CLASS_ITEM *item = def_get_class(class_index);
421
422 if (!item)
423 /* error is already set */
424 return 0;
425 ad->sk = NULL;
426 CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
427 mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth);
428 if (mx > 0) {
429 storage = reallocarray(NULL, mx, sizeof(CRYPTO_EX_DATA_FUNCS*));
430 if (!storage)
431 goto skip;
432 for (i = 0; i < mx; i++)
433 storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(
434 item->meth, i);
435 }
436skip:
437 CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);
438 if ((mx > 0) && !storage) {
439 CRYPTOerror(ERR_R_MALLOC_FAILURE);
440 return 0;
441 }
442 for (i = 0; i < mx; i++) {
443 if (storage[i] && storage[i]->new_func) {
444 ptr = CRYPTO_get_ex_data(ad, i);
445 storage[i]->new_func(obj, ptr, ad, i,
446 storage[i]->argl, storage[i]->argp);
447 }
448 }
449 free(storage);
450 return 1;
451}
452
453/* Same thread-safety notes as for "int_new_ex_data" */
454static int
455int_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from)
456{
457 int mx, j, i;
458 char *ptr;
459 CRYPTO_EX_DATA_FUNCS **storage = NULL;
460 EX_CLASS_ITEM *item;
461
462 if (!from->sk)
463 /* 'to' should be "blank" which *is* just like 'from' */
464 return 1;
465 if ((item = def_get_class(class_index)) == NULL)
466 return 0;
467 CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
468 mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth);
469 j = sk_void_num(from->sk);
470 if (j < mx)
471 mx = j;
472 if (mx > 0) {
473 storage = reallocarray(NULL, mx, sizeof(CRYPTO_EX_DATA_FUNCS*));
474 if (!storage)
475 goto skip;
476 for (i = 0; i < mx; i++)
477 storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(
478 item->meth, i);
479 }
480skip:
481 CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);
482 if ((mx > 0) && !storage) {
483 CRYPTOerror(ERR_R_MALLOC_FAILURE);
484 return 0;
485 }
486 for (i = 0; i < mx; i++) {
487 ptr = CRYPTO_get_ex_data(from, i);
488 if (storage[i] && storage[i]->dup_func)
489 storage[i]->dup_func(to, from, &ptr, i,
490 storage[i]->argl, storage[i]->argp);
491 CRYPTO_set_ex_data(to, i, ptr);
492 }
493 free(storage);
494 return 1;
495}
496
497/* Same thread-safety notes as for "int_new_ex_data" */
498static void
499int_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
500{
501 int mx, i;
502 EX_CLASS_ITEM *item;
503 void *ptr;
504 CRYPTO_EX_DATA_FUNCS **storage = NULL;
505
506 if ((item = def_get_class(class_index)) == NULL)
507 return;
508 CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
509 mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth);
510 if (mx > 0) {
511 storage = reallocarray(NULL, mx, sizeof(CRYPTO_EX_DATA_FUNCS*));
512 if (!storage)
513 goto skip;
514 for (i = 0; i < mx; i++)
515 storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(
516 item->meth, i);
517 }
518skip:
519 CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);
520 if ((mx > 0) && !storage) {
521 CRYPTOerror(ERR_R_MALLOC_FAILURE);
522 return;
523 }
524 for (i = 0; i < mx; i++) {
525 if (storage[i] && storage[i]->free_func) {
526 ptr = CRYPTO_get_ex_data(ad, i);
527 storage[i]->free_func(obj, ptr, ad, i,
528 storage[i]->argl, storage[i]->argp);
529 }
530 }
531 free(storage);
532 if (ad->sk) {
533 sk_void_free(ad->sk);
534 ad->sk = NULL;
535 }
536}
537
538/********************************************************************/
539/* API functions that defer all "state" operations to the "ex_data"
540 * implementation we have set. */
541
542/* Release all "ex_data" state to prevent memory leaks. This can't be made
543 * thread-safe without overhauling a lot of stuff, and shouldn't really be
544 * called under potential race-conditions anyway (it's for program shutdown
545 * after all). */
546void
547CRYPTO_cleanup_all_ex_data(void)
548{
549 IMPL_CHECK
550 EX_IMPL(cleanup)();
551}
552LCRYPTO_ALIAS(CRYPTO_cleanup_all_ex_data);
553
554/* Inside an existing class, get/register a new index. */
555int
556CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
557 CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
558{
559 int ret = -1;
560
561 IMPL_CHECK
562 ret = EX_IMPL(get_new_index)(class_index,
563 argl, argp, new_func, dup_func, free_func);
564 return ret;
565}
566LCRYPTO_ALIAS(CRYPTO_get_ex_new_index);
567
568/* Initialise a new CRYPTO_EX_DATA for use in a particular class - including
569 * calling new() callbacks for each index in the class used by this variable */
570int
571CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
572{
573 IMPL_CHECK
574 return EX_IMPL(new_ex_data)(class_index, obj, ad);
575}
576LCRYPTO_ALIAS(CRYPTO_new_ex_data);
577
578/* Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks for
579 * each index in the class used by this variable */
580int
581CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from)
582{
583 IMPL_CHECK
584 return EX_IMPL(dup_ex_data)(class_index, to, from);
585}
586LCRYPTO_ALIAS(CRYPTO_dup_ex_data);
587
588/* Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for
589 * each index in the class used by this variable */
590void
591CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
592{
593 IMPL_CHECK
594 EX_IMPL(free_ex_data)(class_index, obj, ad);
595}
596LCRYPTO_ALIAS(CRYPTO_free_ex_data);
597
598/* For a given CRYPTO_EX_DATA variable, set the value corresponding to a
599 * particular index in the class used by this variable */
600int
601CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val)
602{
603 int i;
604
605 if (ad->sk == NULL) {
606 if ((ad->sk = sk_void_new_null()) == NULL) {
607 CRYPTOerror(ERR_R_MALLOC_FAILURE);
608 return (0);
609 }
610 }
611 i = sk_void_num(ad->sk);
612
613 while (i <= idx) {
614 if (!sk_void_push(ad->sk, NULL)) {
615 CRYPTOerror(ERR_R_MALLOC_FAILURE);
616 return (0);
617 }
618 i++;
619 }
620 sk_void_set(ad->sk, idx, val);
621 return (1);
622}
623LCRYPTO_ALIAS(CRYPTO_set_ex_data);
624
625/* For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a
626 * particular index in the class used by this variable */
627void *
628CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx)
629{
630 if (ad->sk == NULL)
631 return (0);
632 else if (idx >= sk_void_num(ad->sk))
633 return (0);
634 else
635 return (sk_void_value(ad->sk, idx));
636}
637LCRYPTO_ALIAS(CRYPTO_get_ex_data);