/*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include "internal/cryptlib_int.h"
-#include <openssl/lhash.h>
+#include "internal/thread_once.h"
/*
* Each structure type (sometimes called a class), that supports
static CRYPTO_RWLOCK *ex_data_lock = NULL;
static CRYPTO_ONCE ex_data_init = CRYPTO_ONCE_STATIC_INIT;
-static void do_ex_data_init(void)
+DEFINE_RUN_ONCE_STATIC(do_ex_data_init)
{
+ if (!OPENSSL_init_crypto(0, NULL))
+ return 0;
ex_data_lock = CRYPTO_THREAD_lock_new();
+ return ex_data_lock != NULL;
}
/*
return NULL;
}
- CRYPTO_THREAD_run_once(&ex_data_init, do_ex_data_init);
+ if (!RUN_ONCE(&ex_data_init, do_ex_data_init)) {
+ CRYPTOerr(CRYPTO_F_GET_AND_LOCK, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
if (ex_data_lock == NULL) {
/*
{
}
-static int dummy_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from,
+static int dummy_dup(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from,
void *from_d, int idx,
long argl, void *argp)
{
- return 0;
+ return 1;
}
int CRYPTO_free_ex_index(int class_index, int idx)
* 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)
+ const CRYPTO_EX_DATA *from)
{
int mx, j, i;
- char *ptr;
+ void *ptr;
EX_CALLBACK *stack[10];
EX_CALLBACK **storage = NULL;
EX_CALLBACKS *ip;
+ int toret = 0;
if (from->sk == NULL)
/* Nothing to copy over */
}
CRYPTO_THREAD_unlock(ex_data_lock);
- if (mx > 0 && storage == NULL) {
+ if (mx == 0)
+ return 1;
+ if (storage == NULL) {
CRYPTOerr(CRYPTO_F_CRYPTO_DUP_EX_DATA, ERR_R_MALLOC_FAILURE);
return 0;
}
+ /*
+ * Make sure the ex_data stack is at least |mx| elements long to avoid
+ * issues in the for loop that follows; so go get the |mx|'th element
+ * (if it does not exist CRYPTO_get_ex_data() returns NULL), and assign
+ * to itself. This is normally a no-op; but ensures the stack is the
+ * proper size
+ */
+ if (!CRYPTO_set_ex_data(to, mx - 1, CRYPTO_get_ex_data(to, mx - 1)))
+ goto err;
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);
+ if (!storage[i]->dup_func(to, from, &ptr, i,
+ storage[i]->argl, storage[i]->argp))
+ goto err;
CRYPTO_set_ex_data(to, i, ptr);
}
+ toret = 1;
+ err:
if (storage != stack)
OPENSSL_free(storage);
- return 1;
+ return toret;
}
int mx, i;
EX_CALLBACKS *ip;
void *ptr;
+ EX_CALLBACK *f;
EX_CALLBACK *stack[10];
EX_CALLBACK **storage = NULL;
if ((ip = get_and_lock(class_index)) == NULL)
- return;
+ goto err;
mx = sk_EX_CALLBACK_num(ip->meth);
if (mx > 0) {
}
CRYPTO_THREAD_unlock(ex_data_lock);
- if (mx > 0 && storage == NULL) {
- CRYPTOerr(CRYPTO_F_CRYPTO_FREE_EX_DATA, ERR_R_MALLOC_FAILURE);
- return;
- }
for (i = 0; i < mx; i++) {
- if (storage[i] && storage[i]->free_func) {
+ if (storage != NULL)
+ f = storage[i];
+ else {
+ CRYPTO_THREAD_write_lock(ex_data_lock);
+ f = sk_EX_CALLBACK_value(ip->meth, i);
+ CRYPTO_THREAD_unlock(ex_data_lock);
+ }
+ if (f != NULL && f->free_func != NULL) {
ptr = CRYPTO_get_ex_data(ad, i);
- storage[i]->free_func(obj, ptr, ad, i,
- storage[i]->argl, storage[i]->argp);
+ f->free_func(obj, ptr, ad, i, f->argl, f->argp);
}
}
if (storage != stack)
OPENSSL_free(storage);
+ err:
sk_void_free(ad->sk);
ad->sk = NULL;
}
+/*
+ * Allocate a given CRYPTO_EX_DATA item using the class specific allocation
+ * function
+ */
+int CRYPTO_alloc_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad,
+ int idx)
+{
+ EX_CALLBACK *f;
+ EX_CALLBACKS *ip;
+ void *curval;
+
+ curval = CRYPTO_get_ex_data(ad, idx);
+
+ /* Already there, no need to allocate */
+ if (curval != NULL)
+ return 1;
+
+ ip = get_and_lock(class_index);
+ f = sk_EX_CALLBACK_value(ip->meth, idx);
+ CRYPTO_THREAD_unlock(ex_data_lock);
+
+ /*
+ * This should end up calling CRYPTO_set_ex_data(), which allocates
+ * everything necessary to support placing the new data in the right spot.
+ */
+ f->new_func(obj, curval, ad, idx, f->argl, f->argp);
+
+ return 1;
+}
+
/*
* For a given CRYPTO_EX_DATA variable, set the value corresponding to a
* particular index in the class used by this variable