ex_data.c 14.8 KB
Newer Older
1 2 3 4 5 6
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
 * All rights reserved.
 *
 * This package is an SSL implementation written
 * by Eric Young (eay@cryptsoft.com).
 * The implementation was written so as to conform with Netscapes SSL.
7
 *
8 9 10 11 12 13
 * This library is free for commercial and non-commercial use as long as
 * the following conditions are aheared to.  The following conditions
 * apply to all code found in this distribution, be it the RC4, RSA,
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
 * included with this distribution is covered by the same copyright terms
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14
 *
15 16 17 18 19 20
 * Copyright remains Eric Young's, and as such any Copyright notices in
 * the code are not to be removed.
 * If this package is used in a product, Eric Young should be given attribution
 * as the author of the parts of the library used.
 * This can be in the form of a textual message at program startup or
 * in documentation (online or textual) provided with the package.
21
 *
22 23 24 25 26 27 28 29 30 31 32 33 34 35
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    "This product includes cryptographic software written by
 *     Eric Young (eay@cryptsoft.com)"
 *    The word 'cryptographic' can be left out if the rouines from the library
 *    being used are not cryptographic related :-).
36
 * 4. If you include any Windows specific code (or a derivative thereof) from
37 38
 *    the apps directory (application code) you must include an acknowledgement:
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39
 *
40 41 42 43 44 45 46 47 48 49 50
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
51
 *
52 53 54 55 56
 * The licence and distribution terms for any publically available version or
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
 * copied and put under another distribution licence
 * [including the GNU Public Licence.]
 */
B
Bodo Möller 已提交
57 58 59 60 61 62 63 64
/* ====================================================================
 * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
65
 *    notice, this list of conditions and the following disclaimer.
B
Bodo Möller 已提交
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
 *
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    openssl-core@openssl.org.
 *
 * 5. Products derived from this software may not be called "OpenSSL"
 *    nor may "OpenSSL" appear in their names without prior written
 *    permission of the OpenSSL Project.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 *
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 * This product includes cryptographic software written by Eric Young
 * (eay@cryptsoft.com).  This product includes software written by Tim
 * Hudson (tjh@cryptsoft.com).
 *
 */
110

111
#include "internal/cryptlib.h"
112
#include <openssl/lhash.h>
113

114

115 116 117 118 119 120

/*
 * Each structure type (sometimes called a class), that supports
 * exdata has a stack of callbacks for each instance.
 */
typedef struct ex_callback_st {
R
Rich Salz 已提交
121 122 123 124 125
    long argl;                  /* Arbitary long */
    void *argp;                 /* Arbitary void * */
    CRYPTO_EX_new *new_func;
    CRYPTO_EX_free *free_func;
    CRYPTO_EX_dup *dup_func;
126
} EX_CALLBACK;
127

128
DEFINE_STACK_OF(EX_CALLBACK)
129 130

/*
131 132
 * The state for each class.  This could just be a typedef, but
 * a structure allows future changes.
133
 */
134 135 136
typedef struct ex_callbacks_st {
    STACK_OF(EX_CALLBACK) *meth;
} EX_CALLBACKS;
137

138
static EX_CALLBACKS ex_data[CRYPTO_EX_INDEX__COUNT];
139

140
/*
141
 * Return the EX_CALLBACKS from the |ex_data| array that corresponds to
R
Rich Salz 已提交
142
 * a given class.  On success, *holds the lock.*
143
 */
144
static EX_CALLBACKS *get_and_lock(int class_index)
145
{
146
    EX_CALLBACKS *ip;
R
Rich Salz 已提交
147 148

    if (class_index < 0 || class_index >= CRYPTO_EX_INDEX__COUNT) {
149
        CRYPTOerr(CRYPTO_F_GET_AND_LOCK, ERR_R_MALLOC_FAILURE);
R
Rich Salz 已提交
150 151 152 153
        return NULL;
    }

    ip = &ex_data[class_index];
154
    CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
R
Rich Salz 已提交
155
    if (ip->meth == NULL) {
156
        ip->meth = sk_EX_CALLBACK_new_null();
R
Rich Salz 已提交
157 158 159
        /* We push an initial value on the stack because the SSL
         * "app_data" routines use ex_data index zero.  See RT 3710. */
        if (ip->meth == NULL
160 161
            || !sk_EX_CALLBACK_push(ip->meth, NULL)) {
            CRYPTOerr(CRYPTO_F_GET_AND_LOCK, ERR_R_MALLOC_FAILURE);
R
Rich Salz 已提交
162 163 164 165 166
            CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
            return NULL;
        }
    }
    return ip;
167 168
}

169
static void cleanup_cb(EX_CALLBACK *funcs)
170 171 172
{
    OPENSSL_free(funcs);
}
173

174
/*
R
Rich Salz 已提交
175 176 177 178
 * Release all "ex_data" state to prevent memory leaks. This can't be made
 * thread-safe without overhauling a lot of stuff, and shouldn't really be
 * called under potential race-conditions anyway (it's for program shutdown
 * after all).
179
 */
R
Rich Salz 已提交
180
void CRYPTO_cleanup_all_ex_data(void)
181
{
R
Rich Salz 已提交
182
    int i;
183

R
Rich Salz 已提交
184
    for (i = 0; i < CRYPTO_EX_INDEX__COUNT; ++i) {
185
        EX_CALLBACKS *ip = &ex_data[i];
R
Rich Salz 已提交
186

187
        sk_EX_CALLBACK_pop_free(ip->meth, cleanup_cb);
R
Rich Salz 已提交
188
        ip->meth = NULL;
189 190 191
    }
}

192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

/*
 * Unregister a new index by replacing the callbacks with no-ops.
 * Any in-use instances are leaked.
 */
static void dummy_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
                     long argl, void *argp)
{
}

static void dummy_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
                       long argl, void *argp)
{
}

static int dummy_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from,
                     void *from_d, int idx,
                     long argl, void *argp)
{
    return 0;
}

int CRYPTO_free_ex_index(int class_index, int idx)
{
    EX_CALLBACKS *ip = get_and_lock(class_index);
    EX_CALLBACK *a;
    int toret = 0;

    if (ip == NULL)
        return 0;
    if (idx < 0 || idx >= sk_EX_CALLBACK_num(ip->meth))
        goto err;
    a = sk_EX_CALLBACK_value(ip->meth, idx);
    if (a == NULL)
        goto err;
    a->new_func = dummy_new;
    a->dup_func = dummy_dup;
    a->free_func = dummy_free;
    toret = 1;
err:
    CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
    return toret;
}

236
/*
237
 * Register a new index.
238
 */
R
Rich Salz 已提交
239 240 241
int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
                            CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
                            CRYPTO_EX_free *free_func)
242 243
{
    int toret = -1;
244 245
    EX_CALLBACK *a;
    EX_CALLBACKS *ip = get_and_lock(class_index);
R
Rich Salz 已提交
246

247
    if (ip == NULL)
248
        return -1;
249
    a = (EX_CALLBACK *)OPENSSL_malloc(sizeof(*a));
250
    if (a == NULL) {
R
Rich Salz 已提交
251 252
        CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
        goto err;
253 254 255 256 257 258
    }
    a->argl = argl;
    a->argp = argp;
    a->new_func = new_func;
    a->dup_func = dup_func;
    a->free_func = free_func;
259

260
    if (!sk_EX_CALLBACK_push(ip->meth, NULL)) {
R
Rich Salz 已提交
261 262 263 264
        CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
        OPENSSL_free(a);
        goto err;
    }
265 266
    toret = sk_EX_CALLBACK_num(ip->meth) - 1;
    (void)sk_EX_CALLBACK_set(ip->meth, toret, a);
267

R
Rich Salz 已提交
268
 err:
269 270 271
    CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
    return toret;
}
272

273
/*
R
Rich Salz 已提交
274 275
 * Initialise a new CRYPTO_EX_DATA for use in a particular class - including
 * calling new() callbacks for each index in the class used by this variable
276
 * Thread-safe by copying a class's array of "EX_CALLBACK" entries
R
Rich Salz 已提交
277 278
 * in the lock, then using them outside the lock. Note this only applies
 * to the global "ex_data" state (ie. class definitions), not 'ad' itself.
279
 */
R
Rich Salz 已提交
280
int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
281 282 283
{
    int mx, i;
    void *ptr;
284 285 286
    EX_CALLBACK **storage = NULL;
    EX_CALLBACK *stack[10];
    EX_CALLBACKS *ip = get_and_lock(class_index);
R
Rich Salz 已提交
287

288
    if (ip == NULL)
289
        return 0;
R
Rich Salz 已提交
290

291
    ad->sk = NULL;
R
Rich Salz 已提交
292

293
    mx = sk_EX_CALLBACK_num(ip->meth);
294
    if (mx > 0) {
R
Rich Salz 已提交
295 296 297 298
        if (mx < (int)OSSL_NELEM(stack))
            storage = stack;
        else
            storage = OPENSSL_malloc(sizeof(*storage) * mx);
299
        if (storage != NULL)
R
Rich Salz 已提交
300
            for (i = 0; i < mx; i++)
301
                storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
302
    }
R
Rich Salz 已提交
303 304 305 306
    CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);

    if (mx > 0 && storage == NULL) {
        CRYPTOerr(CRYPTO_F_CRYPTO_NEW_EX_DATA, ERR_R_MALLOC_FAILURE);
307 308 309 310 311 312 313 314 315
        return 0;
    }
    for (i = 0; i < mx; i++) {
        if (storage[i] && storage[i]->new_func) {
            ptr = CRYPTO_get_ex_data(ad, i);
            storage[i]->new_func(obj, ptr, ad, i,
                                 storage[i]->argl, storage[i]->argp);
        }
    }
R
Rich Salz 已提交
316 317
    if (storage != stack)
        OPENSSL_free(storage);
318 319
    return 1;
}
320

R
Rich Salz 已提交
321 322 323 324 325 326
/*
 * Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks
 * for each index in the class used by this variable
 */
int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
                       CRYPTO_EX_DATA *from)
327 328 329
{
    int mx, j, i;
    char *ptr;
330 331 332
    EX_CALLBACK *stack[10];
    EX_CALLBACK **storage = NULL;
    EX_CALLBACKS *ip;
R
Rich Salz 已提交
333 334 335

    if (from->sk == NULL)
        /* Nothing to copy over */
336
        return 1;
337
    if ((ip = get_and_lock(class_index)) == NULL)
338
        return 0;
R
Rich Salz 已提交
339

340
    mx = sk_EX_CALLBACK_num(ip->meth);
341 342 343 344
    j = sk_void_num(from->sk);
    if (j < mx)
        mx = j;
    if (mx > 0) {
R
Rich Salz 已提交
345 346 347 348
        if (mx < (int)OSSL_NELEM(stack))
            storage = stack;
        else
            storage = OPENSSL_malloc(sizeof(*storage) * mx);
349
        if (storage != NULL)
R
Rich Salz 已提交
350
            for (i = 0; i < mx; i++)
351
                storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
352
    }
R
Rich Salz 已提交
353 354 355 356
    CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);

    if (mx > 0 && storage == NULL) {
        CRYPTOerr(CRYPTO_F_CRYPTO_DUP_EX_DATA, ERR_R_MALLOC_FAILURE);
357 358
        return 0;
    }
R
Rich Salz 已提交
359

360 361 362 363 364 365 366
    for (i = 0; i < mx; i++) {
        ptr = CRYPTO_get_ex_data(from, i);
        if (storage[i] && storage[i]->dup_func)
            storage[i]->dup_func(to, from, &ptr, i,
                                 storage[i]->argl, storage[i]->argp);
        CRYPTO_set_ex_data(to, i, ptr);
    }
R
Rich Salz 已提交
367 368
    if (storage != stack)
        OPENSSL_free(storage);
369 370
    return 1;
}
371

R
Rich Salz 已提交
372 373 374 375 376 377

/*
 * Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for
 * each index in the class used by this variable
 */
void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
378 379
{
    int mx, i;
380
    EX_CALLBACKS *ip;
381
    void *ptr;
382 383
    EX_CALLBACK *stack[10];
    EX_CALLBACK **storage = NULL;
R
Rich Salz 已提交
384

385
    if ((ip = get_and_lock(class_index)) == NULL)
386
        return;
R
Rich Salz 已提交
387

388
    mx = sk_EX_CALLBACK_num(ip->meth);
389
    if (mx > 0) {
R
Rich Salz 已提交
390 391 392 393
        if (mx < (int)OSSL_NELEM(stack))
            storage = stack;
        else
            storage = OPENSSL_malloc(sizeof(*storage) * mx);
394
        if (storage != NULL)
R
Rich Salz 已提交
395
            for (i = 0; i < mx; i++)
396
                storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
397
    }
R
Rich Salz 已提交
398 399 400 401
    CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);

    if (mx > 0 && storage == NULL) {
        CRYPTOerr(CRYPTO_F_CRYPTO_FREE_EX_DATA, ERR_R_MALLOC_FAILURE);
402 403 404 405 406 407 408 409 410
        return;
    }
    for (i = 0; i < mx; i++) {
        if (storage[i] && storage[i]->free_func) {
            ptr = CRYPTO_get_ex_data(ad, i);
            storage[i]->free_func(obj, ptr, ad, i,
                                  storage[i]->argl, storage[i]->argp);
        }
    }
R
Rich Salz 已提交
411 412 413

    if (storage != stack)
        OPENSSL_free(storage);
R
Rich Salz 已提交
414 415
    sk_void_free(ad->sk);
    ad->sk = NULL;
416
}
417

418 419 420 421
/*
 * For a given CRYPTO_EX_DATA variable, set the value corresponding to a
 * particular index in the class used by this variable
 */
D
 
Dr. Stephen Henson 已提交
422
int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val)
423 424 425 426 427 428
{
    int i;

    if (ad->sk == NULL) {
        if ((ad->sk = sk_void_new_null()) == NULL) {
            CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
R
Rich Salz 已提交
429
            return 0;
430 431 432
        }
    }

R
Rich Salz 已提交
433
    for (i = sk_void_num(ad->sk); i <= idx; ++i) {
434 435
        if (!sk_void_push(ad->sk, NULL)) {
            CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
R
Rich Salz 已提交
436
            return 0;
437 438 439
        }
    }
    sk_void_set(ad->sk, idx, val);
R
Rich Salz 已提交
440
    return 1;
441 442 443 444 445 446
}

/*
 * For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a
 * particular index in the class used by this variable
 */
447
void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx)
448
{
R
Rich Salz 已提交
449 450 451
    if (ad->sk == NULL || idx >= sk_void_num(ad->sk))
        return NULL;
    return sk_void_value(ad->sk, idx);
452
}