#include "orconfig.h"
#define CRYPTO_PRIVATE
#include "lib/crypt_ops/crypto_init.h"
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/crypt_ops/crypto_openssl_mgt.h"
#include "lib/crypt_ops/crypto_nss_mgt.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_sys.h"
#include "lib/crypt_ops/crypto_options_st.h"
#include "lib/conf/conftypes.h"
#include "lib/log/util_bug.h"
#include "lib/subsys/subsys.h"
#include "ext/siphash.h"
static int crypto_early_initialized_ = 0;
static int crypto_global_initialized_ = 0;
static int have_seeded_siphash = 0;
int
crypto_init_siphash_key(void)
{
struct sipkey key;
if (have_seeded_siphash)
return 0;
crypto_rand((char*) &key, sizeof(key));
siphash_set_global_key(&key);
have_seeded_siphash = 1;
return 0;
}
int
crypto_early_init(void)
{
if (!crypto_early_initialized_) {
crypto_early_initialized_ = 1;
#ifdef ENABLE_OPENSSL
crypto_openssl_early_init();
#endif
#ifdef ENABLE_NSS
crypto_nss_early_init(0);
#endif
if (crypto_seed_rng() < 0)
return -1;
if (crypto_init_siphash_key() < 0)
return -1;
crypto_rand_fast_init();
curve25519_init();
ed25519_init();
}
return 0;
}
int
crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
{
if (!crypto_global_initialized_) {
if (crypto_early_init() < 0)
return -1;
crypto_global_initialized_ = 1;
crypto_dh_init();
#ifdef ENABLE_OPENSSL
if (crypto_openssl_late_init(useAccel, accelName, accelDir) < 0)
return -1;
#else
(void)useAccel;
(void)accelName;
(void)accelDir;
#endif
#ifdef ENABLE_NSS
if (crypto_nss_late_init() < 0)
return -1;
#endif
}
return 0;
}
void
crypto_thread_cleanup(void)
{
#ifdef ENABLE_OPENSSL
crypto_openssl_thread_cleanup();
#endif
destroy_thread_fast_rng();
}
int
crypto_global_cleanup(void)
{
crypto_dh_free_all();
#ifdef ENABLE_OPENSSL
crypto_openssl_global_cleanup();
#endif
#ifdef ENABLE_NSS
crypto_nss_global_cleanup();
#endif
crypto_rand_fast_shutdown();
crypto_early_initialized_ = 0;
crypto_global_initialized_ = 0;
have_seeded_siphash = 0;
siphash_unset_global_key();
return 0;
}
void
crypto_prefork(void)
{
#ifdef ENABLE_NSS
crypto_nss_prefork();
#endif
destroy_thread_fast_rng();
}
void
crypto_postfork(void)
{
#ifdef ENABLE_NSS
crypto_nss_postfork();
#endif
}
const char *
crypto_get_library_name(void)
{
#ifdef ENABLE_OPENSSL
return "OpenSSL";
#endif
#ifdef ENABLE_NSS
return "NSS";
#endif
}
const char *
crypto_get_library_version_string(void)
{
#ifdef ENABLE_OPENSSL
return crypto_openssl_get_version_str();
#endif
#ifdef ENABLE_NSS
return crypto_nss_get_version_str();
#endif
}
const char *
crypto_get_header_version_string(void)
{
#ifdef ENABLE_OPENSSL
return crypto_openssl_get_header_version_str();
#endif
#ifdef ENABLE_NSS
return crypto_nss_get_header_version_str();
#endif
}
int
tor_is_using_nss(void)
{
#ifdef ENABLE_NSS
return 1;
#else
return 0;
#endif
}
static int
subsys_crypto_initialize(void)
{
if (crypto_early_init() < 0)
return -1;
crypto_dh_init();
return 0;
}
static void
subsys_crypto_shutdown(void)
{
crypto_global_cleanup();
}
static void
subsys_crypto_prefork(void)
{
crypto_prefork();
}
static void
subsys_crypto_postfork(void)
{
crypto_postfork();
}
static void
subsys_crypto_thread_cleanup(void)
{
crypto_thread_cleanup();
}
#define CRYPTO_OPTIONS_MAGIC 0x68757368
static int
crypto_options_validate(const void *arg, char **msg_out)
{
const crypto_options_t *opt = arg;
tor_assert(opt->magic == CRYPTO_OPTIONS_MAGIC);
tor_assert(msg_out);
if (opt->AccelDir && !opt->AccelName) {
*msg_out = tor_strdup("Can't use hardware crypto accelerator dir "
"without engine name.");
return -1;
}
return 0;
}
#define CONF_CONTEXT LL_TABLE
#include "lib/crypt_ops/crypto_options.inc"
#undef CONF_CONTEXT
static const config_format_t crypto_options_fmt = {
.size = sizeof(crypto_options_t),
.magic = { "crypto_options_t",
CRYPTO_OPTIONS_MAGIC,
offsetof(crypto_options_t, magic) },
.vars = crypto_options_t_vars,
.validate_fn = crypto_options_validate,
};
static int
crypto_set_options(void *arg)
{
const crypto_options_t *options = arg;
const bool hardware_accel = options->HardwareAccel || options->AccelName;
if (crypto_global_init(hardware_accel,
options->AccelName,
options->AccelDir)) {
log_err(LD_BUG, "Unable to initialize the crypto subsystem. Exiting.");
return -1;
}
return 0;
}
const struct subsys_fns_t sys_crypto = {
.name = "crypto",
SUBSYS_DECLARE_LOCATION(),
.supported = true,
.level = -60,
.initialize = subsys_crypto_initialize,
.shutdown = subsys_crypto_shutdown,
.prefork = subsys_crypto_prefork,
.postfork = subsys_crypto_postfork,
.thread_cleanup = subsys_crypto_thread_cleanup,
.options_format = &crypto_options_fmt,
.set_options = crypto_set_options,
};