mirror of
https://github.com/QuasarApp/openssl.git
synced 2025-05-15 19:09:42 +00:00
When the new OpenSSL CSPRNG was introduced in version 1.1.1, it was announced in the release notes that it would be fork-safe, which the old CSPRNG hadn't been. The fork-safety was implemented using a fork count, which was incremented by a pthread_atfork handler. Initially, this handler was enabled by default. Unfortunately, the default behaviour had to be changed for other reasons in commit b5319bdbd095, so the new OpenSSL CSPRNG failed to keep its promise. This commit restores the fork-safety using a different approach. It replaces the fork count by a fork id, which coincides with the process id on UNIX-like operating systems and is zero on other operating systems. It is used to detect when an automatic reseed after a fork is necessary. To prevent a future regression, it also adds a test to verify that the child reseeds after fork. CVE-2019-1549 Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/9832)
682 lines
19 KiB
C
682 lines
19 KiB
C
/*
|
|
* Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
|
|
*
|
|
* 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 "e_os.h"
|
|
#include "internal/cryptlib_int.h"
|
|
#include <openssl/err.h>
|
|
#include "internal/rand_int.h"
|
|
#include "internal/bio.h"
|
|
#include <openssl/evp.h>
|
|
#include "internal/evp_int.h"
|
|
#include "internal/conf.h"
|
|
#include "internal/async.h"
|
|
#include "internal/engine.h"
|
|
#include "internal/comp.h"
|
|
#include "internal/err.h"
|
|
#include "internal/err_int.h"
|
|
#include "internal/objects.h"
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include "internal/thread_once.h"
|
|
#include "internal/dso_conf.h"
|
|
#include "internal/dso.h"
|
|
#include "internal/store.h"
|
|
#include <openssl/trace.h>
|
|
|
|
static int stopped = 0;
|
|
|
|
typedef struct ossl_init_stop_st OPENSSL_INIT_STOP;
|
|
struct ossl_init_stop_st {
|
|
void (*handler)(void);
|
|
OPENSSL_INIT_STOP *next;
|
|
};
|
|
|
|
static OPENSSL_INIT_STOP *stop_handlers = NULL;
|
|
static CRYPTO_RWLOCK *init_lock = NULL;
|
|
|
|
static CRYPTO_ONCE base = CRYPTO_ONCE_STATIC_INIT;
|
|
static int base_inited = 0;
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_base)
|
|
{
|
|
/* no need to init trace */
|
|
|
|
OSSL_TRACE(INIT, "ossl_init_base: setting up stop handlers\n");
|
|
#ifndef OPENSSL_NO_CRYPTO_MDEBUG
|
|
ossl_malloc_setup_failures();
|
|
#endif
|
|
|
|
if ((init_lock = CRYPTO_THREAD_lock_new()) == NULL)
|
|
goto err;
|
|
OPENSSL_cpuid_setup();
|
|
|
|
if (!ossl_init_thread())
|
|
return 0;
|
|
|
|
base_inited = 1;
|
|
return 1;
|
|
|
|
err:
|
|
OSSL_TRACE(INIT, "ossl_init_base failed!\n");
|
|
CRYPTO_THREAD_lock_free(init_lock);
|
|
init_lock = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static CRYPTO_ONCE register_atexit = CRYPTO_ONCE_STATIC_INIT;
|
|
#if !defined(OPENSSL_SYS_UEFI) && defined(_WIN32)
|
|
static int win32atexit(void)
|
|
{
|
|
OPENSSL_cleanup();
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_register_atexit)
|
|
{
|
|
#ifdef OPENSSL_INIT_DEBUG
|
|
fprintf(stderr, "OPENSSL_INIT: ossl_init_register_atexit()\n");
|
|
#endif
|
|
#ifndef OPENSSL_SYS_UEFI
|
|
# ifdef _WIN32
|
|
/* We use _onexit() in preference because it gets called on DLL unload */
|
|
if (_onexit(win32atexit) == NULL)
|
|
return 0;
|
|
# else
|
|
if (atexit(OPENSSL_cleanup) != 0)
|
|
return 0;
|
|
# endif
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_register_atexit,
|
|
ossl_init_register_atexit)
|
|
{
|
|
#ifdef OPENSSL_INIT_DEBUG
|
|
fprintf(stderr, "OPENSSL_INIT: ossl_init_no_register_atexit ok!\n");
|
|
#endif
|
|
/* Do nothing in this case */
|
|
return 1;
|
|
}
|
|
|
|
static CRYPTO_ONCE load_crypto_nodelete = CRYPTO_ONCE_STATIC_INIT;
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_nodelete)
|
|
{
|
|
OSSL_TRACE(INIT, "ossl_init_load_crypto_nodelete()\n");
|
|
|
|
#if !defined(OPENSSL_USE_NODELETE) \
|
|
&& !defined(OPENSSL_NO_PINSHARED)
|
|
# if defined(DSO_WIN32) && !defined(_WIN32_WCE)
|
|
{
|
|
HMODULE handle = NULL;
|
|
BOOL ret;
|
|
|
|
/* We don't use the DSO route for WIN32 because there is a better way */
|
|
ret = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|
|
| GET_MODULE_HANDLE_EX_FLAG_PIN,
|
|
(void *)&base_inited, &handle);
|
|
|
|
OSSL_TRACE1(INIT,
|
|
"ossl_init_load_crypto_nodelete: "
|
|
"obtained DSO reference? %s\n",
|
|
(ret == TRUE ? "No!" : "Yes."));
|
|
return (ret == TRUE) ? 1 : 0;
|
|
}
|
|
# elif !defined(DSO_NONE)
|
|
/*
|
|
* Deliberately leak a reference to ourselves. This will force the library
|
|
* to remain loaded until the atexit() handler is run at process exit.
|
|
*/
|
|
{
|
|
DSO *dso;
|
|
void *err;
|
|
|
|
if (!err_shelve_state(&err))
|
|
return 0;
|
|
|
|
dso = DSO_dsobyaddr(&base_inited, DSO_FLAG_NO_UNLOAD_ON_FREE);
|
|
/*
|
|
* In case of No!, it is uncertain our exit()-handlers can still be
|
|
* called. After dlclose() the whole library might have been unloaded
|
|
* already.
|
|
*/
|
|
OSSL_TRACE1(INIT, "obtained DSO reference? %s\n",
|
|
(dso == NULL ? "No!" : "Yes."));
|
|
DSO_free(dso);
|
|
err_unshelve_state(err);
|
|
}
|
|
# endif
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
static CRYPTO_ONCE load_crypto_strings = CRYPTO_ONCE_STATIC_INIT;
|
|
static int load_crypto_strings_inited = 0;
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_strings)
|
|
{
|
|
int ret = 1;
|
|
/*
|
|
* OPENSSL_NO_AUTOERRINIT is provided here to prevent at compile time
|
|
* pulling in all the error strings during static linking
|
|
*/
|
|
#if !defined(OPENSSL_NO_ERR) && !defined(OPENSSL_NO_AUTOERRINIT)
|
|
OSSL_TRACE(INIT, "err_load_crypto_strings_int()\n");
|
|
ret = err_load_crypto_strings_int();
|
|
load_crypto_strings_inited = 1;
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_load_crypto_strings,
|
|
ossl_init_load_crypto_strings)
|
|
{
|
|
/* Do nothing in this case */
|
|
return 1;
|
|
}
|
|
|
|
static CRYPTO_ONCE add_all_ciphers = CRYPTO_ONCE_STATIC_INIT;
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_ciphers)
|
|
{
|
|
/*
|
|
* OPENSSL_NO_AUTOALGINIT is provided here to prevent at compile time
|
|
* pulling in all the ciphers during static linking
|
|
*/
|
|
#ifndef OPENSSL_NO_AUTOALGINIT
|
|
OSSL_TRACE(INIT, "openssl_add_all_ciphers_int()\n");
|
|
openssl_add_all_ciphers_int();
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_add_all_ciphers,
|
|
ossl_init_add_all_ciphers)
|
|
{
|
|
/* Do nothing */
|
|
return 1;
|
|
}
|
|
|
|
static CRYPTO_ONCE add_all_digests = CRYPTO_ONCE_STATIC_INIT;
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_digests)
|
|
{
|
|
/*
|
|
* OPENSSL_NO_AUTOALGINIT is provided here to prevent at compile time
|
|
* pulling in all the ciphers during static linking
|
|
*/
|
|
#ifndef OPENSSL_NO_AUTOALGINIT
|
|
OSSL_TRACE(INIT, "openssl_add_all_digests()\n");
|
|
openssl_add_all_digests_int();
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_add_all_digests,
|
|
ossl_init_add_all_digests)
|
|
{
|
|
/* Do nothing */
|
|
return 1;
|
|
}
|
|
|
|
static CRYPTO_ONCE config = CRYPTO_ONCE_STATIC_INIT;
|
|
static int config_inited = 0;
|
|
static const OPENSSL_INIT_SETTINGS *conf_settings = NULL;
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_config)
|
|
{
|
|
int ret = openssl_config_int(conf_settings);
|
|
config_inited = 1;
|
|
return ret;
|
|
}
|
|
DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_config, ossl_init_config)
|
|
{
|
|
OSSL_TRACE(INIT, "openssl_no_config_int()\n");
|
|
openssl_no_config_int();
|
|
config_inited = 1;
|
|
return 1;
|
|
}
|
|
|
|
static CRYPTO_ONCE async = CRYPTO_ONCE_STATIC_INIT;
|
|
static int async_inited = 0;
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_async)
|
|
{
|
|
OSSL_TRACE(INIT, "async_init()\n");
|
|
if (!async_init())
|
|
return 0;
|
|
async_inited = 1;
|
|
return 1;
|
|
}
|
|
|
|
#ifndef OPENSSL_NO_ENGINE
|
|
static CRYPTO_ONCE engine_openssl = CRYPTO_ONCE_STATIC_INIT;
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_engine_openssl)
|
|
{
|
|
OSSL_TRACE(INIT, "engine_load_openssl_int()\n");
|
|
engine_load_openssl_int();
|
|
return 1;
|
|
}
|
|
# ifndef OPENSSL_NO_RDRAND
|
|
static CRYPTO_ONCE engine_rdrand = CRYPTO_ONCE_STATIC_INIT;
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_engine_rdrand)
|
|
{
|
|
OSSL_TRACE(INIT, "engine_load_rdrand_int()\n");
|
|
engine_load_rdrand_int();
|
|
return 1;
|
|
}
|
|
# endif
|
|
static CRYPTO_ONCE engine_dynamic = CRYPTO_ONCE_STATIC_INIT;
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_engine_dynamic)
|
|
{
|
|
OSSL_TRACE(INIT, "engine_load_dynamic_int()\n");
|
|
engine_load_dynamic_int();
|
|
return 1;
|
|
}
|
|
# ifndef OPENSSL_NO_STATIC_ENGINE
|
|
# ifndef OPENSSL_NO_DEVCRYPTOENG
|
|
static CRYPTO_ONCE engine_devcrypto = CRYPTO_ONCE_STATIC_INIT;
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_engine_devcrypto)
|
|
{
|
|
OSSL_TRACE(INIT, "engine_load_devcrypto_int()\n");
|
|
engine_load_devcrypto_int();
|
|
return 1;
|
|
}
|
|
# endif
|
|
# if !defined(OPENSSL_NO_PADLOCKENG)
|
|
static CRYPTO_ONCE engine_padlock = CRYPTO_ONCE_STATIC_INIT;
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_engine_padlock)
|
|
{
|
|
OSSL_TRACE(INIT, "engine_load_padlock_int()\n");
|
|
engine_load_padlock_int();
|
|
return 1;
|
|
}
|
|
# endif
|
|
# if defined(OPENSSL_SYS_WIN32) && !defined(OPENSSL_NO_CAPIENG)
|
|
static CRYPTO_ONCE engine_capi = CRYPTO_ONCE_STATIC_INIT;
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_engine_capi)
|
|
{
|
|
OSSL_TRACE(INIT, "engine_load_capi_int()\n");
|
|
engine_load_capi_int();
|
|
return 1;
|
|
}
|
|
# endif
|
|
# if !defined(OPENSSL_NO_AFALGENG)
|
|
static CRYPTO_ONCE engine_afalg = CRYPTO_ONCE_STATIC_INIT;
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_engine_afalg)
|
|
{
|
|
OSSL_TRACE(INIT, "engine_load_afalg_int()\n");
|
|
engine_load_afalg_int();
|
|
return 1;
|
|
}
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
#ifndef OPENSSL_NO_COMP
|
|
static CRYPTO_ONCE zlib = CRYPTO_ONCE_STATIC_INIT;
|
|
|
|
static int zlib_inited = 0;
|
|
DEFINE_RUN_ONCE_STATIC(ossl_init_zlib)
|
|
{
|
|
/* Do nothing - we need to know about this for the later cleanup */
|
|
zlib_inited = 1;
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
void OPENSSL_cleanup(void)
|
|
{
|
|
OPENSSL_INIT_STOP *currhandler, *lasthandler;
|
|
|
|
/*
|
|
* TODO(3.0): This function needs looking at with a view to moving most/all
|
|
* of this into onfree handlers in OPENSSL_CTX.
|
|
*/
|
|
|
|
/* If we've not been inited then no need to deinit */
|
|
if (!base_inited)
|
|
return;
|
|
|
|
/* Might be explicitly called and also by atexit */
|
|
if (stopped)
|
|
return;
|
|
stopped = 1;
|
|
|
|
/*
|
|
* Thread stop may not get automatically called by the thread library for
|
|
* the very last thread in some situations, so call it directly.
|
|
*/
|
|
OPENSSL_thread_stop();
|
|
|
|
currhandler = stop_handlers;
|
|
while (currhandler != NULL) {
|
|
currhandler->handler();
|
|
lasthandler = currhandler;
|
|
currhandler = currhandler->next;
|
|
OPENSSL_free(lasthandler);
|
|
}
|
|
stop_handlers = NULL;
|
|
|
|
CRYPTO_THREAD_lock_free(init_lock);
|
|
init_lock = NULL;
|
|
|
|
/*
|
|
* We assume we are single-threaded for this function, i.e. no race
|
|
* conditions for the various "*_inited" vars below.
|
|
*/
|
|
|
|
#ifndef OPENSSL_NO_COMP
|
|
if (zlib_inited) {
|
|
OSSL_TRACE(INIT, "OPENSSL_cleanup: comp_zlib_cleanup_int()\n");
|
|
comp_zlib_cleanup_int();
|
|
}
|
|
#endif
|
|
|
|
if (async_inited) {
|
|
OSSL_TRACE(INIT, "OPENSSL_cleanup: async_deinit()\n");
|
|
async_deinit();
|
|
}
|
|
|
|
if (load_crypto_strings_inited) {
|
|
OSSL_TRACE(INIT, "OPENSSL_cleanup: err_free_strings_int()\n");
|
|
err_free_strings_int();
|
|
}
|
|
|
|
/*
|
|
* Note that cleanup order is important:
|
|
* - rand_cleanup_int could call an ENGINE's RAND cleanup function so
|
|
* must be called before engine_cleanup_int()
|
|
* - ENGINEs use CRYPTO_EX_DATA and therefore, must be cleaned up
|
|
* before the ex data handlers are wiped during default openssl_ctx deinit.
|
|
* - conf_modules_free_int() can end up in ENGINE code so must be called
|
|
* before engine_cleanup_int()
|
|
* - ENGINEs and additional EVP algorithms might use added OIDs names so
|
|
* obj_cleanup_int() must be called last
|
|
*/
|
|
OSSL_TRACE(INIT, "OPENSSL_cleanup: rand_cleanup_int()\n");
|
|
rand_cleanup_int();
|
|
|
|
OSSL_TRACE(INIT, "OPENSSL_cleanup: conf_modules_free_int()\n");
|
|
conf_modules_free_int();
|
|
|
|
#ifndef OPENSSL_NO_ENGINE
|
|
OSSL_TRACE(INIT, "OPENSSL_cleanup: engine_cleanup_int()\n");
|
|
engine_cleanup_int();
|
|
#endif
|
|
OSSL_TRACE(INIT, "OPENSSL_cleanup: ossl_store_cleanup_int()\n");
|
|
ossl_store_cleanup_int();
|
|
|
|
OSSL_TRACE(INIT, "OPENSSL_cleanup: openssl_ctx_default_deinit()\n");
|
|
openssl_ctx_default_deinit();
|
|
|
|
ossl_cleanup_thread();
|
|
|
|
OSSL_TRACE(INIT, "OPENSSL_cleanup: bio_cleanup()\n");
|
|
bio_cleanup();
|
|
|
|
OSSL_TRACE(INIT, "OPENSSL_cleanup: evp_cleanup_int()\n");
|
|
evp_cleanup_int();
|
|
|
|
OSSL_TRACE(INIT, "OPENSSL_cleanup: obj_cleanup_int()\n");
|
|
obj_cleanup_int();
|
|
|
|
OSSL_TRACE(INIT, "OPENSSL_cleanup: err_int()\n");
|
|
err_cleanup();
|
|
|
|
OSSL_TRACE(INIT, "OPENSSL_cleanup: CRYPTO_secure_malloc_done()\n");
|
|
CRYPTO_secure_malloc_done();
|
|
|
|
OSSL_TRACE(INIT, "OPENSSL_cleanup: ossl_trace_cleanup()\n");
|
|
ossl_trace_cleanup();
|
|
|
|
base_inited = 0;
|
|
}
|
|
|
|
/*
|
|
* If this function is called with a non NULL settings value then it must be
|
|
* called prior to any threads making calls to any OpenSSL functions,
|
|
* i.e. passing a non-null settings value is assumed to be single-threaded.
|
|
*/
|
|
int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
|
|
{
|
|
/*
|
|
* TODO(3.0): This function needs looking at with a view to moving most/all
|
|
* of this into OPENSSL_CTX.
|
|
*/
|
|
|
|
if (stopped) {
|
|
if (!(opts & OPENSSL_INIT_BASE_ONLY))
|
|
CRYPTOerr(CRYPTO_F_OPENSSL_INIT_CRYPTO, ERR_R_INIT_FAIL);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* When the caller specifies OPENSSL_INIT_BASE_ONLY, that should be the
|
|
* *only* option specified. With that option we return immediately after
|
|
* doing the requested limited initialization. Note that
|
|
* err_shelve_state() called by us via ossl_init_load_crypto_nodelete()
|
|
* re-enters OPENSSL_init_crypto() with OPENSSL_INIT_BASE_ONLY, but with
|
|
* base already initialized this is a harmless NOOP.
|
|
*
|
|
* If we remain the only caller of err_shelve_state() the recursion should
|
|
* perhaps be removed, but if in doubt, it can be left in place.
|
|
*/
|
|
if (!RUN_ONCE(&base, ossl_init_base))
|
|
return 0;
|
|
|
|
if (opts & OPENSSL_INIT_BASE_ONLY)
|
|
return 1;
|
|
|
|
/*
|
|
* Now we don't always set up exit handlers, the INIT_BASE_ONLY calls
|
|
* should not have the side-effect of setting up exit handlers, and
|
|
* therefore, this code block is below the INIT_BASE_ONLY-conditioned early
|
|
* return above.
|
|
*/
|
|
if ((opts & OPENSSL_INIT_NO_ATEXIT) != 0) {
|
|
if (!RUN_ONCE_ALT(®ister_atexit, ossl_init_no_register_atexit,
|
|
ossl_init_register_atexit))
|
|
return 0;
|
|
} else if (!RUN_ONCE(®ister_atexit, ossl_init_register_atexit)) {
|
|
return 0;
|
|
}
|
|
|
|
if (!RUN_ONCE(&load_crypto_nodelete, ossl_init_load_crypto_nodelete))
|
|
return 0;
|
|
|
|
if ((opts & OPENSSL_INIT_NO_LOAD_CRYPTO_STRINGS)
|
|
&& !RUN_ONCE_ALT(&load_crypto_strings,
|
|
ossl_init_no_load_crypto_strings,
|
|
ossl_init_load_crypto_strings))
|
|
return 0;
|
|
|
|
if ((opts & OPENSSL_INIT_LOAD_CRYPTO_STRINGS)
|
|
&& !RUN_ONCE(&load_crypto_strings, ossl_init_load_crypto_strings))
|
|
return 0;
|
|
|
|
if ((opts & OPENSSL_INIT_NO_ADD_ALL_CIPHERS)
|
|
&& !RUN_ONCE_ALT(&add_all_ciphers, ossl_init_no_add_all_ciphers,
|
|
ossl_init_add_all_ciphers))
|
|
return 0;
|
|
|
|
if ((opts & OPENSSL_INIT_ADD_ALL_CIPHERS)
|
|
&& !RUN_ONCE(&add_all_ciphers, ossl_init_add_all_ciphers))
|
|
return 0;
|
|
|
|
if ((opts & OPENSSL_INIT_NO_ADD_ALL_DIGESTS)
|
|
&& !RUN_ONCE_ALT(&add_all_digests, ossl_init_no_add_all_digests,
|
|
ossl_init_add_all_digests))
|
|
return 0;
|
|
|
|
if ((opts & OPENSSL_INIT_ADD_ALL_DIGESTS)
|
|
&& !RUN_ONCE(&add_all_digests, ossl_init_add_all_digests))
|
|
return 0;
|
|
|
|
if ((opts & OPENSSL_INIT_ATFORK)
|
|
&& !openssl_init_fork_handlers())
|
|
return 0;
|
|
|
|
if ((opts & OPENSSL_INIT_NO_LOAD_CONFIG)
|
|
&& !RUN_ONCE_ALT(&config, ossl_init_no_config, ossl_init_config))
|
|
return 0;
|
|
|
|
if (opts & OPENSSL_INIT_LOAD_CONFIG) {
|
|
int ret;
|
|
CRYPTO_THREAD_write_lock(init_lock);
|
|
conf_settings = settings;
|
|
ret = RUN_ONCE(&config, ossl_init_config);
|
|
conf_settings = NULL;
|
|
CRYPTO_THREAD_unlock(init_lock);
|
|
if (ret <= 0)
|
|
return 0;
|
|
}
|
|
|
|
if ((opts & OPENSSL_INIT_ASYNC)
|
|
&& !RUN_ONCE(&async, ossl_init_async))
|
|
return 0;
|
|
|
|
#ifndef OPENSSL_NO_ENGINE
|
|
if ((opts & OPENSSL_INIT_ENGINE_OPENSSL)
|
|
&& !RUN_ONCE(&engine_openssl, ossl_init_engine_openssl))
|
|
return 0;
|
|
# ifndef OPENSSL_NO_RDRAND
|
|
if ((opts & OPENSSL_INIT_ENGINE_RDRAND)
|
|
&& !RUN_ONCE(&engine_rdrand, ossl_init_engine_rdrand))
|
|
return 0;
|
|
# endif
|
|
if ((opts & OPENSSL_INIT_ENGINE_DYNAMIC)
|
|
&& !RUN_ONCE(&engine_dynamic, ossl_init_engine_dynamic))
|
|
return 0;
|
|
# ifndef OPENSSL_NO_STATIC_ENGINE
|
|
# ifndef OPENSSL_NO_DEVCRYPTOENG
|
|
if ((opts & OPENSSL_INIT_ENGINE_CRYPTODEV)
|
|
&& !RUN_ONCE(&engine_devcrypto, ossl_init_engine_devcrypto))
|
|
return 0;
|
|
# endif
|
|
# if !defined(OPENSSL_NO_PADLOCKENG)
|
|
if ((opts & OPENSSL_INIT_ENGINE_PADLOCK)
|
|
&& !RUN_ONCE(&engine_padlock, ossl_init_engine_padlock))
|
|
return 0;
|
|
# endif
|
|
# if defined(OPENSSL_SYS_WIN32) && !defined(OPENSSL_NO_CAPIENG)
|
|
if ((opts & OPENSSL_INIT_ENGINE_CAPI)
|
|
&& !RUN_ONCE(&engine_capi, ossl_init_engine_capi))
|
|
return 0;
|
|
# endif
|
|
# if !defined(OPENSSL_NO_AFALGENG)
|
|
if ((opts & OPENSSL_INIT_ENGINE_AFALG)
|
|
&& !RUN_ONCE(&engine_afalg, ossl_init_engine_afalg))
|
|
return 0;
|
|
# endif
|
|
# endif
|
|
if (opts & (OPENSSL_INIT_ENGINE_ALL_BUILTIN
|
|
| OPENSSL_INIT_ENGINE_OPENSSL
|
|
| OPENSSL_INIT_ENGINE_AFALG)) {
|
|
ENGINE_register_all_complete();
|
|
}
|
|
#endif
|
|
|
|
#ifndef OPENSSL_NO_COMP
|
|
if ((opts & OPENSSL_INIT_ZLIB)
|
|
&& !RUN_ONCE(&zlib, ossl_init_zlib))
|
|
return 0;
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
int OPENSSL_atexit(void (*handler)(void))
|
|
{
|
|
OPENSSL_INIT_STOP *newhand;
|
|
|
|
#if !defined(OPENSSL_USE_NODELETE)\
|
|
&& !defined(OPENSSL_NO_PINSHARED)
|
|
{
|
|
union {
|
|
void *sym;
|
|
void (*func)(void);
|
|
} handlersym;
|
|
|
|
handlersym.func = handler;
|
|
# if defined(DSO_WIN32) && !defined(_WIN32_WCE)
|
|
{
|
|
HMODULE handle = NULL;
|
|
BOOL ret;
|
|
|
|
/*
|
|
* We don't use the DSO route for WIN32 because there is a better
|
|
* way
|
|
*/
|
|
ret = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|
|
| GET_MODULE_HANDLE_EX_FLAG_PIN,
|
|
handlersym.sym, &handle);
|
|
|
|
if (!ret)
|
|
return 0;
|
|
}
|
|
# elif !defined(DSO_NONE)
|
|
/*
|
|
* Deliberately leak a reference to the handler. This will force the
|
|
* library/code containing the handler to remain loaded until we run the
|
|
* atexit handler. If -znodelete has been used then this is
|
|
* unnecessary.
|
|
*/
|
|
{
|
|
DSO *dso = NULL;
|
|
|
|
ERR_set_mark();
|
|
dso = DSO_dsobyaddr(handlersym.sym, DSO_FLAG_NO_UNLOAD_ON_FREE);
|
|
/* See same code above in ossl_init_base() for an explanation. */
|
|
OSSL_TRACE1(INIT,
|
|
"atexit: obtained DSO reference? %s\n",
|
|
(dso == NULL ? "No!" : "Yes."));
|
|
DSO_free(dso);
|
|
ERR_pop_to_mark();
|
|
}
|
|
# endif
|
|
}
|
|
#endif
|
|
|
|
if ((newhand = OPENSSL_malloc(sizeof(*newhand))) == NULL) {
|
|
CRYPTOerr(CRYPTO_F_OPENSSL_ATEXIT, ERR_R_MALLOC_FAILURE);
|
|
return 0;
|
|
}
|
|
|
|
newhand->handler = handler;
|
|
newhand->next = stop_handlers;
|
|
stop_handlers = newhand;
|
|
|
|
return 1;
|
|
}
|
|
|
|
#ifdef OPENSSL_SYS_UNIX
|
|
/*
|
|
* The following three functions are for OpenSSL developers. This is
|
|
* where we set/reset state across fork (called via pthread_atfork when
|
|
* it exists, or manually by the application when it doesn't).
|
|
*
|
|
* WARNING! If you put code in either OPENSSL_fork_parent or
|
|
* OPENSSL_fork_child, you MUST MAKE SURE that they are async-signal-
|
|
* safe. See this link, for example:
|
|
* http://man7.org/linux/man-pages/man7/signal-safety.7.html
|
|
*/
|
|
|
|
void OPENSSL_fork_prepare(void)
|
|
{
|
|
}
|
|
|
|
void OPENSSL_fork_parent(void)
|
|
{
|
|
}
|
|
|
|
void OPENSSL_fork_child(void)
|
|
{
|
|
/* TODO(3.0): Inform all providers about a fork event */
|
|
}
|
|
#endif
|