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.c850
1 files changed, 196 insertions, 654 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 8402ca079a..57981f9a00 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -13,10 +13,7 @@
#include "orconfig.h"
#ifdef _WIN32
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
-#endif
-#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
#include <windows.h>
#include <wincrypt.h>
/* Windows defines this; so does OpenSSL 0.9.8h and later. We don't actually
@@ -24,13 +21,24 @@
#undef OCSP_RESPONSE
#endif
+#include <openssl/opensslv.h>
+
+#define CRYPTO_PRIVATE
+#include "crypto.h"
+#include "crypto_curve25519.h"
+#include "crypto_ed25519.h"
+#include "crypto_format.h"
+
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0)
+#error "We require OpenSSL >= 1.0.0"
+#endif
+
#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/opensslv.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/conf.h>
@@ -49,18 +57,13 @@
#include <sys/fcntl.h>
#endif
-#define CRYPTO_PRIVATE
-#include "crypto.h"
-#include "../common/torlog.h"
+#include "torlog.h"
#include "aes.h"
-#include "../common/util.h"
+#include "util.h"
#include "container.h"
#include "compat.h"
#include "sandbox.h"
-
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
-#error "We require OpenSSL >= 0.9.8"
-#endif
+#include "util_format.h"
#ifdef ANDROID
/* Android's OpenSSL seems to have removed all of its Engine support. */
@@ -300,19 +303,15 @@ crypto_early_init(void)
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());
- }
-
crypto_force_rand_ssleay();
- if (crypto_seed_rng(1) < 0)
+ if (crypto_seed_rng() < 0)
return -1;
if (crypto_init_siphash_key() < 0)
return -1;
+
+ curve25519_init();
+ ed25519_init();
}
return 0;
}
@@ -391,7 +390,7 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
}
if (crypto_force_rand_ssleay()) {
- if (crypto_seed_rng(1) < 0)
+ if (crypto_seed_rng() < 0)
return -1;
}
@@ -405,7 +404,11 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
void
crypto_thread_cleanup(void)
{
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
+ ERR_remove_thread_state(NULL);
+#else
ERR_remove_state(0);
+#endif
}
/** used by tortls.c: wrap an RSA* in a crypto_pk_t. */
@@ -830,7 +833,7 @@ crypto_pk_public_exponent_ok(crypto_pk_t *env)
* Note that this may leak information about the keys through timing.
*/
int
-crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b)
+crypto_pk_cmp_keys(const crypto_pk_t *a, const crypto_pk_t *b)
{
int result;
char a_is_non_null = (a != NULL) && (a->key != NULL);
@@ -856,19 +859,19 @@ crypto_pk_cmp_keys(crypto_pk_t *a, crypto_pk_t *b)
* Note that this may leak information about the keys through timing.
*/
int
-crypto_pk_eq_keys(crypto_pk_t *a, crypto_pk_t *b)
+crypto_pk_eq_keys(const crypto_pk_t *a, const 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)
+crypto_pk_keysize(const crypto_pk_t *env)
{
tor_assert(env);
tor_assert(env->key);
- return (size_t) RSA_size(env->key);
+ return (size_t) RSA_size((RSA*)env->key);
}
/** Return the size of the public key modulus of <b>env</b>, in bits. */
@@ -997,7 +1000,7 @@ crypto_pk_private_decrypt(crypto_pk_t *env, char *to,
* at least the length of the modulus of <b>env</b>.
*/
int
-crypto_pk_public_checksig(crypto_pk_t *env, char *to,
+crypto_pk_public_checksig(const crypto_pk_t *env, char *to,
size_t tolen,
const char *from, size_t fromlen)
{
@@ -1069,7 +1072,7 @@ crypto_pk_public_checksig_digest(crypto_pk_t *env, const char *data,
* at least the length of the modulus of <b>env</b>.
*/
int
-crypto_pk_private_sign(crypto_pk_t *env, char *to, size_t tolen,
+crypto_pk_private_sign(const crypto_pk_t *env, char *to, size_t tolen,
const char *from, size_t fromlen)
{
int r;
@@ -1084,7 +1087,7 @@ crypto_pk_private_sign(crypto_pk_t *env, char *to, size_t tolen,
r = RSA_private_encrypt((int)fromlen,
(unsigned char*)from, (unsigned char*)to,
- env->key, RSA_PKCS1_PADDING);
+ (RSA*)env->key, RSA_PKCS1_PADDING);
if (r<0) {
crypto_log_errors(LOG_WARN, "generating RSA signature");
return -1;
@@ -1298,7 +1301,7 @@ crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out)
unsigned char *buf = NULL;
int len;
- len = i2d_RSAPublicKey(pk->key, &buf);
+ len = i2d_RSAPublicKey((RSA*)pk->key, &buf);
if (len < 0 || buf == NULL)
return -1;
if (crypto_digest(digest_out, (char*)buf, len) < 0) {
@@ -1397,6 +1400,78 @@ crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out)
return 0;
}
+/** Given a crypto_pk_t <b>pk</b>, allocate a new buffer containing the
+ * Base64 encoding of the DER representation of the private key as a NUL
+ * terminated string, and return it via <b>priv_out</b>. Return 0 on
+ * sucess, -1 on failure.
+ *
+ * It is the caller's responsibility to sanitize and free the resulting buffer.
+ */
+int
+crypto_pk_base64_encode(const crypto_pk_t *pk, char **priv_out)
+{
+ unsigned char *der = NULL;
+ int der_len;
+ int ret = -1;
+
+ *priv_out = NULL;
+
+ der_len = i2d_RSAPrivateKey(pk->key, &der);
+ if (der_len < 0 || der == NULL)
+ return ret;
+
+ size_t priv_len = base64_encode_size(der_len, 0) + 1;
+ char *priv = tor_malloc_zero(priv_len);
+ if (base64_encode(priv, priv_len, (char *)der, der_len, 0) >= 0) {
+ *priv_out = priv;
+ ret = 0;
+ } else {
+ tor_free(priv);
+ }
+
+ memwipe(der, 0, der_len);
+ OPENSSL_free(der);
+ return ret;
+}
+
+/** Given a string containing the Base64 encoded DER representation of the
+ * private key <b>str</b>, decode and return the result on success, or NULL
+ * on failure.
+ */
+crypto_pk_t *
+crypto_pk_base64_decode(const char *str, size_t len)
+{
+ crypto_pk_t *pk = NULL;
+
+ char *der = tor_malloc_zero(len + 1);
+ int der_len = base64_decode(der, len, str, len);
+ if (der_len <= 0) {
+ log_warn(LD_CRYPTO, "Stored RSA private key seems corrupted (base64).");
+ goto out;
+ }
+
+ const unsigned char *dp = (unsigned char*)der; /* Shut the compiler up. */
+ RSA *rsa = d2i_RSAPrivateKey(NULL, &dp, der_len);
+ if (!rsa) {
+ crypto_log_errors(LOG_WARN, "decoding private key");
+ goto out;
+ }
+
+ pk = crypto_new_pk_from_rsa_(rsa);
+
+ /* Make sure it's valid. */
+ if (crypto_pk_check_key(pk) <= 0) {
+ crypto_pk_free(pk);
+ pk = NULL;
+ goto out;
+ }
+
+ out:
+ memwipe(der, 0, len + 1);
+ tor_free(der);
+ return pk;
+}
+
/* symmetric crypto */
/** Return a pointer to the key set for the cipher in <b>env</b>.
@@ -1724,7 +1799,24 @@ crypto_digest_assign(crypto_digest_t *into,
* <b>out_len</b> must be \<= DIGEST256_LEN. */
void
crypto_digest_smartlist(char *digest_out, size_t len_out,
- const smartlist_t *lst, const char *append,
+ const smartlist_t *lst,
+ const char *append,
+ digest_algorithm_t alg)
+{
+ crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg);
+}
+
+/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
+ * at <b>digest_out</b> to the hash of the concatenation of: the
+ * optional string <b>prepend</b>, those strings,
+ * and the optional string <b>append</b>, computed with the algorithm
+ * <b>alg</b>.
+ * <b>out_len</b> must be \<= DIGEST256_LEN. */
+void
+crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
+ const char *prepend,
+ const smartlist_t *lst,
+ const char *append,
digest_algorithm_t alg)
{
crypto_digest_t *d;
@@ -1732,6 +1824,8 @@ crypto_digest_smartlist(char *digest_out, size_t len_out,
d = crypto_digest_new();
else
d = crypto_digest256_new(alg);
+ if (prepend)
+ crypto_digest_add_bytes(d, prepend, strlen(prepend));
SMARTLIST_FOREACH(lst, const char *, cp,
crypto_digest_add_bytes(d, cp, strlen(cp)));
if (append)
@@ -1768,235 +1862,12 @@ static BIGNUM *dh_param_p_tls = NULL;
/** Shared G parameter for our DH key exchanges. */
static BIGNUM *dh_param_g = NULL;
-/** Generate and return a reasonable and safe DH parameter p. */
-static BIGNUM *
-crypto_generate_dynamic_dh_modulus(void)
-{
- BIGNUM *dynamic_dh_modulus;
- DH *dh_parameters;
- int r, dh_codes;
- char *s;
-
- dynamic_dh_modulus = BN_new();
- tor_assert(dynamic_dh_modulus);
-
- dh_parameters = DH_new();
- tor_assert(dh_parameters);
-
- r = DH_generate_parameters_ex(dh_parameters,
- DH_BYTES*8, DH_GENERATOR, NULL);
- tor_assert(r == 0);
-
- r = DH_check(dh_parameters, &dh_codes);
- tor_assert(r && !dh_codes);
-
- BN_copy(dynamic_dh_modulus, dh_parameters->p);
- tor_assert(dynamic_dh_modulus);
-
- DH_free(dh_parameters);
-
- { /* log the dynamic DH modulus: */
- s = BN_bn2hex(dynamic_dh_modulus);
- tor_assert(s);
- log_info(LD_OR, "Dynamic DH modulus generated: [%s]", s);
- OPENSSL_free(s);
- }
-
- return dynamic_dh_modulus;
-}
-
-/** Store our dynamic DH modulus (and its group parameters) to
- <b>fname</b> for future use. */
-static int
-crypto_store_dynamic_dh_modulus(const char *fname)
-{
- int len, new_len;
- DH *dh = NULL;
- unsigned char *dh_string_repr = NULL;
- char *base64_encoded_dh = NULL;
- char *file_string = NULL;
- int retval = -1;
- static const char file_header[] = "# This file contains stored Diffie-"
- "Hellman parameters for future use.\n# You *do not* need to edit this "
- "file.\n\n";
-
- tor_assert(fname);
-
- if (!dh_param_p_tls) {
- log_info(LD_CRYPTO, "Tried to store a DH modulus that does not exist.");
- goto done;
- }
-
- if (!(dh = DH_new()))
- goto done;
- if (!(dh->p = BN_dup(dh_param_p_tls)))
- goto done;
- if (!(dh->g = BN_new()))
- goto done;
- if (!BN_set_word(dh->g, DH_GENERATOR))
- goto done;
-
- len = i2d_DHparams(dh, &dh_string_repr);
- if ((len < 0) || (dh_string_repr == NULL)) {
- log_warn(LD_CRYPTO, "Error occured while DER encoding DH modulus (2).");
- goto done;
- }
-
- base64_encoded_dh = tor_calloc(len, 2); /* should be enough */
- new_len = base64_encode(base64_encoded_dh, len * 2,
- (char *)dh_string_repr, len);
- if (new_len < 0) {
- log_warn(LD_CRYPTO, "Error occured while base64-encoding DH modulus.");
- goto done;
- }
-
- /* concatenate file header and the dh parameters blob */
- new_len = tor_asprintf(&file_string, "%s%s", file_header, base64_encoded_dh);
-
- /* write to file */
- if (write_bytes_to_new_file(fname, file_string, new_len, 0) < 0) {
- log_info(LD_CRYPTO, "'%s' was already occupied.", fname);
- goto done;
- }
-
- retval = 0;
-
- done:
- if (dh)
- DH_free(dh);
- if (dh_string_repr)
- OPENSSL_free(dh_string_repr);
- tor_free(base64_encoded_dh);
- tor_free(file_string);
-
- return retval;
-}
-
-/** Return the dynamic DH modulus stored in <b>fname</b>. If there is no
- dynamic DH modulus stored in <b>fname</b>, return NULL. */
-static BIGNUM *
-crypto_get_stored_dynamic_dh_modulus(const char *fname)
-{
- int retval;
- char *contents = NULL;
- const char *contents_tmp = NULL;
- int dh_codes;
- DH *stored_dh = NULL;
- BIGNUM *dynamic_dh_modulus = NULL;
- int length = 0;
- unsigned char *base64_decoded_dh = NULL;
- const unsigned char *cp = NULL;
-
- tor_assert(fname);
-
- contents = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL);
- if (!contents) {
- log_info(LD_CRYPTO, "Could not open file '%s'", fname);
- goto done; /*usually means that ENOENT. don't try to move file to broken.*/
- }
-
- /* skip the file header */
- contents_tmp = eat_whitespace(contents);
- if (!*contents_tmp) {
- log_warn(LD_CRYPTO, "Stored dynamic DH modulus file "
- "seems corrupted (eat_whitespace).");
- goto err;
- }
-
- /* 'fname' contains the DH parameters stored in base64-ed DER
- * format. We are only interested in the DH modulus.
- * NOTE: We allocate more storage here than we need. Since we're already
- * doing that, we can also add 1 byte extra to appease Coverity's
- * scanner. */
-
- cp = base64_decoded_dh = tor_malloc_zero(strlen(contents_tmp) + 1);
- length = base64_decode((char *)base64_decoded_dh, strlen(contents_tmp),
- contents_tmp, strlen(contents_tmp));
- if (length < 0) {
- log_warn(LD_CRYPTO, "Stored dynamic DH modulus seems corrupted (base64).");
- goto err;
- }
-
- stored_dh = d2i_DHparams(NULL, &cp, length);
- if ((!stored_dh) || (cp - base64_decoded_dh != length)) {
- log_warn(LD_CRYPTO, "Stored dynamic DH modulus seems corrupted (d2i).");
- goto err;
- }
-
- { /* check the cryptographic qualities of the stored dynamic DH modulus: */
- retval = DH_check(stored_dh, &dh_codes);
- if (!retval || dh_codes) {
- log_warn(LD_CRYPTO, "Stored dynamic DH modulus is not a safe prime.");
- goto err;
- }
-
- retval = DH_size(stored_dh);
- if (retval < DH_BYTES) {
- log_warn(LD_CRYPTO, "Stored dynamic DH modulus is smaller "
- "than '%d' bits.", DH_BYTES*8);
- goto err;
- }
-
- if (!BN_is_word(stored_dh->g, 2)) {
- log_warn(LD_CRYPTO, "Stored dynamic DH parameters do not use '2' "
- "as the group generator.");
- goto err;
- }
- }
-
- { /* log the dynamic DH modulus: */
- char *s = BN_bn2hex(stored_dh->p);
- tor_assert(s);
- log_info(LD_OR, "Found stored dynamic DH modulus: [%s]", s);
- OPENSSL_free(s);
- }
-
- goto done;
-
- err:
-
- {
- /* move broken prime to $filename.broken */
- char *fname_new=NULL;
- tor_asprintf(&fname_new, "%s.broken", fname);
-
- log_warn(LD_CRYPTO, "Moving broken dynamic DH prime to '%s'.", fname_new);
-
- if (replace_file(fname, fname_new))
- log_notice(LD_CRYPTO, "Error while moving '%s' to '%s'.",
- fname, fname_new);
-
- tor_free(fname_new);
- }
-
- if (stored_dh) {
- DH_free(stored_dh);
- stored_dh = NULL;
- }
-
- done:
- tor_free(contents);
- tor_free(base64_decoded_dh);
-
- if (stored_dh) {
- dynamic_dh_modulus = BN_dup(stored_dh->p);
- DH_free(stored_dh);
- }
-
- return dynamic_dh_modulus;
-}
-
-/** Set the global TLS Diffie-Hellman modulus.
- * If <b>dynamic_dh_modulus_fname</b> is set, try to read a dynamic DH modulus
- * off it and use it as the DH modulus. If that's not possible,
- * generate a new dynamic DH modulus.
- * If <b>dynamic_dh_modulus_fname</b> is NULL, use the Apache mod_ssl DH
+/** Set the global TLS Diffie-Hellman modulus. Use the Apache mod_ssl DH
* modulus. */
void
-crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname)
+crypto_set_tls_dh_prime(void)
{
BIGNUM *tls_prime = NULL;
- int store_dh_prime_afterwards = 0;
int r;
/* If the space is occupied, free the previous TLS DH prime */
@@ -2005,44 +1876,24 @@ crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname)
dh_param_p_tls = NULL;
}
- if (dynamic_dh_modulus_fname) { /* use dynamic DH modulus: */
- log_info(LD_OR, "Using stored dynamic DH modulus.");
- tls_prime = crypto_get_stored_dynamic_dh_modulus(dynamic_dh_modulus_fname);
-
- if (!tls_prime) {
- log_notice(LD_OR, "Generating fresh dynamic DH modulus. "
- "This might take a while...");
- tls_prime = crypto_generate_dynamic_dh_modulus();
+ tls_prime = BN_new();
+ tor_assert(tls_prime);
- store_dh_prime_afterwards++;
- }
- } else { /* use the static DH prime modulus used by Apache in mod_ssl: */
- tls_prime = BN_new();
- tor_assert(tls_prime);
-
- /* This is the 1024-bit safe prime that Apache uses for its DH stuff; see
- * modules/ssl/ssl_engine_dh.c; Apache also uses a generator of 2 with this
- * prime.
- */
- r =BN_hex2bn(&tls_prime,
- "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98"
- "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A"
- "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7"
- "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68"
- "B0E7393E0F24218EB3");
- tor_assert(r);
- }
+ /* This is the 1024-bit safe prime that Apache uses for its DH stuff; see
+ * modules/ssl/ssl_engine_dh.c; Apache also uses a generator of 2 with this
+ * prime.
+ */
+ r = BN_hex2bn(&tls_prime,
+ "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98"
+ "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A"
+ "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7"
+ "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68"
+ "B0E7393E0F24218EB3");
+ tor_assert(r);
tor_assert(tls_prime);
dh_param_p_tls = tls_prime;
-
- if (store_dh_prime_afterwards)
- /* save the new dynamic DH modulus to disk. */
- if (crypto_store_dynamic_dh_modulus(dynamic_dh_modulus_fname)) {
- log_notice(LD_CRYPTO, "Failed while storing dynamic DH modulus. "
- "Make sure your data directory is sane.");
- }
}
/** Initialize dh_param_p and dh_param_g if they are not already
@@ -2079,10 +1930,8 @@ init_dh_param(void)
dh_param_p = circuit_dh_prime;
dh_param_g = generator;
- /* Ensure that we have TLS DH parameters set up, too, even if we're
- going to change them soon. */
if (!dh_param_p_tls) {
- crypto_set_tls_dh_prime(NULL);
+ crypto_set_tls_dh_prime();
}
}
@@ -2134,6 +1983,8 @@ crypto_dh_t *
crypto_dh_dup(const crypto_dh_t *dh)
{
crypto_dh_t *dh_new = tor_malloc_zero(sizeof(crypto_dh_t));
+ tor_assert(dh);
+ tor_assert(dh->dh);
dh_new->dh = dh->dh;
DH_up_ref(dh->dh);
return dh_new;
@@ -2419,15 +2270,6 @@ crypto_dh_free(crypto_dh_t *dh)
* work for us too. */
#define ADD_ENTROPY 32
-/** True iff it's safe to use RAND_poll after setup.
- *
- * Versions of OpenSSL prior to 0.9.7k and 0.9.8c had a bug where RAND_poll
- * would allocate an fd_set on the stack, open a new file, and try to FD_SET
- * 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,8,'c'))
-
/** Set the seed of the weak RNG to a random value. */
void
crypto_seed_weak_rng(tor_weak_rng_t *rng)
@@ -2497,7 +2339,7 @@ crypto_strongest_rand(uint8_t *out, size_t out_len)
* have not yet allocated a bunch of fds. Return 0 on success, -1 on failure.
*/
int
-crypto_seed_rng(int startup)
+crypto_seed_rng(void)
{
int rand_poll_ok = 0, load_entropy_ok = 0;
uint8_t buf[ADD_ENTROPY];
@@ -2505,11 +2347,9 @@ crypto_seed_rng(int startup)
/* OpenSSL has a RAND_poll function that knows about more kinds of
* entropy than we do. We'll try calling that, *and* calling our own entropy
* functions. If one succeeds, we'll accept the RNG as seeded. */
- if (startup || RAND_POLL_IS_SAFE) {
- rand_poll_ok = RAND_poll();
- if (rand_poll_ok == 0)
- log_warn(LD_CRYPTO, "RAND_poll() failed.");
- }
+ rand_poll_ok = RAND_poll();
+ if (rand_poll_ok == 0)
+ log_warn(LD_CRYPTO, "RAND_poll() failed.");
load_entropy_ok = !crypto_strongest_rand(buf, sizeof(buf));
if (load_entropy_ok) {
@@ -2525,11 +2365,20 @@ crypto_seed_rng(int startup)
}
/** Write <b>n</b> bytes of strong random data to <b>to</b>. Return 0 on
- * success, -1 on failure.
+ * success, -1 on failure, with support for mocking for unit tests.
*/
MOCK_IMPL(int,
crypto_rand, (char *to, size_t n))
{
+ return crypto_rand_unmocked(to, n);
+}
+
+/** Write <b>n</b> bytes of strong random data to <b>to</b>. Return 0 on
+ * success, -1 on failure. Most callers will want crypto_rand instead.
+ */
+int
+crypto_rand_unmocked(char *to, size_t n)
+{
int r;
tor_assert(n < INT_MAX);
tor_assert(to);
@@ -2562,8 +2411,41 @@ crypto_rand_int(unsigned int max)
}
}
+/** Return a pseudorandom integer, chosen uniformly from the values <i>i</i>
+ * such that <b>min</b> &lt;= <i>i</i> &lt <b>max</b>.
+ *
+ * <b>min</b> MUST be in range [0, <b>max</b>).
+ * <b>max</b> MUST be in range (min, INT_MAX].
+ */
+int
+crypto_rand_int_range(unsigned int min, unsigned int max)
+{
+ tor_assert(min < max);
+ tor_assert(max <= INT_MAX);
+
+ /* The overflow is avoided here because crypto_rand_int() returns a value
+ * between 0 and (max - min) inclusive. */
+ return min + crypto_rand_int(max - min);
+}
+
+/** As crypto_rand_int_range, but supports uint64_t. */
+uint64_t
+crypto_rand_uint64_range(uint64_t min, uint64_t max)
+{
+ tor_assert(min < max);
+ return min + crypto_rand_uint64(max - min);
+}
+
+/** As crypto_rand_int_range, but supports time_t. */
+time_t
+crypto_rand_time_range(time_t min, time_t max)
+{
+ tor_assert(min < max);
+ return min + (time_t)crypto_rand_uint64(max - min);
+}
+
/** Return a pseudorandom 64-bit integer, chosen uniformly from the values
- * between 0 and <b>max</b>-1. */
+ * between 0 and <b>max</b>-1 inclusive. */
uint64_t
crypto_rand_uint64(uint64_t max)
{
@@ -2624,7 +2506,7 @@ crypto_random_hostname(int min_rand_len, int max_rand_len, const char *prefix,
if (min_rand_len > max_rand_len)
min_rand_len = max_rand_len;
- randlen = min_rand_len + crypto_rand_int(max_rand_len - min_rand_len + 1);
+ randlen = crypto_rand_int_range(min_rand_len, max_rand_len+1);
prefixlen = strlen(prefix);
resultlen = prefixlen + strlen(suffix) + randlen + 16;
@@ -2671,344 +2553,6 @@ smartlist_shuffle(smartlist_t *sl)
}
}
-/** Base64 encode <b>srclen</b> bytes of data from <b>src</b>. Write
- * the result into <b>dest</b>, if it will fit within <b>destlen</b>
- * bytes. Return the number of bytes written on success; -1 if
- * destlen is too short, or other failure.
- */
-int
-base64_encode(char *dest, size_t destlen, const char *src, size_t srclen)
-{
- /* FFFF we might want to rewrite this along the lines of base64_decode, if
- * it ever shows up in the profile. */
- EVP_ENCODE_CTX ctx;
- int len, ret;
- tor_assert(srclen < INT_MAX);
-
- /* 48 bytes of input -> 64 bytes of output plus newline.
- Plus one more byte, in case I'm wrong.
- */
- if (destlen < ((srclen/48)+1)*66)
- return -1;
- if (destlen > SIZE_T_CEILING)
- return -1;
-
- EVP_EncodeInit(&ctx);
- EVP_EncodeUpdate(&ctx, (unsigned char*)dest, &len,
- (unsigned char*)src, (int)srclen);
- EVP_EncodeFinal(&ctx, (unsigned char*)(dest+len), &ret);
- ret += len;
- return ret;
-}
-
-/** @{ */
-/** Special values used for the base64_decode_table */
-#define X 255
-#define SP 64
-#define PAD 65
-/** @} */
-/** Internal table mapping byte values to what they represent in base64.
- * Numbers 0..63 are 6-bit integers. SPs are spaces, and should be
- * skipped. Xs are invalid and must not appear in base64. PAD indicates
- * end-of-string. */
-static const uint8_t base64_decode_table[256] = {
- X, X, X, X, X, X, X, X, X, SP, SP, SP, X, SP, X, X, /* */
- X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
- SP, X, X, X, X, X, X, X, X, X, X, 62, X, X, X, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, X, X, X, PAD, X, X,
- X, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, X, X, X, X, X,
- X, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, X, X, X, X, X,
- X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
- X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
- X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
- X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
- X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
- X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
- X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
- X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
-};
-
-/** Base64 decode <b>srclen</b> bytes of data from <b>src</b>. Write
- * the result into <b>dest</b>, if it will fit within <b>destlen</b>
- * bytes. Return the number of bytes written on success; -1 if
- * destlen is too short, or other failure.
- *
- * NOTE 1: destlen is checked conservatively, as though srclen contained no
- * spaces or padding.
- *
- * NOTE 2: This implementation does not check for the correct number of
- * padding "=" characters at the end of the string, and does not check
- * for internal padding characters.
- */
-int
-base64_decode(char *dest, size_t destlen, const char *src, size_t srclen)
-{
-#ifdef USE_OPENSSL_BASE64
- EVP_ENCODE_CTX ctx;
- int len, ret;
- /* 64 bytes of input -> *up to* 48 bytes of output.
- Plus one more byte, in case I'm wrong.
- */
- if (destlen < ((srclen/64)+1)*49)
- return -1;
- if (destlen > SIZE_T_CEILING)
- return -1;
-
- memset(dest, 0, destlen);
-
- EVP_DecodeInit(&ctx);
- EVP_DecodeUpdate(&ctx, (unsigned char*)dest, &len,
- (unsigned char*)src, srclen);
- EVP_DecodeFinal(&ctx, (unsigned char*)dest, &ret);
- ret += len;
- return ret;
-#else
- const char *eos = src+srclen;
- uint32_t n=0;
- int n_idx=0;
- char *dest_orig = dest;
-
- /* Max number of bits == srclen*6.
- * Number of bytes required to hold all bits == (srclen*6)/8.
- * Yes, we want to round down: anything that hangs over the end of a
- * byte is padding. */
- if (destlen < (srclen*3)/4)
- return -1;
- if (destlen > SIZE_T_CEILING)
- return -1;
-
- memset(dest, 0, destlen);
-
- /* Iterate over all the bytes in src. Each one will add 0 or 6 bits to the
- * value we're decoding. Accumulate bits in <b>n</b>, and whenever we have
- * 24 bits, batch them into 3 bytes and flush those bytes to dest.
- */
- for ( ; src < eos; ++src) {
- unsigned char c = (unsigned char) *src;
- uint8_t v = base64_decode_table[c];
- switch (v) {
- case X:
- /* This character isn't allowed in base64. */
- return -1;
- case SP:
- /* This character is whitespace, and has no effect. */
- continue;
- case PAD:
- /* We've hit an = character: the data is over. */
- goto end_of_loop;
- default:
- /* We have an actual 6-bit value. Append it to the bits in n. */
- n = (n<<6) | v;
- if ((++n_idx) == 4) {
- /* We've accumulated 24 bits in n. Flush them. */
- *dest++ = (n>>16);
- *dest++ = (n>>8) & 0xff;
- *dest++ = (n) & 0xff;
- n_idx = 0;
- n = 0;
- }
- }
- }
- end_of_loop:
- /* If we have leftover bits, we need to cope. */
- switch (n_idx) {
- case 0:
- default:
- /* No leftover bits. We win. */
- break;
- case 1:
- /* 6 leftover bits. That's invalid; we can't form a byte out of that. */
- return -1;
- case 2:
- /* 12 leftover bits: The last 4 are padding and the first 8 are data. */
- *dest++ = n >> 4;
- break;
- case 3:
- /* 18 leftover bits: The last 2 are padding and the first 16 are data. */
- *dest++ = n >> 10;
- *dest++ = n >> 2;
- }
-
- tor_assert((dest-dest_orig) <= (ssize_t)destlen);
- tor_assert((dest-dest_orig) <= INT_MAX);
-
- return (int)(dest-dest_orig);
-#endif
-}
-#undef X
-#undef SP
-#undef PAD
-
-/** Base64 encode DIGEST_LINE bytes from <b>digest</b>, remove the trailing =
- * and newline characters, and store the nul-terminated result in the first
- * BASE64_DIGEST_LEN+1 bytes of <b>d64</b>. */
-int
-digest_to_base64(char *d64, const char *digest)
-{
- char buf[256];
- base64_encode(buf, sizeof(buf), digest, DIGEST_LEN);
- buf[BASE64_DIGEST_LEN] = '\0';
- memcpy(d64, buf, BASE64_DIGEST_LEN+1);
- return 0;
-}
-
-/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
- * trailing newline or = characters), decode it and store the result in the
- * first DIGEST_LEN bytes at <b>digest</b>. */
-int
-digest_from_base64(char *digest, const char *d64)
-{
-#ifdef USE_OPENSSL_BASE64
- char buf_in[BASE64_DIGEST_LEN+3];
- char buf[256];
- if (strlen(d64) != BASE64_DIGEST_LEN)
- return -1;
- memcpy(buf_in, d64, BASE64_DIGEST_LEN);
- memcpy(buf_in+BASE64_DIGEST_LEN, "=\n\0", 3);
- if (base64_decode(buf, sizeof(buf), buf_in, strlen(buf_in)) != DIGEST_LEN)
- return -1;
- memcpy(digest, buf, DIGEST_LEN);
- return 0;
-#else
- if (base64_decode(digest, DIGEST_LEN, d64, strlen(d64)) == DIGEST_LEN)
- return 0;
- else
- return -1;
-#endif
-}
-
-/** Base64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the
- * trailing = and newline characters, and store the nul-terminated result in
- * the first BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>. */
-int
-digest256_to_base64(char *d64, const char *digest)
-{
- char buf[256];
- base64_encode(buf, sizeof(buf), digest, DIGEST256_LEN);
- buf[BASE64_DIGEST256_LEN] = '\0';
- memcpy(d64, buf, BASE64_DIGEST256_LEN+1);
- return 0;
-}
-
-/** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
- * trailing newline or = characters), decode it and store the result in the
- * first DIGEST256_LEN bytes at <b>digest</b>. */
-int
-digest256_from_base64(char *digest, const char *d64)
-{
-#ifdef USE_OPENSSL_BASE64
- char buf_in[BASE64_DIGEST256_LEN+3];
- char buf[256];
- if (strlen(d64) != BASE64_DIGEST256_LEN)
- return -1;
- memcpy(buf_in, d64, BASE64_DIGEST256_LEN);
- memcpy(buf_in+BASE64_DIGEST256_LEN, "=\n\0", 3);
- if (base64_decode(buf, sizeof(buf), buf_in, strlen(buf_in)) != DIGEST256_LEN)
- return -1;
- memcpy(digest, buf, DIGEST256_LEN);
- return 0;
-#else
- if (base64_decode(digest, DIGEST256_LEN, d64, strlen(d64)) == DIGEST256_LEN)
- return 0;
- else
- return -1;
-#endif
-}
-
-/** Implements base32 encoding as in RFC 4648. Limitation: Requires
- * that srclen*8 is a multiple of 5.
- */
-void
-base32_encode(char *dest, size_t destlen, const char *src, size_t srclen)
-{
- unsigned int i, v, u;
- size_t nbits = srclen * 8, bit;
-
- tor_assert(srclen < SIZE_T_CEILING/8);
- tor_assert((nbits%5) == 0); /* We need an even multiple of 5 bits. */
- tor_assert((nbits/5)+1 <= destlen); /* We need enough space. */
- tor_assert(destlen < SIZE_T_CEILING);
-
- for (i=0,bit=0; bit < nbits; ++i, bit+=5) {
- /* set v to the 16-bit value starting at src[bits/8], 0-padded. */
- v = ((uint8_t)src[bit/8]) << 8;
- if (bit+5<nbits) v += (uint8_t)src[(bit/8)+1];
- /* set u to the 5-bit value at the bit'th bit of src. */
- u = (v >> (11-(bit%8))) & 0x1F;
- dest[i] = BASE32_CHARS[u];
- }
- dest[i] = '\0';
-}
-
-/** Implements base32 decoding as in RFC 4648. Limitation: Requires
- * that srclen*5 is a multiple of 8. Returns 0 if successful, -1 otherwise.
- */
-int
-base32_decode(char *dest, size_t destlen, const char *src, size_t srclen)
-{
- /* XXXX we might want to rewrite this along the lines of base64_decode, if
- * it ever shows up in the profile. */
- unsigned int i;
- size_t nbits, j, bit;
- char *tmp;
- nbits = srclen * 5;
-
- tor_assert(srclen < SIZE_T_CEILING / 5);
- tor_assert((nbits%8) == 0); /* We need an even multiple of 8 bits. */
- tor_assert((nbits/8) <= destlen); /* We need enough space. */
- tor_assert(destlen < SIZE_T_CEILING);
-
- memset(dest, 0, destlen);
-
- /* Convert base32 encoded chars to the 5-bit values that they represent. */
- tmp = tor_malloc_zero(srclen);
- for (j = 0; j < srclen; ++j) {
- if (src[j] > 0x60 && src[j] < 0x7B) tmp[j] = src[j] - 0x61;
- else if (src[j] > 0x31 && src[j] < 0x38) tmp[j] = src[j] - 0x18;
- else if (src[j] > 0x40 && src[j] < 0x5B) tmp[j] = src[j] - 0x41;
- else {
- log_warn(LD_BUG, "illegal character in base32 encoded string");
- tor_free(tmp);
- return -1;
- }
- }
-
- /* Assemble result byte-wise by applying five possible cases. */
- for (i = 0, bit = 0; bit < nbits; ++i, bit += 8) {
- switch (bit % 40) {
- case 0:
- dest[i] = (((uint8_t)tmp[(bit/5)]) << 3) +
- (((uint8_t)tmp[(bit/5)+1]) >> 2);
- break;
- case 8:
- dest[i] = (((uint8_t)tmp[(bit/5)]) << 6) +
- (((uint8_t)tmp[(bit/5)+1]) << 1) +
- (((uint8_t)tmp[(bit/5)+2]) >> 4);
- break;
- case 16:
- dest[i] = (((uint8_t)tmp[(bit/5)]) << 4) +
- (((uint8_t)tmp[(bit/5)+1]) >> 1);
- break;
- case 24:
- dest[i] = (((uint8_t)tmp[(bit/5)]) << 7) +
- (((uint8_t)tmp[(bit/5)+1]) << 2) +
- (((uint8_t)tmp[(bit/5)+2]) >> 3);
- break;
- case 32:
- dest[i] = (((uint8_t)tmp[(bit/5)]) << 5) +
- ((uint8_t)tmp[(bit/5)+1]);
- break;
- }
- }
-
- memwipe(tmp, 0, srclen);
- tor_free(tmp);
- tmp = NULL;
- return 0;
-}
-
/**
* Destroy the <b>sz</b> bytes of data stored at <b>mem</b>, setting them to
* the value <b>byte</b>.
@@ -3129,13 +2673,11 @@ openssl_dynlock_destroy_cb_(struct CRYPTO_dynlock_value *v,
tor_free(v);
}
-#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0)
static void
tor_set_openssl_thread_id(CRYPTO_THREADID *threadid)
{
CRYPTO_THREADID_set_numeric(threadid, tor_get_thread_id());
}
-#endif
/** @{ */
/** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being
@@ -3150,11 +2692,7 @@ setup_openssl_threading(void)
for (i=0; i < n; ++i)
openssl_mutexes_[i] = tor_mutex_new();
CRYPTO_set_locking_callback(openssl_locking_cb_);
-#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0)
- CRYPTO_set_id_callback(tor_get_thread_id);
-#else
CRYPTO_THREADID_set_callback(tor_set_openssl_thread_id);
-#endif
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_);
@@ -3167,7 +2705,11 @@ int
crypto_global_cleanup(void)
{
EVP_cleanup();
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0)
+ ERR_remove_thread_state(NULL);
+#else
ERR_remove_state(0);
+#endif
ERR_free_strings();
if (dh_param_p)