Refactor crypto.[ch] into smaller OpenSSL module.

Add two new files (crypto_openssl.c, crypto_openssl.h) as new module of
crypto.[ch]. This new module includes all functions and dependencies related
to OpenSSL management. Those have been removed from crypto.[ch].

All new changes related to OpenSSL management must be done in these files.

Follows #24658

Signed-off-by: Fernando Fernandez Mancera <ffernandezmancera@gmail.com>
This commit is contained in:
Fernando Fernandez Mancera 2018-01-08 13:57:06 +01:00
parent 5f2c7a8567
commit 4022277272
4 changed files with 220 additions and 178 deletions

View file

@ -29,21 +29,6 @@
#include "crypto_ed25519.h"
#include "crypto_format.h"
DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/engine.h>
#include <openssl/rand.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/conf.h>
#include <openssl/hmac.h>
ENABLE_GCC_WARNING(redundant-decls)
#if __GNUC__ && GCC_VERSION >= 402
#if GCC_VERSION >= 406
#pragma GCC diagnostic pop
@ -82,40 +67,12 @@ ENABLE_GCC_WARNING(redundant-decls)
#include "keccak-tiny/keccak-tiny.h"
#ifdef ANDROID
/* Android's OpenSSL seems to have removed all of its Engine support. */
#define DISABLE_ENGINES
#endif
#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && \
!defined(LIBRESSL_VERSION_NUMBER)
/* OpenSSL as of 1.1.0pre4 has an "new" thread API, which doesn't require
* seting up various callbacks.
*
* OpenSSL 1.1.0pre4 has a messed up `ERR_remove_thread_state()` prototype,
* while the previous one was restored in pre5, and the function made a no-op
* (along with a deprecated annotation, which produces a compiler warning).
*
* While it is possible to support all three versions of the thread API,
* a version that existed only for one snapshot pre-release is kind of
* pointless, so let's not.
*/
#define NEW_THREAD_API
#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && ... */
/** Longest recognized */
#define MAX_DNS_LABEL_SIZE 63
/** Largest strong entropy request */
#define MAX_STRONGEST_RAND_SIZE 256
#ifndef NEW_THREAD_API
/** A number of preallocated mutexes for use by OpenSSL. */
static tor_mutex_t **openssl_mutexes_ = NULL;
/** How many mutexes have we allocated for use by OpenSSL? */
static int n_openssl_mutexes_ = 0;
#endif /* !defined(NEW_THREAD_API) */
/** A public key, or a public/private key-pair. */
struct crypto_pk_t
{
@ -129,7 +86,6 @@ struct crypto_dh_t {
DH *dh; /**< The openssl DH object */
};
static int setup_openssl_threading(void);
static int tor_check_dh_key(int severity, const BIGNUM *bn);
/** Return the number of bytes added by padding method <b>padding</b>.
@ -220,52 +176,6 @@ try_load_engine(const char *path, const char *engine)
}
#endif /* !defined(DISABLE_ENGINES) */
/* Returns a trimmed and human-readable version of an openssl version string
* <b>raw_version</b>. They are usually in the form of 'OpenSSL 1.0.0b 10
* May 2012' and this will parse them into a form similar to '1.0.0b' */
static char *
parse_openssl_version_str(const char *raw_version)
{
const char *end_of_version = NULL;
/* The output should be something like "OpenSSL 1.0.0b 10 May 2012. Let's
trim that down. */
if (!strcmpstart(raw_version, "OpenSSL ")) {
raw_version += strlen("OpenSSL ");
end_of_version = strchr(raw_version, ' ');
}
if (end_of_version)
return tor_strndup(raw_version,
end_of_version-raw_version);
else
return tor_strdup(raw_version);
}
static char *crypto_openssl_version_str = NULL;
/* Return a human-readable version of the run-time openssl version number. */
const char *
crypto_openssl_get_version_str(void)
{
if (crypto_openssl_version_str == NULL) {
const char *raw_version = OpenSSL_version(OPENSSL_VERSION);
crypto_openssl_version_str = parse_openssl_version_str(raw_version);
}
return crypto_openssl_version_str;
}
static char *crypto_openssl_header_version_str = NULL;
/* Return a human-readable version of the compile-time openssl version
* number. */
const char *
crypto_openssl_get_header_version_str(void)
{
if (crypto_openssl_header_version_str == NULL) {
crypto_openssl_header_version_str =
parse_openssl_version_str(OPENSSL_VERSION_TEXT);
}
return crypto_openssl_header_version_str;
}
/** Make sure that openssl is using its default PRNG. Return 1 if we had to
* adjust it; 0 otherwise. */
STATIC int
@ -3347,36 +3257,6 @@ memwipe(void *mem, uint8_t byte, size_t sz)
memset(mem, byte, sz);
}
#ifndef OPENSSL_THREADS
#error OpenSSL has been built without thread support. Tor requires an \
OpenSSL library with thread support enabled.
#endif
#ifndef NEW_THREAD_API
/** Helper: OpenSSL uses this callback to manipulate mutexes. */
static void
openssl_locking_cb_(int mode, int n, const char *file, int line)
{
(void)file;
(void)line;
if (!openssl_mutexes_)
/* This is not a really good fix for the
* "release-freed-lock-from-separate-thread-on-shutdown" problem, but
* it can't hurt. */
return;
if (mode & CRYPTO_LOCK)
tor_mutex_acquire(openssl_mutexes_[n]);
else
tor_mutex_release(openssl_mutexes_[n]);
}
static void
tor_set_openssl_thread_id(CRYPTO_THREADID *threadid)
{
CRYPTO_THREADID_set_numeric(threadid, tor_get_thread_id());
}
#endif /* !defined(NEW_THREAD_API) */
#if 0
/* This code is disabled, because OpenSSL never actually uses these callbacks.
*/
@ -3428,29 +3308,6 @@ openssl_dynlock_destroy_cb_(struct CRYPTO_dynlock_value *v,
#endif /* 0 */
/** @{ */
/** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being
* multithreaded. Returns 0. */
static int
setup_openssl_threading(void)
{
#ifndef NEW_THREAD_API
int i;
int n = CRYPTO_num_locks();
n_openssl_mutexes_ = n;
openssl_mutexes_ = tor_calloc(n, sizeof(tor_mutex_t *));
for (i=0; i < n; ++i)
openssl_mutexes_[i] = tor_mutex_new();
CRYPTO_set_locking_callback(openssl_locking_cb_);
CRYPTO_THREADID_set_callback(tor_set_openssl_thread_id);
#endif /* !defined(NEW_THREAD_API) */
#if 0
CRYPTO_set_dynlock_create_callback(openssl_dynlock_create_cb_);
CRYPTO_set_dynlock_lock_callback(openssl_dynlock_lock_cb_);
CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy_cb_);
#endif
return 0;
}
/** Uninitialize the crypto library. Return 0 on success. Does not detect
* failure.
*/

View file

@ -20,41 +20,8 @@
#include "testsupport.h"
#include "compat.h"
#include <openssl/engine.h>
#include "keccak-tiny/keccak-tiny.h"
/*
Macro to create an arbitrary OpenSSL version number as used by
OPENSSL_VERSION_NUMBER or SSLeay(), since the actual numbers are a bit hard
to read.
Don't use this directly, instead use one of the other OPENSSL_V macros
below.
The format is: 4 bits major, 8 bits minor, 8 bits fix, 8 bits patch, 4 bit
status.
*/
#define OPENSSL_VER(a,b,c,d,e) \
(((a)<<28) | \
((b)<<20) | \
((c)<<12) | \
((d)<< 4) | \
(e))
/** An openssl release number. For example, OPENSSL_V(0,9,8,'j') is the
* version for the released version of 0.9.8j */
#define OPENSSL_V(a,b,c,d) \
OPENSSL_VER((a),(b),(c),(d)-'a'+1,0xf)
/** An openssl release number for the first release in the series. For
* example, OPENSSL_V_NOPATCH(1,0,0) is the first released version of OpenSSL
* 1.0.0. */
#define OPENSSL_V_NOPATCH(a,b,c) \
OPENSSL_VER((a),(b),(c),0,0xf)
/** The first version that would occur for any alpha or beta in an openssl
* series. For example, OPENSSL_V_SERIES(0,9,8) is greater than any released
* 0.9.7, and less than any released 0.9.8. */
#define OPENSSL_V_SERIES(a,b,c) \
OPENSSL_VER((a),(b),(c),0,0)
/** Length of the output of our message digest. */
#define DIGEST_LEN 20
/** Length of the output of our second (improved) message digests. (For now
@ -131,8 +98,6 @@ typedef struct crypto_xof_t crypto_xof_t;
typedef struct crypto_dh_t crypto_dh_t;
/* global state */
const char * crypto_openssl_get_version_str(void);
const char * crypto_openssl_get_header_version_str(void);
int crypto_early_init(void) ATTR_WUR;
int crypto_global_init(int hardwareAccel,
const char *accelName,

115
src/common/crypto_openssl.c Normal file
View file

@ -0,0 +1,115 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file crypto_openssl.c
*
* \brief Block of functions related to operations from OpenSSL.
**/
#include "crypto_openssl.h"
#ifndef NEW_THREAD_API
/** A number of preallocated mutexes for use by OpenSSL. */
tor_mutex_t **openssl_mutexes_ = NULL;
/** How many mutexes have we allocated for use by OpenSSL? */
int n_openssl_mutexes_ = 0;
#endif /* !defined(NEW_THREAD_API) */
/* Returns a trimmed and human-readable version of an openssl version string
* <b>raw_version</b>. They are usually in the form of 'OpenSSL 1.0.0b 10
* May 2012' and this will parse them into a form similar to '1.0.0b' */
char *
parse_openssl_version_str(const char *raw_version)
{
const char *end_of_version = NULL;
/* The output should be something like "OpenSSL 1.0.0b 10 May 2012. Let's
trim that down. */
if (!strcmpstart(raw_version, "OpenSSL ")) {
raw_version += strlen("OpenSSL ");
end_of_version = strchr(raw_version, ' ');
}
if (end_of_version)
return tor_strndup(raw_version,
end_of_version-raw_version);
else
return tor_strdup(raw_version);
}
char *crypto_openssl_version_str = NULL;
/* Return a human-readable version of the run-time openssl version number. */
const char *
crypto_openssl_get_version_str(void)
{
if (crypto_openssl_version_str == NULL) {
const char *raw_version = OpenSSL_version(OPENSSL_VERSION);
crypto_openssl_version_str = parse_openssl_version_str(raw_version);
}
return crypto_openssl_version_str;
}
char *crypto_openssl_header_version_str = NULL;
/* Return a human-readable version of the compile-time openssl version
* number. */
const char *
crypto_openssl_get_header_version_str(void)
{
if (crypto_openssl_header_version_str == NULL) {
crypto_openssl_header_version_str =
parse_openssl_version_str(OPENSSL_VERSION_TEXT);
}
return crypto_openssl_header_version_str;
}
#ifndef OPENSSL_THREADS
#error OpenSSL has been built without thread support. Tor requires an \
OpenSSL library with thread support enabled.
#endif
#ifndef NEW_THREAD_API
/** Helper: OpenSSL uses this callback to manipulate mutexes. */
void
openssl_locking_cb_(int mode, int n, const char *file, int line)
{
(void)file;
(void)line;
if (!openssl_mutexes_)
/* This is not a really good fix for the
* "release-freed-lock-from-separate-thread-on-shutdown" problem, but
* it can't hurt. */
return;
if (mode & CRYPTO_LOCK)
tor_mutex_acquire(openssl_mutexes_[n]);
else
tor_mutex_release(openssl_mutexes_[n]);
}
void
tor_set_openssl_thread_id(CRYPTO_THREADID *threadid)
{
CRYPTO_THREADID_set_numeric(threadid, tor_get_thread_id());
}
#endif /* !defined(NEW_THREAD_API) */
/** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being
* multithreaded. Returns 0. */
int
setup_openssl_threading(void)
{
#ifndef NEW_THREAD_API
int i;
int n = CRYPTO_num_locks();
n_openssl_mutexes_ = n;
openssl_mutexes_ = tor_calloc(n, sizeof(tor_mutex_t *));
for (i=0; i < n; ++i)
openssl_mutexes_[i] = tor_mutex_new();
CRYPTO_set_locking_callback(openssl_locking_cb_);
CRYPTO_THREADID_set_callback(tor_set_openssl_thread_id);
#endif /* !defined(NEW_THREAD_API) */
return 0;
}

105
src/common/crypto_openssl.h Normal file
View file

@ -0,0 +1,105 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file crypto_openssl.h
*
* \brief Headers for crypto_openssl.c
**/
#ifndef TOR_CRYPTO_OPENSSL_H
#define TOR_CRYPTO_OPENSSL_H
#include <stdio.h>
#include "util.h"
#include <openssl/engine.h>
DISABLE_GCC_WARNING(redundant-decls)
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/engine.h>
#include <openssl/rand.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/conf.h>
#include <openssl/hmac.h>
ENABLE_GCC_WARNING(redundant-decls)
/*
Macro to create an arbitrary OpenSSL version number as used by
OPENSSL_VERSION_NUMBER or SSLeay(), since the actual numbers are a bit hard
to read.
Don't use this directly, instead use one of the other OPENSSL_V macros
below.
The format is: 4 bits major, 8 bits minor, 8 bits fix, 8 bits patch, 4 bit
status.
*/
#define OPENSSL_VER(a,b,c,d,e) \
(((a)<<28) | \
((b)<<20) | \
((c)<<12) | \
((d)<< 4) | \
(e))
/** An openssl release number. For example, OPENSSL_V(0,9,8,'j') is the
* version for the released version of 0.9.8j */
#define OPENSSL_V(a,b,c,d) \
OPENSSL_VER((a),(b),(c),(d)-'a'+1,0xf)
/** An openssl release number for the first release in the series. For
* example, OPENSSL_V_NOPATCH(1,0,0) is the first released version of OpenSSL
* 1.0.0. */
#define OPENSSL_V_NOPATCH(a,b,c) \
OPENSSL_VER((a),(b),(c),0,0xf)
/** The first version that would occur for any alpha or beta in an openssl
* series. For example, OPENSSL_V_SERIES(0,9,8) is greater than any released
* 0.9.7, and less than any released 0.9.8. */
#define OPENSSL_V_SERIES(a,b,c) \
OPENSSL_VER((a),(b),(c),0,0)
#ifdef ANDROID
/* Android's OpenSSL seems to have removed all of its Engine support. */
#define DISABLE_ENGINES
#endif
#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && \
!defined(LIBRESSL_VERSION_NUMBER)
/* OpenSSL as of 1.1.0pre4 has an "new" thread API, which doesn't require
* seting up various callbacks.
*
* OpenSSL 1.1.0pre4 has a messed up `ERR_remove_thread_state()` prototype,
* while the previous one was restored in pre5, and the function made a no-op
* (along with a deprecated annotation, which produces a compiler warning).
*
* While it is possible to support all three versions of the thread API,
* a version that existed only for one snapshot pre-release is kind of
* pointless, so let's not.
*/
#define NEW_THREAD_API
#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && ... */
tor_mutex_t **openssl_mutexes_;
int n_openssl_mutexes_;
/* global openssl state */
const char * crypto_openssl_get_version_str(void);
const char * crypto_openssl_get_header_version_str(void);
/* generics OpenSSL functions */
char * parse_openssl_version_str(const char *raw_version);
void openssl_locking_cb_(int mode, int n, const char *file, int line);
void tor_set_openssl_thread_id(CRYPTO_THREADID *threadid);
/* OpenSSL threading setup function */
int setup_openssl_threading(void);
#endif /* !defined(TOR_CRYPTO_OPENSSL_H) */