Commit 40222772 authored by Fernando Fernandez Mancera's avatar Fernando Fernandez Mancera
Browse files

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: default avatarFernando Fernandez Mancera <ffernandezmancera@gmail.com>
parent 5f2c7a85
Loading
Loading
Loading
Loading
+0 −143
Original line number Diff line number Diff line
@@ -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.
 */
+0 −35
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
/* 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 −0
Original line number Diff line number Diff line
/* 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) */