diff options
Diffstat (limited to 'src/common/crypto.c')
-rw-r--r-- | src/common/crypto.c | 217 |
1 files changed, 151 insertions, 66 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c index f8495bb107..16536f3716 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2016, The Tor Project, Inc. */ + * Copyright (c) 2007-2017, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -20,7 +20,7 @@ /* Windows defines this; so does OpenSSL 0.9.8h and later. We don't actually * use either definition. */ #undef OCSP_RESPONSE -#endif +#endif /* defined(_WIN32) */ #define CRYPTO_PRIVATE #include "crypto.h" @@ -50,7 +50,7 @@ ENABLE_GCC_WARNING(redundant-decls) #else #pragma GCC diagnostic warning "-Wredundant-decls" #endif -#endif +#endif /* __GNUC__ && GCC_VERSION >= 402 */ #ifdef HAVE_CTYPE_H #include <ctype.h> @@ -101,7 +101,7 @@ ENABLE_GCC_WARNING(redundant-decls) * pointless, so let's not. */ #define NEW_THREAD_API -#endif +#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && ... */ /** Longest recognized */ #define MAX_DNS_LABEL_SIZE 63 @@ -114,7 +114,7 @@ ENABLE_GCC_WARNING(redundant-decls) static tor_mutex_t **openssl_mutexes_ = NULL; /** How many mutexes have we allocated for use by OpenSSL? */ static int n_openssl_mutexes_ = 0; -#endif +#endif /* !defined(NEW_THREAD_API) */ /** A public key, or a public/private key-pair. */ struct crypto_pk_t @@ -198,7 +198,7 @@ log_engine(const char *fn, ENGINE *e) log_info(LD_CRYPTO, "Using default implementation for %s", fn); } } -#endif +#endif /* !defined(DISABLE_ENGINES) */ #ifndef DISABLE_ENGINES /** Try to load an engine in a shared library via fully qualified path. @@ -218,7 +218,7 @@ try_load_engine(const char *path, const char *engine) } return e; } -#endif +#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 @@ -394,7 +394,7 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir) #else log_engine("ECDH", ENGINE_get_default_ECDH()); log_engine("ECDSA", ENGINE_get_default_ECDSA()); -#endif +#endif /* defined(OPENSSL_1_1_API) */ log_engine("RAND", ENGINE_get_default_RAND()); log_engine("RAND (which we will not use)", ENGINE_get_default_RAND()); log_engine("SHA1", ENGINE_get_digest_engine(NID_sha1)); @@ -412,7 +412,7 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir) log_engine("AES-256-GCM", ENGINE_get_cipher_engine(NID_aes_256_gcm)); #endif -#endif +#endif /* defined(DISABLE_ENGINES) */ } else { log_info(LD_CRYPTO, "NOT using OpenSSL engine support."); } @@ -450,9 +450,9 @@ crypto_pk_private_ok(const crypto_pk_t *k) const BIGNUM *p, *q; RSA_get0_factors(k->key, &p, &q); return p != NULL; /* XXX/yawning: Should we check q? */ -#else +#else /* !(defined(OPENSSL_1_1_API)) */ return k && k->key && k->key->p; -#endif +#endif /* defined(OPENSSL_1_1_API) */ } /** used by tortls.c: wrap an RSA* in a crypto_pk_t. */ @@ -467,7 +467,7 @@ crypto_new_pk_from_rsa_(RSA *rsa) return env; } -/** Helper, used by tor-checkkey.c and tor-gencert.c. Return the RSA from a +/** Helper, used by tor-gencert.c. Return the RSA from a * crypto_pk_t. */ RSA * crypto_pk_get_rsa_(crypto_pk_t *env) @@ -479,7 +479,7 @@ crypto_pk_get_rsa_(crypto_pk_t *env) * private is set, include the private-key portion of the key. Return a valid * pointer on success, and NULL on failure. */ MOCK_IMPL(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; @@ -516,7 +516,7 @@ crypto_dh_get_dh_(crypto_dh_t *dh) * be set. */ MOCK_IMPL(crypto_pk_t *, - crypto_pk_new,(void)) +crypto_pk_new,(void)) { RSA *rsa; @@ -606,7 +606,7 @@ crypto_cipher_free(crypto_cipher_t *env) * Return 0 on success, -1 on failure. */ MOCK_IMPL(int, - crypto_pk_generate_key_with_bits,(crypto_pk_t *env, int bits)) +crypto_pk_generate_key_with_bits,(crypto_pk_t *env, int bits)) { tor_assert(env); @@ -899,7 +899,7 @@ crypto_pk_public_exponent_ok(crypto_pk_t *env) RSA_get0_key(env->key, &n, &e, &d); #else e = env->key->e; -#endif +#endif /* defined(OPENSSL_1_1_API) */ return BN_is_word(e, 65537); } @@ -933,7 +933,7 @@ crypto_pk_cmp_keys(const crypto_pk_t *a, const crypto_pk_t *b) a_e = a->key->e; b_n = b->key->n; b_e = b->key->e; -#endif +#endif /* defined(OPENSSL_1_1_API) */ tor_assert(a_n != NULL && a_e != NULL); tor_assert(b_n != NULL && b_e != NULL); @@ -982,10 +982,10 @@ crypto_pk_num_bits(crypto_pk_t *env) tor_assert(n != NULL); return RSA_bits(env->key); -#else +#else /* !(defined(OPENSSL_1_1_API)) */ tor_assert(env->key->n); return BN_num_bits(env->key->n); -#endif +#endif /* defined(OPENSSL_1_1_API) */ } /** Increase the reference count of <b>env</b>, and return it. @@ -1012,7 +1012,7 @@ crypto_pk_assign_(crypto_pk_t *dest, const crypto_pk_t *src) RSA_free(dest->key); dest->key = RSAPrivateKey_dup(src->key); } -#endif +#endif /* defined(TOR_UNIT_TESTS) */ /** Make a real honest-to-goodness copy of <b>env</b>, and return it. * Returns NULL on failure. */ @@ -1122,10 +1122,10 @@ crypto_pk_private_decrypt(crypto_pk_t *env, char *to, * <b>tolen</b> is the number of writable bytes in <b>to</b>, and must be * at least the length of the modulus of <b>env</b>. */ -int -crypto_pk_public_checksig(const crypto_pk_t *env, char *to, - size_t tolen, - const char *from, size_t fromlen) +MOCK_IMPL(int, +crypto_pk_public_checksig,(const crypto_pk_t *env, char *to, + size_t tolen, + const char *from, size_t fromlen)) { int r; tor_assert(env); @@ -1149,9 +1149,10 @@ crypto_pk_public_checksig(const crypto_pk_t *env, char *to, * in <b>env</b>. Return 0 if <b>sig</b> is a correct signature for * SHA1(data). Else return -1. */ -int -crypto_pk_public_checksig_digest(crypto_pk_t *env, const char *data, - size_t datalen, const char *sig, size_t siglen) +MOCK_IMPL(int, +crypto_pk_public_checksig_digest,(crypto_pk_t *env, const char *data, + size_t datalen, const char *sig, + size_t siglen)) { char digest[DIGEST_LEN]; char *buf; @@ -1252,9 +1253,12 @@ crypto_pk_private_sign_digest(crypto_pk_t *env, char *to, size_t tolen, * - The beginning of the source data prefixed with a 16-byte symmetric key, * padded and encrypted with the public key; followed by the rest of * the source data encrypted in AES-CTR mode with the symmetric key. + * + * NOTE that this format does not authenticate the symmetrically encrypted + * part of the data, and SHOULD NOT BE USED for new protocols. */ int -crypto_pk_public_hybrid_encrypt(crypto_pk_t *env, +crypto_pk_obsolete_public_hybrid_encrypt(crypto_pk_t *env, char *to, size_t tolen, const char *from, size_t fromlen, @@ -1316,10 +1320,14 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_t *env, return -1; } -/** Invert crypto_pk_public_hybrid_encrypt. Returns the number of bytes - * written on success, -1 on failure. */ +/** Invert crypto_pk_obsolete_public_hybrid_encrypt. Returns the number of + * bytes written on success, -1 on failure. + * + * NOTE that this format does not authenticate the symmetrically encrypted + * part of the data, and SHOULD NOT BE USED for new protocols. + */ int -crypto_pk_private_hybrid_decrypt(crypto_pk_t *env, +crypto_pk_obsolete_private_hybrid_decrypt(crypto_pk_t *env, char *to, size_t tolen, const char *from, @@ -1521,7 +1529,7 @@ crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out) if (crypto_pk_get_digest(pk, digest)) { return -1; } - if (crypto_digest(hashed_digest, digest, DIGEST_LEN)) { + if (crypto_digest(hashed_digest, digest, DIGEST_LEN) < 0) { return -1; } base16_encode(fp_out, FINGERPRINT_LEN + 1, hashed_digest, DIGEST_LEN); @@ -1715,19 +1723,21 @@ crypto_cipher_decrypt_with_iv(const char *key, /** Compute the SHA1 digest of the <b>len</b> bytes on data stored in * <b>m</b>. Write the DIGEST_LEN byte result into <b>digest</b>. - * Return 0 on success, 1 on failure. + * Return 0 on success, -1 on failure. */ int crypto_digest(char *digest, const char *m, size_t len) { tor_assert(m); tor_assert(digest); - return (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL); + if (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL) + return -1; + return 0; } /** Compute a 256-bit digest of <b>len</b> bytes in data stored in <b>m</b>, * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN256-byte result - * into <b>digest</b>. Return 0 on success, 1 on failure. */ + * into <b>digest</b>. Return 0 on success, -1 on failure. */ int crypto_digest256(char *digest, const char *m, size_t len, digest_algorithm_t algorithm) @@ -1735,16 +1745,22 @@ crypto_digest256(char *digest, const char *m, size_t len, tor_assert(m); tor_assert(digest); tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); + + int ret = 0; if (algorithm == DIGEST_SHA256) - return (SHA256((const uint8_t*)m,len,(uint8_t*)digest) == NULL); + ret = (SHA256((const uint8_t*)m,len,(uint8_t*)digest) != NULL); else - return (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len) - == -1); + ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len) + > -1); + + if (!ret) + return -1; + return 0; } /** Compute a 512-bit digest of <b>len</b> bytes in data stored in <b>m</b>, * using the algorithm <b>algorithm</b>. Write the DIGEST_LEN512-byte result - * into <b>digest</b>. Return 0 on success, 1 on failure. */ + * into <b>digest</b>. Return 0 on success, -1 on failure. */ int crypto_digest512(char *digest, const char *m, size_t len, digest_algorithm_t algorithm) @@ -1752,12 +1768,18 @@ crypto_digest512(char *digest, const char *m, size_t len, tor_assert(m); tor_assert(digest); tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); + + int ret = 0; if (algorithm == DIGEST_SHA512) - return (SHA512((const unsigned char*)m,len,(unsigned char*)digest) - == NULL); + ret = (SHA512((const unsigned char*)m,len,(unsigned char*)digest) + != NULL); else - return (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len) - == -1); + ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len) + > -1); + + if (!ret) + return -1; + return 0; } /** Set the common_digests_t in <b>ds_out</b> to contain every digest on the @@ -1791,8 +1813,8 @@ crypto_digest_algorithm_get_name(digest_algorithm_t alg) return "sha3-256"; case DIGEST_SHA3_512: return "sha3-512"; - default: // LCOV_EXCL_START + default: tor_fragile_assert(); return "??unknown_digest??"; // LCOV_EXCL_STOP @@ -1854,6 +1876,18 @@ struct crypto_digest_t { } d; }; +#ifdef TOR_UNIT_TESTS + +digest_algorithm_t +crypto_digest_get_algorithm(crypto_digest_t *digest) +{ + tor_assert(digest); + + return digest->algorithm; +} + +#endif /* defined(TOR_UNIT_TESTS) */ + /** * Return the number of bytes we need to malloc in order to get a * crypto_digest_t for <b>alg</b>, or the number of bytes we need to wipe @@ -1865,7 +1899,7 @@ crypto_digest_alloc_bytes(digest_algorithm_t alg) /* Helper: returns the number of bytes in the 'f' field of 'st' */ #define STRUCT_FIELD_SIZE(st, f) (sizeof( ((st*)0)->f )) /* Gives the length of crypto_digest_t through the end of the field 'd' */ -#define END_OF_FIELD(f) (STRUCT_OFFSET(crypto_digest_t, f) + \ +#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \ STRUCT_FIELD_SIZE(crypto_digest_t, f)) switch (alg) { case DIGEST_SHA1: @@ -2124,6 +2158,35 @@ crypto_hmac_sha256(char *hmac_out, tor_assert(rv); } +/** Compute a MAC using SHA3-256 of <b>msg_len</b> bytes in <b>msg</b> using a + * <b>key</b> of length <b>key_len</b> and a <b>salt</b> of length + * <b>salt_len</b>. Store the result of <b>len_out</b> bytes in in + * <b>mac_out</b>. This function can't fail. */ +void +crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out, + const uint8_t *key, size_t key_len, + const uint8_t *msg, size_t msg_len) +{ + crypto_digest_t *digest; + + const uint64_t key_len_netorder = tor_htonll(key_len); + + tor_assert(mac_out); + tor_assert(key); + tor_assert(msg); + + digest = crypto_digest256_new(DIGEST_SHA3_256); + + /* Order matters here that is any subsystem using this function should + * expect this very precise ordering in the MAC construction. */ + crypto_digest_add_bytes(digest, (const char *) &key_len_netorder, + sizeof(key_len_netorder)); + crypto_digest_add_bytes(digest, (const char *) key, key_len); + crypto_digest_add_bytes(digest, (const char *) msg, msg_len); + crypto_digest_get_digest(digest, (char *) mac_out, len_out); + crypto_digest_free(digest); +} + /** Internal state for a eXtendable-Output Function (XOF). */ struct crypto_xof_t { keccak_state s; @@ -2207,12 +2270,12 @@ crypto_validate_dh_params(const BIGNUM *p, const BIGNUM *g) goto out; if (!DH_set0_pqg(dh, dh_p, NULL, dh_g)) goto out; -#else +#else /* !(defined(OPENSSL_1_1_API)) */ if (!(dh->p = BN_dup(p))) goto out; if (!(dh->g = BN_dup(g))) goto out; -#endif +#endif /* defined(OPENSSL_1_1_API) */ /* Perform the validation. */ int codes = 0; @@ -2383,7 +2446,7 @@ crypto_dh_new(int dh_type) if (!DH_set_length(res->dh, DH_PRIVATE_KEY_BITS)) goto err; -#else +#else /* !(defined(OPENSSL_1_1_API)) */ if (dh_type == DH_TYPE_TLS) { if (!(res->dh->p = BN_dup(dh_param_p_tls))) goto err; @@ -2396,12 +2459,13 @@ crypto_dh_new(int dh_type) goto err; res->dh->length = DH_PRIVATE_KEY_BITS; -#endif +#endif /* defined(OPENSSL_1_1_API) */ return res; - err: + /* LCOV_EXCL_START * This error condition is only reached when an allocation fails */ + err: crypto_log_errors(LOG_WARN, "creating DH object"); if (res->dh) DH_free(res->dh); /* frees p and g too */ tor_free(res); @@ -2458,7 +2522,7 @@ crypto_dh_generate_public(crypto_dh_t *dh) "the-universe chances really do happen. Treating as a failure."); return -1; } -#else +#else /* !(defined(OPENSSL_1_1_API)) */ if (tor_check_dh_key(LOG_WARN, dh->dh->pub_key)<0) { /* LCOV_EXCL_START * If this happens, then openssl's DH implementation is busted. */ @@ -2471,7 +2535,7 @@ crypto_dh_generate_public(crypto_dh_t *dh) goto again; /* LCOV_EXCL_STOP */ } -#endif +#endif /* defined(OPENSSL_1_1_API) */ return 0; } @@ -2492,7 +2556,7 @@ crypto_dh_get_public(crypto_dh_t *dh, char *pubkey, size_t pubkey_len) DH_get0_key(dh->dh, &dh_pub, &dh_priv); #else dh_pub = dh->dh->pub_key; -#endif +#endif /* defined(OPENSSL_1_1_API) */ if (!dh_pub) { if (crypto_dh_generate_public(dh)<0) @@ -2643,7 +2707,7 @@ crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len, for (cp = key_out, i=0; cp < key_out+key_out_len; ++i, cp += DIGEST_LEN) { tmp[key_in_len] = i; - if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1)) + if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1) < 0) goto exit; memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out))); } @@ -2816,8 +2880,17 @@ crypto_strongest_rand_syscall(uint8_t *out, size_t out_len) tor_assert(errno != EAGAIN); tor_assert(errno != EINTR); - /* Probably ENOSYS. */ - log_warn(LD_CRYPTO, "Can't get entropy from getrandom()."); + /* Useful log message for errno. */ + if (errno == ENOSYS) { + log_warn(LD_CRYPTO, "Can't get entropy from getrandom()." + " You are running a version of Tor built to support" + " getrandom(), but the kernel doesn't implement this" + " function--probably because it is too old?"); + } else { + log_warn(LD_CRYPTO, "Can't get entropy from getrandom(): %s.", + strerror(errno)); + } + getrandom_works = 0; /* Don't bother trying again. */ return -1; /* LCOV_EXCL_STOP */ @@ -2835,7 +2908,7 @@ crypto_strongest_rand_syscall(uint8_t *out, size_t out_len) return getentropy(out, out_len); #else (void) out; -#endif +#endif /* defined(_WIN32) || ... */ /* This platform doesn't have a supported syscall based random. */ return -1; @@ -2859,7 +2932,7 @@ crypto_strongest_rand_fallback(uint8_t *out, size_t out_len) (void)out; (void)out_len; return -1; -#else +#else /* !(defined(_WIN32)) */ static const char *filenames[] = { "/dev/srandom", "/dev/urandom", "/dev/random", NULL }; @@ -2867,7 +2940,7 @@ crypto_strongest_rand_fallback(uint8_t *out, size_t out_len) size_t n; for (i = 0; filenames[i]; ++i) { - log_debug(LD_FS, "Opening %s for entropy", filenames[i]); + log_debug(LD_FS, "Considering %s for entropy", filenames[i]); fd = open(sandbox_intern_string(filenames[i]), O_RDONLY, 0); if (fd<0) continue; log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]); @@ -2887,7 +2960,7 @@ crypto_strongest_rand_fallback(uint8_t *out, size_t out_len) } return -1; -#endif +#endif /* defined(_WIN32) */ } /** Try to get <b>out_len</b> bytes of the strongest entropy we can generate, @@ -3136,7 +3209,7 @@ crypto_rand_double(void) #define UINT_MAX_AS_DOUBLE 1.8446744073709552e+19 #else #error SIZEOF_INT is neither 4 nor 8 -#endif +#endif /* SIZEOF_INT == 4 || ... */ return ((double)u) / UINT_MAX_AS_DOUBLE; } @@ -3265,7 +3338,7 @@ memwipe(void *mem, uint8_t byte, size_t sz) **/ OPENSSL_cleanse(mem, sz); -#endif +#endif /* defined(SecureZeroMemory) || defined(HAVE_SECUREZEROMEMORY) || ... */ /* Just in case some caller of memwipe() is relying on getting a buffer * filled with a particular value, fill the buffer. @@ -3307,7 +3380,7 @@ tor_set_openssl_thread_id(CRYPTO_THREADID *threadid) { CRYPTO_THREADID_set_numeric(threadid, tor_get_thread_id()); } -#endif +#endif /* !defined(NEW_THREAD_API) */ #if 0 /* This code is disabled, because OpenSSL never actually uses these callbacks. @@ -3357,7 +3430,7 @@ openssl_dynlock_destroy_cb_(struct CRYPTO_dynlock_value *v, tor_mutex_free(v->lock); tor_free(v); } -#endif +#endif /* 0 */ /** @{ */ /** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being @@ -3374,7 +3447,7 @@ setup_openssl_threading(void) openssl_mutexes_[i] = tor_mutex_new(); CRYPTO_set_locking_callback(openssl_locking_cb_); CRYPTO_THREADID_set_callback(tor_set_openssl_thread_id); -#endif +#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_); @@ -3421,7 +3494,7 @@ crypto_global_cleanup(void) } tor_free(ms); } -#endif +#endif /* !defined(NEW_THREAD_API) */ tor_free(crypto_openssl_version_str); tor_free(crypto_openssl_header_version_str); @@ -3430,3 +3503,15 @@ crypto_global_cleanup(void) /** @} */ +#ifdef USE_DMALLOC +/** Tell the crypto library to use Tor's allocation functions rather than + * calling libc's allocation functions directly. Return 0 on success, -1 + * on failure. */ +int +crypto_use_tor_alloc_functions(void) +{ + int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_); + return r ? 0 : -1; +} +#endif /* defined(USE_DMALLOC) */ + |