]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/ex_data.c
various spelling fixes
[thirdparty/openssl.git] / crypto / ex_data.c
1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2 * All rights reserved.
3 *
4 * This package is an SSL implementation written
5 * by Eric Young (eay@cryptsoft.com).
6 * The implementation was written so as to conform with Netscapes SSL.
7 *
8 * This library is free for commercial and non-commercial use as long as
9 * the following conditions are aheared to. The following conditions
10 * apply to all code found in this distribution, be it the RC4, RSA,
11 * lhash, DES, etc., code; not just the SSL code. The SSL documentation
12 * included with this distribution is covered by the same copyright terms
13 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14 *
15 * Copyright remains Eric Young's, and as such any Copyright notices in
16 * the code are not to be removed.
17 * If this package is used in a product, Eric Young should be given attribution
18 * as the author of the parts of the library used.
19 * This can be in the form of a textual message at program startup or
20 * in documentation (online or textual) provided with the package.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 * 3. All advertising materials mentioning features or use of this software
31 * must display the following acknowledgement:
32 * "This product includes cryptographic software written by
33 * Eric Young (eay@cryptsoft.com)"
34 * The word 'cryptographic' can be left out if the rouines from the library
35 * being used are not cryptographic related :-).
36 * 4. If you include any Windows specific code (or a derivative thereof) from
37 * the apps directory (application code) you must include an acknowledgement:
38 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 *
52 * The licence and distribution terms for any publically available version or
53 * derivative of this code cannot be changed. i.e. this code cannot simply be
54 * copied and put under another distribution licence
55 * [including the GNU Public Licence.]
56 */
57 /* ====================================================================
58 * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
59 *
60 * Redistribution and use in source and binary forms, with or without
61 * modification, are permitted provided that the following conditions
62 * are met:
63 *
64 * 1. Redistributions of source code must retain the above copyright
65 * notice, this list of conditions and the following disclaimer.
66 *
67 * 2. Redistributions in binary form must reproduce the above copyright
68 * notice, this list of conditions and the following disclaimer in
69 * the documentation and/or other materials provided with the
70 * distribution.
71 *
72 * 3. All advertising materials mentioning features or use of this
73 * software must display the following acknowledgment:
74 * "This product includes software developed by the OpenSSL Project
75 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
76 *
77 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
78 * endorse or promote products derived from this software without
79 * prior written permission. For written permission, please contact
80 * openssl-core@openssl.org.
81 *
82 * 5. Products derived from this software may not be called "OpenSSL"
83 * nor may "OpenSSL" appear in their names without prior written
84 * permission of the OpenSSL Project.
85 *
86 * 6. Redistributions of any form whatsoever must retain the following
87 * acknowledgment:
88 * "This product includes software developed by the OpenSSL Project
89 * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
90 *
91 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
92 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
93 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
94 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
95 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
96 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
97 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
98 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
99 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
100 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
101 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
102 * OF THE POSSIBILITY OF SUCH DAMAGE.
103 * ====================================================================
104 *
105 * This product includes cryptographic software written by Eric Young
106 * (eay@cryptsoft.com). This product includes software written by Tim
107 * Hudson (tjh@cryptsoft.com).
108 *
109 */
110
111 #include "internal/cryptlib_int.h"
112 #include "internal/threads.h"
113 #include <openssl/lhash.h>
114
115 /*
116 * Each structure type (sometimes called a class), that supports
117 * exdata has a stack of callbacks for each instance.
118 */
119 struct ex_callback_st {
120 long argl; /* Arbitrary long */
121 void *argp; /* Arbitrary void * */
122 CRYPTO_EX_new *new_func;
123 CRYPTO_EX_free *free_func;
124 CRYPTO_EX_dup *dup_func;
125 };
126
127 /*
128 * The state for each class. This could just be a typedef, but
129 * a structure allows future changes.
130 */
131 typedef struct ex_callbacks_st {
132 STACK_OF(EX_CALLBACK) *meth;
133 } EX_CALLBACKS;
134
135 static EX_CALLBACKS ex_data[CRYPTO_EX_INDEX__COUNT];
136
137 static CRYPTO_RWLOCK *ex_data_lock = NULL;
138 static CRYPTO_ONCE ex_data_init = CRYPTO_ONCE_STATIC_INIT;
139
140 static void do_ex_data_init(void)
141 {
142 ex_data_lock = CRYPTO_THREAD_lock_new();
143 }
144
145 /*
146 * Return the EX_CALLBACKS from the |ex_data| array that corresponds to
147 * a given class. On success, *holds the lock.*
148 */
149 static EX_CALLBACKS *get_and_lock(int class_index)
150 {
151 EX_CALLBACKS *ip;
152
153 if (class_index < 0 || class_index >= CRYPTO_EX_INDEX__COUNT) {
154 CRYPTOerr(CRYPTO_F_GET_AND_LOCK, ERR_R_PASSED_INVALID_ARGUMENT);
155 return NULL;
156 }
157
158 CRYPTO_THREAD_run_once(&ex_data_init, do_ex_data_init);
159
160 if (ex_data_lock == NULL) {
161 /*
162 * This can happen in normal operation when using CRYPTO_mem_leaks().
163 * The CRYPTO_mem_leaks() function calls OPENSSL_cleanup() which cleans
164 * up the locks. Subsequently the BIO that CRYPTO_mem_leaks() uses gets
165 * freed, which also attempts to free the ex_data. However
166 * CRYPTO_mem_leaks() ensures that the ex_data is freed early (i.e.
167 * before OPENSSL_cleanup() is called), so if we get here we can safely
168 * ignore this operation. We just treat it as an error.
169 */
170 return NULL;
171 }
172
173 ip = &ex_data[class_index];
174 CRYPTO_THREAD_write_lock(ex_data_lock);
175 return ip;
176 }
177
178 static void cleanup_cb(EX_CALLBACK *funcs)
179 {
180 OPENSSL_free(funcs);
181 }
182
183 /*
184 * Release all "ex_data" state to prevent memory leaks. This can't be made
185 * thread-safe without overhauling a lot of stuff, and shouldn't really be
186 * called under potential race-conditions anyway (it's for program shutdown
187 * after all).
188 */
189 void crypto_cleanup_all_ex_data_int(void)
190 {
191 int i;
192
193 for (i = 0; i < CRYPTO_EX_INDEX__COUNT; ++i) {
194 EX_CALLBACKS *ip = &ex_data[i];
195
196 sk_EX_CALLBACK_pop_free(ip->meth, cleanup_cb);
197 ip->meth = NULL;
198 }
199
200 CRYPTO_THREAD_lock_free(ex_data_lock);
201 ex_data_lock = NULL;
202 }
203
204
205 /*
206 * Unregister a new index by replacing the callbacks with no-ops.
207 * Any in-use instances are leaked.
208 */
209 static void dummy_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
210 long argl, void *argp)
211 {
212 }
213
214 static void dummy_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
215 long argl, void *argp)
216 {
217 }
218
219 static int dummy_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from,
220 void *from_d, int idx,
221 long argl, void *argp)
222 {
223 return 0;
224 }
225
226 int CRYPTO_free_ex_index(int class_index, int idx)
227 {
228 EX_CALLBACKS *ip = get_and_lock(class_index);
229 EX_CALLBACK *a;
230 int toret = 0;
231
232 if (ip == NULL)
233 return 0;
234 if (idx < 0 || idx >= sk_EX_CALLBACK_num(ip->meth))
235 goto err;
236 a = sk_EX_CALLBACK_value(ip->meth, idx);
237 if (a == NULL)
238 goto err;
239 a->new_func = dummy_new;
240 a->dup_func = dummy_dup;
241 a->free_func = dummy_free;
242 toret = 1;
243 err:
244 CRYPTO_THREAD_unlock(ex_data_lock);
245 return toret;
246 }
247
248 /*
249 * Register a new index.
250 */
251 int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
252 CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
253 CRYPTO_EX_free *free_func)
254 {
255 int toret = -1;
256 EX_CALLBACK *a;
257 EX_CALLBACKS *ip = get_and_lock(class_index);
258
259 if (ip == NULL)
260 return -1;
261
262 if (ip->meth == NULL) {
263 ip->meth = sk_EX_CALLBACK_new_null();
264 /* We push an initial value on the stack because the SSL
265 * "app_data" routines use ex_data index zero. See RT 3710. */
266 if (ip->meth == NULL
267 || !sk_EX_CALLBACK_push(ip->meth, NULL)) {
268 CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
269 goto err;
270 }
271 }
272
273 a = (EX_CALLBACK *)OPENSSL_malloc(sizeof(*a));
274 if (a == NULL) {
275 CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
276 goto err;
277 }
278 a->argl = argl;
279 a->argp = argp;
280 a->new_func = new_func;
281 a->dup_func = dup_func;
282 a->free_func = free_func;
283
284 if (!sk_EX_CALLBACK_push(ip->meth, NULL)) {
285 CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
286 OPENSSL_free(a);
287 goto err;
288 }
289 toret = sk_EX_CALLBACK_num(ip->meth) - 1;
290 (void)sk_EX_CALLBACK_set(ip->meth, toret, a);
291
292 err:
293 CRYPTO_THREAD_unlock(ex_data_lock);
294 return toret;
295 }
296
297 /*
298 * Initialise a new CRYPTO_EX_DATA for use in a particular class - including
299 * calling new() callbacks for each index in the class used by this variable
300 * Thread-safe by copying a class's array of "EX_CALLBACK" entries
301 * in the lock, then using them outside the lock. Note this only applies
302 * to the global "ex_data" state (ie. class definitions), not 'ad' itself.
303 */
304 int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
305 {
306 int mx, i;
307 void *ptr;
308 EX_CALLBACK **storage = NULL;
309 EX_CALLBACK *stack[10];
310 EX_CALLBACKS *ip = get_and_lock(class_index);
311
312 if (ip == NULL)
313 return 0;
314
315 ad->sk = NULL;
316
317 mx = sk_EX_CALLBACK_num(ip->meth);
318 if (mx > 0) {
319 if (mx < (int)OSSL_NELEM(stack))
320 storage = stack;
321 else
322 storage = OPENSSL_malloc(sizeof(*storage) * mx);
323 if (storage != NULL)
324 for (i = 0; i < mx; i++)
325 storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
326 }
327 CRYPTO_THREAD_unlock(ex_data_lock);
328
329 if (mx > 0 && storage == NULL) {
330 CRYPTOerr(CRYPTO_F_CRYPTO_NEW_EX_DATA, ERR_R_MALLOC_FAILURE);
331 return 0;
332 }
333 for (i = 0; i < mx; i++) {
334 if (storage[i] && storage[i]->new_func) {
335 ptr = CRYPTO_get_ex_data(ad, i);
336 storage[i]->new_func(obj, ptr, ad, i,
337 storage[i]->argl, storage[i]->argp);
338 }
339 }
340 if (storage != stack)
341 OPENSSL_free(storage);
342 return 1;
343 }
344
345 /*
346 * Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks
347 * for each index in the class used by this variable
348 */
349 int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
350 CRYPTO_EX_DATA *from)
351 {
352 int mx, j, i;
353 char *ptr;
354 EX_CALLBACK *stack[10];
355 EX_CALLBACK **storage = NULL;
356 EX_CALLBACKS *ip;
357
358 if (from->sk == NULL)
359 /* Nothing to copy over */
360 return 1;
361 if ((ip = get_and_lock(class_index)) == NULL)
362 return 0;
363
364 mx = sk_EX_CALLBACK_num(ip->meth);
365 j = sk_void_num(from->sk);
366 if (j < mx)
367 mx = j;
368 if (mx > 0) {
369 if (mx < (int)OSSL_NELEM(stack))
370 storage = stack;
371 else
372 storage = OPENSSL_malloc(sizeof(*storage) * mx);
373 if (storage != NULL)
374 for (i = 0; i < mx; i++)
375 storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
376 }
377 CRYPTO_THREAD_unlock(ex_data_lock);
378
379 if (mx > 0 && storage == NULL) {
380 CRYPTOerr(CRYPTO_F_CRYPTO_DUP_EX_DATA, ERR_R_MALLOC_FAILURE);
381 return 0;
382 }
383
384 for (i = 0; i < mx; i++) {
385 ptr = CRYPTO_get_ex_data(from, i);
386 if (storage[i] && storage[i]->dup_func)
387 storage[i]->dup_func(to, from, &ptr, i,
388 storage[i]->argl, storage[i]->argp);
389 CRYPTO_set_ex_data(to, i, ptr);
390 }
391 if (storage != stack)
392 OPENSSL_free(storage);
393 return 1;
394 }
395
396
397 /*
398 * Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for
399 * each index in the class used by this variable
400 */
401 void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
402 {
403 int mx, i;
404 EX_CALLBACKS *ip;
405 void *ptr;
406 EX_CALLBACK *stack[10];
407 EX_CALLBACK **storage = NULL;
408
409 if ((ip = get_and_lock(class_index)) == NULL)
410 return;
411
412 mx = sk_EX_CALLBACK_num(ip->meth);
413 if (mx > 0) {
414 if (mx < (int)OSSL_NELEM(stack))
415 storage = stack;
416 else
417 storage = OPENSSL_malloc(sizeof(*storage) * mx);
418 if (storage != NULL)
419 for (i = 0; i < mx; i++)
420 storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
421 }
422 CRYPTO_THREAD_unlock(ex_data_lock);
423
424 if (mx > 0 && storage == NULL) {
425 CRYPTOerr(CRYPTO_F_CRYPTO_FREE_EX_DATA, ERR_R_MALLOC_FAILURE);
426 return;
427 }
428 for (i = 0; i < mx; i++) {
429 if (storage[i] && storage[i]->free_func) {
430 ptr = CRYPTO_get_ex_data(ad, i);
431 storage[i]->free_func(obj, ptr, ad, i,
432 storage[i]->argl, storage[i]->argp);
433 }
434 }
435
436 if (storage != stack)
437 OPENSSL_free(storage);
438 sk_void_free(ad->sk);
439 ad->sk = NULL;
440 }
441
442 /*
443 * For a given CRYPTO_EX_DATA variable, set the value corresponding to a
444 * particular index in the class used by this variable
445 */
446 int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val)
447 {
448 int i;
449
450 if (ad->sk == NULL) {
451 if ((ad->sk = sk_void_new_null()) == NULL) {
452 CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
453 return 0;
454 }
455 }
456
457 for (i = sk_void_num(ad->sk); i <= idx; ++i) {
458 if (!sk_void_push(ad->sk, NULL)) {
459 CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
460 return 0;
461 }
462 }
463 sk_void_set(ad->sk, idx, val);
464 return 1;
465 }
466
467 /*
468 * For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a
469 * particular index in the class used by this variable
470 */
471 void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx)
472 {
473 if (ad->sk == NULL || idx >= sk_void_num(ad->sk))
474 return NULL;
475 return sk_void_value(ad->sk, idx);
476 }