diff options
Diffstat (limited to 'src/common/crypto.c')
-rw-r--r-- | src/common/crypto.c | 187 |
1 files changed, 95 insertions, 92 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c index 940a756f61..9bdb1f41fa 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -56,6 +56,7 @@ #include "../common/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" @@ -114,7 +115,6 @@ crypto_get_rsa_padding_overhead(int padding) switch (padding) { case RSA_PKCS1_OAEP_PADDING: return PKCS1_OAEP_PADDING_OVERHEAD; - case RSA_PKCS1_PADDING: return PKCS1_PADDING_OVERHEAD; default: tor_assert(0); return -1; } } @@ -126,7 +126,6 @@ crypto_get_rsa_padding(int padding) { switch (padding) { - case PK_PKCS1_PADDING: return RSA_PKCS1_PADDING; case PK_PKCS1_OAEP_PADDING: return RSA_PKCS1_OAEP_PADDING; default: tor_assert(0); return -1; } @@ -197,6 +196,27 @@ try_load_engine(const char *path, const char *engine) } #endif +/* 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 * @@ -204,23 +224,24 @@ 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); + 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; +} + /** Initialize the crypto library. Return 0 on success, -1 on failure. */ int @@ -286,12 +307,29 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir) " setting default ciphers."); ENGINE_set_default(e, ENGINE_METHOD_ALL); } + /* Log, if available, the intersection of the set of algorithms + used by Tor and the set of algorithms available in the engine */ log_engine("RSA", ENGINE_get_default_RSA()); log_engine("DH", ENGINE_get_default_DH()); + log_engine("ECDH", ENGINE_get_default_ECDH()); + log_engine("ECDSA", ENGINE_get_default_ECDSA()); + 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)); - log_engine("3DES", ENGINE_get_cipher_engine(NID_des_ede3_ecb)); - log_engine("AES", ENGINE_get_cipher_engine(NID_aes_128_ecb)); + log_engine("3DES-CBC", ENGINE_get_cipher_engine(NID_des_ede3_cbc)); + log_engine("AES-128-ECB", ENGINE_get_cipher_engine(NID_aes_128_ecb)); + log_engine("AES-128-CBC", ENGINE_get_cipher_engine(NID_aes_128_cbc)); +#ifdef NID_aes_128_ctr + log_engine("AES-128-CTR", ENGINE_get_cipher_engine(NID_aes_128_ctr)); +#endif +#ifdef NID_aes_128_gcm + log_engine("AES-128-GCM", ENGINE_get_cipher_engine(NID_aes_128_gcm)); +#endif + log_engine("AES-256-CBC", ENGINE_get_cipher_engine(NID_aes_256_cbc)); +#ifdef NID_aes_256_gcm + log_engine("AES-256-GCM", ENGINE_get_cipher_engine(NID_aes_256_gcm)); +#endif + #endif } else { log_info(LD_CRYPTO, "NOT using OpenSSL engine support."); @@ -486,7 +524,7 @@ crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits) r = NULL; done: if (e) - BN_free(e); + BN_clear_free(e); if (r) RSA_free(r); } @@ -1161,22 +1199,21 @@ int crypto_pk_asn1_encode(crypto_pk_t *pk, char *dest, size_t dest_len) { int len; - unsigned char *buf, *cp; - len = i2d_RSAPublicKey(pk->key, NULL); - if (len < 0 || (size_t)len > dest_len || dest_len > SIZE_T_CEILING) + unsigned char *buf = NULL; + + len = i2d_RSAPublicKey(pk->key, &buf); + if (len < 0 || buf == NULL) return -1; - cp = buf = tor_malloc(len+1); - len = i2d_RSAPublicKey(pk->key, &cp); - if (len < 0) { - crypto_log_errors(LOG_WARN,"encoding public key"); - tor_free(buf); + + if ((size_t)len > dest_len || dest_len > SIZE_T_CEILING) { + OPENSSL_free(buf); return -1; } /* We don't encode directly into 'dest', because that would be illegal * type-punning. (C99 is smarter than me, C99 is smarter than me...) */ memcpy(dest,buf,len); - tor_free(buf); + OPENSSL_free(buf); return len; } @@ -1207,24 +1244,17 @@ crypto_pk_asn1_decode(const char *str, size_t len) int crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out) { - unsigned char *buf, *bufp; + unsigned char *buf = NULL; int len; - len = i2d_RSAPublicKey(pk->key, NULL); - if (len < 0) - return -1; - buf = bufp = tor_malloc(len+1); - len = i2d_RSAPublicKey(pk->key, &bufp); - if (len < 0) { - crypto_log_errors(LOG_WARN,"encoding public key"); - tor_free(buf); + len = i2d_RSAPublicKey(pk->key, &buf); + if (len < 0 || buf == NULL) return -1; - } if (crypto_digest(digest_out, (char*)buf, len) < 0) { - tor_free(buf); + OPENSSL_free(buf); return -1; } - tor_free(buf); + OPENSSL_free(buf); return 0; } @@ -1233,31 +1263,24 @@ crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out) int crypto_pk_get_all_digests(crypto_pk_t *pk, digests_t *digests_out) { - unsigned char *buf, *bufp; + unsigned char *buf = NULL; int len; - len = i2d_RSAPublicKey(pk->key, NULL); - if (len < 0) - return -1; - buf = bufp = tor_malloc(len+1); - len = i2d_RSAPublicKey(pk->key, &bufp); - if (len < 0) { - crypto_log_errors(LOG_WARN,"encoding public key"); - tor_free(buf); + len = i2d_RSAPublicKey(pk->key, &buf); + if (len < 0 || buf == NULL) return -1; - } if (crypto_digest_all(digests_out, (char*)buf, len) < 0) { - tor_free(buf); + OPENSSL_free(buf); return -1; } - tor_free(buf); + OPENSSL_free(buf); return 0; } /** Copy <b>in</b> to the <b>outlen</b>-byte buffer <b>out</b>, adding spaces * every four spaces. */ -/* static */ void -add_spaces_to_fp(char *out, size_t outlen, const char *in) +void +crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in) { int n = 0; char *end = out+outlen; @@ -1294,7 +1317,7 @@ crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space) } base16_encode(hexdigest,sizeof(hexdigest),digest,DIGEST_LEN); if (add_space) { - add_spaces_to_fp(fp_out, FINGERPRINT_LEN+1, hexdigest); + crypto_add_spaces_to_fp(fp_out, FINGERPRINT_LEN+1, hexdigest); } else { strncpy(fp_out, hexdigest, HEX_DIGEST_LEN+1); } @@ -1644,21 +1667,6 @@ crypto_digest_smartlist(char *digest_out, size_t len_out, crypto_digest_free(d); } -/** Compute the HMAC-SHA-1 of the <b>msg_len</b> bytes in <b>msg</b>, using - * the <b>key</b> of length <b>key_len</b>. Store the DIGEST_LEN-byte result - * in <b>hmac_out</b>. - */ -void -crypto_hmac_sha1(char *hmac_out, - const char *key, size_t key_len, - const char *msg, size_t msg_len) -{ - tor_assert(key_len < INT_MAX); - tor_assert(msg_len < INT_MAX); - HMAC(EVP_sha1(), key, (int)key_len, (unsigned char*)msg, (int)msg_len, - (unsigned char*)hmac_out, NULL); -} - /** Compute the HMAC-SHA-256 of the <b>msg_len</b> bytes in <b>msg</b>, using * the <b>key</b> of length <b>key_len</b>. Store the DIGEST256_LEN-byte * result in <b>hmac_out</b>. @@ -1727,7 +1735,7 @@ crypto_store_dynamic_dh_modulus(const char *fname) { int len, new_len; DH *dh = NULL; - unsigned char *dh_string_repr = NULL, *cp = NULL; + unsigned char *dh_string_repr = NULL; char *base64_encoded_dh = NULL; char *file_string = NULL; int retval = -1; @@ -1751,15 +1759,8 @@ crypto_store_dynamic_dh_modulus(const char *fname) if (!BN_set_word(dh->g, DH_GENERATOR)) goto done; - len = i2d_DHparams(dh, NULL); - if (len < 0) { - log_warn(LD_CRYPTO, "Error occured while DER encoding DH modulus (1)."); - goto done; - } - - cp = dh_string_repr = tor_malloc_zero(len+1); - len = i2d_DHparams(dh, &cp); - if ((len < 0) || ((cp - dh_string_repr) != len)) { + 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; } @@ -1786,7 +1787,8 @@ crypto_store_dynamic_dh_modulus(const char *fname) done: if (dh) DH_free(dh); - tor_free(dh_string_repr); + if (dh_string_repr) + OPENSSL_free(dh_string_repr); tor_free(base64_encoded_dh); tor_free(file_string); @@ -1922,7 +1924,7 @@ crypto_set_tls_dh_prime(const char *dynamic_dh_modulus_fname) /* If the space is occupied, free the previous TLS DH prime */ if (dh_param_p_tls) { - BN_free(dh_param_p_tls); + BN_clear_free(dh_param_p_tls); dh_param_p_tls = NULL; } @@ -2084,8 +2086,8 @@ crypto_dh_generate_public(crypto_dh_t *dh) log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" "the-universe chances really do happen. Trying again."); /* Free and clear the keys, so OpenSSL will actually try again. */ - BN_free(dh->dh->pub_key); - BN_free(dh->dh->priv_key); + BN_clear_free(dh->dh->pub_key); + BN_clear_free(dh->dh->priv_key); dh->dh->pub_key = dh->dh->priv_key = NULL; goto again; } @@ -2147,10 +2149,10 @@ tor_check_dh_key(int severity, BIGNUM *bn) log_fn(severity, LD_CRYPTO, "DH key must be at most p-2."); goto err; } - BN_free(x); + BN_clear_free(x); return 0; err: - BN_free(x); + BN_clear_free(x); s = BN_bn2hex(bn); log_fn(severity, LD_CRYPTO, "Rejecting insecure DH key [%s]", s); OPENSSL_free(s); @@ -2209,7 +2211,7 @@ crypto_dh_compute_secret(int severity, crypto_dh_t *dh, done: crypto_log_errors(LOG_WARN, "completing DH handshake"); if (pubkey_bn) - BN_free(pubkey_bn); + BN_clear_free(pubkey_bn); if (secret_tmp) { memwipe(secret_tmp, 0, secret_tmp_len); tor_free(secret_tmp); @@ -2394,7 +2396,7 @@ crypto_strongest_rand(uint8_t *out, size_t out_len) return 0; #else for (i = 0; filenames[i]; ++i) { - fd = open(filenames[i], O_RDONLY, 0); + fd = open(sandbox_intern_string(filenames[i]), O_RDONLY, 0); if (fd<0) continue; log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]); n = read_all(fd, (char*)out, out_len, 0); @@ -2449,8 +2451,8 @@ 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. */ -int -crypto_rand(char *to, size_t n) +MOCK_IMPL(int, +crypto_rand, (char *to, size_t n)) { int r; tor_assert(n < INT_MAX); @@ -3118,11 +3120,11 @@ crypto_global_cleanup(void) ERR_free_strings(); if (dh_param_p) - BN_free(dh_param_p); + BN_clear_free(dh_param_p); if (dh_param_p_tls) - BN_free(dh_param_p_tls); + BN_clear_free(dh_param_p_tls); if (dh_param_g) - BN_free(dh_param_g); + BN_clear_free(dh_param_g); #ifndef DISABLE_ENGINES ENGINE_cleanup(); @@ -3144,6 +3146,7 @@ crypto_global_cleanup(void) } #endif tor_free(crypto_openssl_version_str); + tor_free(crypto_openssl_header_version_str); return 0; } |