summaryrefslogtreecommitdiff
path: root/src/common/crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/crypto.c')
-rw-r--r--src/common/crypto.c232
1 files changed, 105 insertions, 127 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 30990ecc8f..6c3dd8d4a4 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -57,8 +57,8 @@
#include "container.h"
#include "compat.h"
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,7)
-#error "We require OpenSSL >= 0.9.7"
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
+#error "We require OpenSSL >= 0.9.8"
#endif
#ifdef ANDROID
@@ -69,31 +69,6 @@
/** Longest recognized */
#define MAX_DNS_LABEL_SIZE 63
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8) && \
- !defined(RUNNING_DOXYGEN)
-/** @{ */
-/** On OpenSSL versions before 0.9.8, there is no working SHA256
- * implementation, so we use Tom St Denis's nice speedy one, slightly adapted
- * to our needs. These macros make it usable by us. */
-#define SHA256_CTX sha256_state
-#define SHA256_Init sha256_init
-#define SHA256_Update sha256_process
-#define LTC_ARGCHK(x) tor_assert(x)
-/** @} */
-#include "sha256.c"
-#define SHA256_Final(a,b) sha256_done(b,a)
-
-static unsigned char *
-SHA256(const unsigned char *m, size_t len, unsigned char *d)
-{
- SHA256_CTX ctx;
- SHA256_Init(&ctx);
- SHA256_Update(&ctx, m, len);
- SHA256_Final(d, &ctx);
- return d;
-}
-#endif
-
/** Macro: is k a valid RSA public or private key? */
#define PUBLIC_KEY_OK(k) ((k) && (k)->key && (k)->key->n)
/** Macro: is k a valid RSA private key? */
@@ -101,9 +76,9 @@ SHA256(const unsigned char *m, size_t len, unsigned char *d)
#ifdef TOR_IS_MULTITHREADED
/** A number of preallocated mutexes for use by OpenSSL. */
-static tor_mutex_t **_openssl_mutexes = NULL;
+static tor_mutex_t **openssl_mutexes_ = NULL;
/** How many mutexes have we allocated for use by OpenSSL? */
-static int _n_openssl_mutexes = 0;
+static int n_openssl_mutexes_ = 0;
#endif
/** A public key, or a public/private key-pair. */
@@ -158,7 +133,7 @@ crypto_get_rsa_padding(int padding)
}
/** Boolean: has OpenSSL's crypto been initialized? */
-static int _crypto_global_initialized = 0;
+static int crypto_global_initialized_ = 0;
/** Log all pending crypto errors at level <b>severity</b>. Use
* <b>doing</b> to describe our current activities.
@@ -221,16 +196,60 @@ try_load_engine(const char *path, const char *engine)
}
#endif
+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 = SSLeay_version(SSLEAY_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)
+ crypto_openssl_version_str = tor_strndup(raw_version,
+ end_of_version-raw_version);
+ else
+ crypto_openssl_version_str = tor_strdup(raw_version);
+ }
+ return crypto_openssl_version_str;
+}
+
/** Initialize the crypto library. Return 0 on success, -1 on failure.
*/
int
crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
{
- if (!_crypto_global_initialized) {
+ if (!crypto_global_initialized_) {
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
- _crypto_global_initialized = 1;
+ crypto_global_initialized_ = 1;
setup_openssl_threading();
+
+ if (SSLeay() == OPENSSL_VERSION_NUMBER &&
+ !strcmp(SSLeay_version(SSLEAY_VERSION), OPENSSL_VERSION_TEXT)) {
+ log_info(LD_CRYPTO, "OpenSSL version matches version from headers "
+ "(%lx: %s).", SSLeay(), SSLeay_version(SSLEAY_VERSION));
+ } else {
+ log_warn(LD_CRYPTO, "OpenSSL version from headers does not match the "
+ "version we're running with. If you get weird crashes, that "
+ "might be why. (Compiled with %lx: %s; running with %lx: %s).",
+ (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT,
+ SSLeay(), SSLeay_version(SSLEAY_VERSION));
+ }
+
+ if (SSLeay() < OPENSSL_V_SERIES(1,0,0)) {
+ log_notice(LD_CRYPTO,
+ "Your OpenSSL version seems to be %s. We recommend 1.0.0 "
+ "or later.",
+ crypto_openssl_get_version_str());
+ }
+
if (useAccel > 0) {
#ifdef DISABLE_ENGINES
(void)accelName;
@@ -294,7 +313,7 @@ crypto_thread_cleanup(void)
/** used by tortls.c: wrap an RSA* in a crypto_pk_t. */
crypto_pk_t *
-_crypto_new_pk_from_rsa(RSA *rsa)
+crypto_new_pk_from_rsa_(RSA *rsa)
{
crypto_pk_t *env;
tor_assert(rsa);
@@ -307,7 +326,7 @@ _crypto_new_pk_from_rsa(RSA *rsa)
/** Helper, used by tor-checkkey.c and tor-gencert.c. Return the RSA from a
* crypto_pk_t. */
RSA *
-_crypto_pk_get_rsa(crypto_pk_t *env)
+crypto_pk_get_rsa_(crypto_pk_t *env)
{
return env->key;
}
@@ -315,7 +334,7 @@ _crypto_pk_get_rsa(crypto_pk_t *env)
/** used by tortls.c: get an equivalent EVP_PKEY* for a crypto_pk_t. Iff
* private is set, include the private-key portion of the key. */
EVP_PKEY *
-_crypto_pk_get_evp_pkey(crypto_pk_t *env, int private)
+crypto_pk_get_evp_pkey_(crypto_pk_t *env, int private)
{
RSA *key = NULL;
EVP_PKEY *pkey = NULL;
@@ -343,7 +362,7 @@ _crypto_pk_get_evp_pkey(crypto_pk_t *env, int private)
/** Used by tortls.c: Get the DH* from a crypto_dh_t.
*/
DH *
-_crypto_dh_get_dh(crypto_dh_t *dh)
+crypto_dh_get_dh_(crypto_dh_t *dh)
{
return dh->dh;
}
@@ -358,7 +377,7 @@ crypto_pk_new(void)
rsa = RSA_new();
tor_assert(rsa);
- return _crypto_new_pk_from_rsa(rsa);
+ return crypto_new_pk_from_rsa_(rsa);
}
/** Release a reference to an asymmetric key; when all the references
@@ -441,11 +460,7 @@ crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits)
if (env->key)
RSA_free(env->key);
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
- /* In OpenSSL 0.9.7, RSA_generate_key is all we have. */
- env->key = RSA_generate_key(bits, 65537, NULL, NULL);
-#else
- /* In OpenSSL 0.9.8, RSA_generate_key is deprecated. */
+
{
BIGNUM *e = BN_new();
RSA *r = NULL;
@@ -466,8 +481,8 @@ crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits)
BN_free(e);
if (r)
RSA_free(r);
- }
-#endif
+ }
+
if (!env->key) {
crypto_log_errors(LOG_WARN, "generating RSA key");
return -1;
@@ -711,19 +726,23 @@ crypto_pk_public_exponent_ok(crypto_pk_t *env)
return BN_is_word(env->key->e, 65537);
}
-/** Compare the public-key components of a and b. Return -1 if a\<b, 0
- * if a==b, and 1 if a\>b.
+/** Compare the public-key components of a and b. Return less than 0
+ * if a\<b, 0 if a==b, and greater than 0 if a\>b. A NULL key is
+ * considered to be less than all non-NULL keys, and equal to itself.
+ *
+ * Note that this may leak information about the keys through timing.
*/
int
crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b)
{
int result;
+ char a_is_non_null = (a != NULL) && (a->key != NULL);
+ char b_is_non_null = (b != NULL) && (b->key != NULL);
+ char an_argument_is_null = !a_is_non_null | !b_is_non_null;
- if (!a || !b)
- return -1;
-
- if (!a->key || !b->key)
- return -1;
+ result = tor_memcmp(&a_is_non_null, &b_is_non_null, sizeof(a_is_non_null));
+ if (an_argument_is_null)
+ return result;
tor_assert(PUBLIC_KEY_OK(a));
tor_assert(PUBLIC_KEY_OK(b));
@@ -733,6 +752,18 @@ crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b)
return BN_cmp((a->key)->e, (b->key)->e);
}
+/** Compare the public-key components of a and b. Return non-zero iff
+ * a==b. A NULL key is considered to be distinct from all non-NULL
+ * keys, and equal to itself.
+ *
+ * Note that this may leak information about the keys through timing.
+ */
+int
+crypto_pk_eq_keys(crypto_pk_t *a, crypto_pk_t *b)
+{
+ return (crypto_pk_cmp_keys(a, b) == 0);
+}
+
/** Return the size of the public key modulus in <b>env</b>, in bytes. */
size_t
crypto_pk_keysize(crypto_pk_t *env)
@@ -791,7 +822,7 @@ crypto_pk_copy_full(crypto_pk_t *env)
return NULL;
}
- return _crypto_new_pk_from_rsa(new_key);
+ return crypto_new_pk_from_rsa_(new_key);
}
/** Encrypt <b>fromlen</b> bytes from <b>from</b> with the public key
@@ -1158,7 +1189,7 @@ crypto_pk_asn1_decode(const char *str, size_t len)
crypto_log_errors(LOG_WARN,"decoding public key");
return NULL;
}
- return _crypto_new_pk_from_rsa(rsa);
+ return crypto_new_pk_from_rsa_(rsa);
}
/** Given a private or public key <b>pk</b>, put a SHA1 hash of the
@@ -1623,63 +1654,11 @@ crypto_hmac_sha256(char *hmac_out,
const char *key, size_t key_len,
const char *msg, size_t msg_len)
{
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(0,9,8)
/* If we've got OpenSSL >=0.9.8 we can use its hmac implementation. */
tor_assert(key_len < INT_MAX);
tor_assert(msg_len < INT_MAX);
HMAC(EVP_sha256(), key, (int)key_len, (unsigned char*)msg, (int)msg_len,
(unsigned char*)hmac_out, NULL);
-#else
- /* OpenSSL doesn't have an EVP implementation for SHA256. We'll need
- to do HMAC on our own.
-
- HMAC isn't so hard: To compute HMAC(key, msg):
- 1. If len(key) > blocksize, key = H(key).
- 2. If len(key) < blocksize, right-pad key up to blocksize with 0 bytes.
- 3. let ipad = key xor 0x363636363636....36
- let opad = key xor 0x5c5c5c5c5c5c....5c
- The result is H(opad | H( ipad | msg ) )
- */
-#define BLOCKSIZE 64
-#define DIGESTSIZE 32
- uint8_t k[BLOCKSIZE];
- uint8_t pad[BLOCKSIZE];
- uint8_t d[DIGESTSIZE];
- int i;
- SHA256_CTX st;
-
- tor_assert(key_len < INT_MAX);
- tor_assert(msg_len < INT_MAX);
-
- if (key_len <= BLOCKSIZE) {
- memset(k, 0, sizeof(k));
- memcpy(k, key, key_len); /* not time invariant in key_len */
- } else {
- SHA256((const uint8_t *)key, key_len, k);
- memset(k+DIGESTSIZE, 0, sizeof(k)-DIGESTSIZE);
- }
- for (i = 0; i < BLOCKSIZE; ++i)
- pad[i] = k[i] ^ 0x36;
- SHA256_Init(&st);
- SHA256_Update(&st, pad, BLOCKSIZE);
- SHA256_Update(&st, (uint8_t*)msg, msg_len);
- SHA256_Final(d, &st);
-
- for (i = 0; i < BLOCKSIZE; ++i)
- pad[i] = k[i] ^ 0x5c;
- SHA256_Init(&st);
- SHA256_Update(&st, pad, BLOCKSIZE);
- SHA256_Update(&st, d, DIGESTSIZE);
- SHA256_Final((uint8_t*)hmac_out, &st);
-
- /* Now clear everything. */
- memwipe(k, 0, sizeof(k));
- memwipe(pad, 0, sizeof(pad));
- memwipe(d, 0, sizeof(d));
- memwipe(&st, 0, sizeof(st));
-#undef BLOCKSIZE
-#undef DIGESTSIZE
-#endif
}
/* DH */
@@ -2282,9 +2261,7 @@ crypto_dh_free(crypto_dh_t *dh)
* that fd without checking whether it fit in the fd_set. Thus, if the
* system has not just been started up, it is unsafe to call */
#define RAND_POLL_IS_SAFE \
- ((OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,7,'j') && \
- OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)) || \
- OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,8,'c'))
+ (OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,8,'c'))
/** Set the seed of the weak RNG to a random value. */
static void
@@ -2939,19 +2916,19 @@ memwipe(void *mem, uint8_t byte, size_t sz)
#ifdef TOR_IS_MULTITHREADED
/** Helper: OpenSSL uses this callback to manipulate mutexes. */
static void
-_openssl_locking_cb(int mode, int n, const char *file, int line)
+openssl_locking_cb_(int mode, int n, const char *file, int line)
{
(void)file;
(void)line;
- if (!_openssl_mutexes)
+ 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]);
+ tor_mutex_acquire(openssl_mutexes_[n]);
else
- tor_mutex_release(_openssl_mutexes[n]);
+ tor_mutex_release(openssl_mutexes_[n]);
}
/** OpenSSL helper type: wraps a Tor mutex so that OpenSSL can use it
@@ -2963,7 +2940,7 @@ struct CRYPTO_dynlock_value {
/** OpenSSL callback function to allocate a lock: see CRYPTO_set_dynlock_*
* documentation in OpenSSL's docs for more info. */
static struct CRYPTO_dynlock_value *
-_openssl_dynlock_create_cb(const char *file, int line)
+openssl_dynlock_create_cb_(const char *file, int line)
{
struct CRYPTO_dynlock_value *v;
(void)file;
@@ -2976,7 +2953,7 @@ _openssl_dynlock_create_cb(const char *file, int line)
/** OpenSSL callback function to acquire or release a lock: see
* CRYPTO_set_dynlock_* documentation in OpenSSL's docs for more info. */
static void
-_openssl_dynlock_lock_cb(int mode, struct CRYPTO_dynlock_value *v,
+openssl_dynlock_lock_cb_(int mode, struct CRYPTO_dynlock_value *v,
const char *file, int line)
{
(void)file;
@@ -2990,7 +2967,7 @@ _openssl_dynlock_lock_cb(int mode, struct CRYPTO_dynlock_value *v,
/** OpenSSL callback function to free a lock: see CRYPTO_set_dynlock_*
* documentation in OpenSSL's docs for more info. */
static void
-_openssl_dynlock_destroy_cb(struct CRYPTO_dynlock_value *v,
+openssl_dynlock_destroy_cb_(struct CRYPTO_dynlock_value *v,
const char *file, int line)
{
(void)file;
@@ -3007,15 +2984,15 @@ setup_openssl_threading(void)
{
int i;
int n = CRYPTO_num_locks();
- _n_openssl_mutexes = n;
- _openssl_mutexes = tor_malloc(n*sizeof(tor_mutex_t *));
+ n_openssl_mutexes_ = n;
+ openssl_mutexes_ = tor_malloc(n*sizeof(tor_mutex_t *));
for (i=0; i < n; ++i)
- _openssl_mutexes[i] = tor_mutex_new();
- CRYPTO_set_locking_callback(_openssl_locking_cb);
+ openssl_mutexes_[i] = tor_mutex_new();
+ CRYPTO_set_locking_callback(openssl_locking_cb_);
CRYPTO_set_id_callback(tor_get_thread_id);
- 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);
+ 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_);
return 0;
}
#else
@@ -3049,18 +3026,19 @@ crypto_global_cleanup(void)
CONF_modules_unload(1);
CRYPTO_cleanup_all_ex_data();
#ifdef TOR_IS_MULTITHREADED
- if (_n_openssl_mutexes) {
- int n = _n_openssl_mutexes;
- tor_mutex_t **ms = _openssl_mutexes;
+ if (n_openssl_mutexes_) {
+ int n = n_openssl_mutexes_;
+ tor_mutex_t **ms = openssl_mutexes_;
int i;
- _openssl_mutexes = NULL;
- _n_openssl_mutexes = 0;
+ openssl_mutexes_ = NULL;
+ n_openssl_mutexes_ = 0;
for (i=0;i<n;++i) {
tor_mutex_free(ms[i]);
}
tor_free(ms);
}
#endif
+ tor_free(crypto_openssl_version_str);
return 0;
}