diff options
author | Nick Mathewson <nickm@torproject.org> | 2004-04-26 18:09:50 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2004-04-26 18:09:50 +0000 |
commit | f6dbe5a0d42dcf82d440ef24b7a879854c3da14f (patch) | |
tree | 94476491174ca63cc79c4d105b940def1ab9c8f4 | |
parent | b410dff6c078022a7478ce2d17c07ccb38104081 (diff) | |
download | tor-f6dbe5a0d42dcf82d440ef24b7a879854c3da14f.tar tor-f6dbe5a0d42dcf82d440ef24b7a879854c3da14f.tar.gz |
Refactor crypto error handling to be more like TLS error handling:
crypto_perror is a no-no, since an operation can set more than one
error.
Also, fix a bug in the unix crypto_seed_rng: mixing stdio with
/dev/urandom is a bad idea, since fopen can make all kinds of weird
extraneous syscalls (mmap, fcntl, stat64, etc.) and since fread tends
to buffer data in big chunks, thus depleting the entropy pool.
svn:r1717
-rw-r--r-- | src/common/crypto.c | 171 | ||||
-rw-r--r-- | src/common/crypto.h | 6 | ||||
-rw-r--r-- | src/or/circuit.c | 2 | ||||
-rw-r--r-- | src/or/router.c | 4 | ||||
-rw-r--r-- | src/or/test.c | 14 |
5 files changed, 103 insertions, 94 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c index d36c6c92a..4a0fc653a 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -25,6 +25,15 @@ #ifdef HAVE_CTYPE_H #include <ctype.h> #endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_SYS_FCNTL_H +#include <sys/fcntl.h> +#endif #include "crypto.h" #include "log.h" @@ -97,6 +106,25 @@ crypto_get_rsa_padding(int padding) { static int _crypto_global_initialized = 0; + +/* errors */ +static void +crypto_log_errors(int severity, const char *doing) +{ + int err; + const char *msg, *lib, *func; + while ((err = ERR_get_error()) != 0) { + msg = (const char*)ERR_reason_error_string(err); + lib = (const char*)ERR_lib_error_string(err); + func = (const char*)ERR_func_error_string(err); + if (!msg) msg = "(null)"; + if (doing) { + log(severity, "crypto error while %s: %s (in %s:%s)", doing, msg, lib,func); + } else { + log(severity, "crypto error: %s (in %s:%s)", msg, lib, func); + } + } +} int crypto_global_init() { if (!_crypto_global_initialized) { @@ -199,12 +227,12 @@ crypto_create_init_cipher(const char *key, const char *iv, int encrypt_mode) } if (crypto_cipher_set_key(crypto, key)) { - log_fn(LOG_WARN, "Unable to set key: %s", crypto_perror()); + crypto_log_errors(LOG_WARN, "setting symmetric key"); goto error; } if (crypto_cipher_set_iv(crypto, iv)) { - log_fn(LOG_WARN, "Unable to set iv: %s", crypto_perror()); + crypto_log_errors(LOG_WARN, "setting IV"); goto error; } @@ -213,10 +241,8 @@ crypto_create_init_cipher(const char *key, const char *iv, int encrypt_mode) else r = crypto_cipher_decrypt_init_cipher(crypto); - if (r) { - log_fn(LOG_WARN, "Unable to initialize cipher: %s", crypto_perror()); + if (r) goto error; - } return crypto; error: @@ -251,21 +277,26 @@ int crypto_pk_generate_key(crypto_pk_env_t *env) if (env->key) RSA_free(env->key); env->key = RSA_generate_key(PK_BITS,65537, NULL, NULL); - if (!env->key) + if (!env->key) { + crypto_log_errors(LOG_WARN, "generating RSA key"); return -1; + } return 0; } -int crypto_pk_read_private_key_from_file(crypto_pk_env_t *env, FILE *src) +static int crypto_pk_read_private_key_from_file(crypto_pk_env_t *env, + FILE *src) { tor_assert(env && src); if (env->key) RSA_free(env->key); env->key = PEM_read_RSAPrivateKey(src, NULL, NULL, NULL); - if (!env->key) + if (!env->key) { + crypto_log_errors(LOG_WARN, "reading private key from file"); return -1; + } return 0; } @@ -288,33 +319,13 @@ int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env, const char *k /* read the private key */ if(crypto_pk_read_private_key_from_file(env, f_pr) < 0) { - log_fn(LOG_WARN,"Error reading private key : %s",crypto_perror()); fclose(f_pr); return -1; } fclose(f_pr); /* check the private key */ - switch(crypto_pk_check_key(env)) { - case 0: - log_fn(LOG_WARN,"Private key read but is invalid : %s.", crypto_perror()); - return -1; - case -1: - log_fn(LOG_WARN,"Private key read but validity checking failed : %s",crypto_perror()); - return -1; - /* case 1: fall through */ - } - return 0; -} - -int crypto_pk_read_public_key_from_file(crypto_pk_env_t *env, FILE *src) -{ - tor_assert(env && src); - - if(env->key) - RSA_free(env->key); - env->key = PEM_read_RSAPublicKey(src, NULL, NULL, NULL); - if (!env->key) + if (crypto_pk_check_key(env) <= 0) return -1; return 0; @@ -331,8 +342,10 @@ int crypto_pk_write_public_key_to_string(crypto_pk_env_t *env, char **dest, int /* Now you can treat b as if it were a file. Just use the * PEM_*_bio_* functions instead of the non-bio variants. */ - if(!PEM_write_bio_RSAPublicKey(b, env->key)) + if(!PEM_write_bio_RSAPublicKey(b, env->key)) { + crypto_log_errors(LOG_WARN, "writing public key to string"); return -1; + } BIO_get_mem_ptr(b, &buf); BIO_set_close(b, BIO_NOCLOSE); /* so BIO_free doesn't free buf */ @@ -360,8 +373,10 @@ int crypto_pk_read_public_key_from_string(crypto_pk_env_t *env, const char *src, RSA_free(env->key); env->key = PEM_read_bio_RSAPublicKey(b, NULL, NULL, NULL); BIO_free(b); - if(!env->key) + if(!env->key) { + crypto_log_errors(LOG_WARN, "reading public key from string"); return -1; + } return 0; } @@ -382,6 +397,7 @@ crypto_pk_write_private_key_to_filename(crypto_pk_env_t *env, return -1; if (PEM_write_bio_RSAPrivateKey(bio, env->key, NULL,NULL,0,NULL,NULL) == 0) { + crypto_log_errors(LOG_WARN, "writing private key"); BIO_free(bio); return -1; } @@ -395,34 +411,15 @@ crypto_pk_write_private_key_to_filename(crypto_pk_env_t *env, return r; } -int crypto_pk_write_private_key_to_file(crypto_pk_env_t *env, FILE *dest) -{ - tor_assert(env && dest); - - if (!env->key) - return -1; - if (PEM_write_RSAPrivateKey(dest, env->key, NULL, NULL, 0,0, NULL) == 0) - return -1; - - return 0; -} -int crypto_pk_write_public_key_to_file(crypto_pk_env_t *env, FILE *dest) -{ - tor_assert(env && dest); - - if (!env->key) - return -1; - if (PEM_write_RSAPublicKey(dest, env->key) == 0) - return -1; - - return 0; -} - int crypto_pk_check_key(crypto_pk_env_t *env) { + int r; tor_assert(env); - return RSA_check_key(env->key); + r = RSA_check_key(env->key); + if (r <= 0) + crypto_log_errors(LOG_WARN,"checking RSA key"); + return r; } int crypto_pk_cmp_keys(crypto_pk_env_t *a, crypto_pk_env_t *b) { @@ -459,37 +456,54 @@ crypto_pk_env_t *crypto_pk_dup_key(crypto_pk_env_t *env) { int crypto_pk_public_encrypt(crypto_pk_env_t *env, const unsigned char *from, int fromlen, unsigned char *to, int padding) { + int r; tor_assert(env && from && to); - return RSA_public_encrypt(fromlen, (unsigned char*)from, to, env->key, + r = RSA_public_encrypt(fromlen, (unsigned char*)from, to, env->key, crypto_get_rsa_padding(padding)); + if (r<0) + crypto_log_errors(LOG_WARN, "performing RSA encryption"); + return r; } int crypto_pk_private_decrypt(crypto_pk_env_t *env, const unsigned char *from, int fromlen, unsigned char *to, int padding) { + int r; tor_assert(env && from && to && env->key); if (!env->key->p) /* Not a private key */ return -1; - return RSA_private_decrypt(fromlen, (unsigned char*)from, to, env->key, + r = RSA_private_decrypt(fromlen, (unsigned char*)from, to, env->key, crypto_get_rsa_padding(padding)); + if (r<0) + crypto_log_errors(LOG_WARN, "performing RSA decryption"); + return r; } int crypto_pk_public_checksig(crypto_pk_env_t *env, const unsigned char *from, int fromlen, unsigned char *to) { + int r; tor_assert(env && from && to); - return RSA_public_decrypt(fromlen, (unsigned char*)from, to, env->key, RSA_PKCS1_PADDING); + r = RSA_public_decrypt(fromlen, (unsigned char*)from, to, env->key, RSA_PKCS1_PADDING); + + if (r<0) + crypto_log_errors(LOG_WARN, "checking RSA signature"); + return r; } int crypto_pk_private_sign(crypto_pk_env_t *env, const unsigned char *from, int fromlen, unsigned char *to) { + int r; tor_assert(env && from && to); if (!env->key->p) /* Not a private key */ return -1; - return RSA_private_encrypt(fromlen, (unsigned char*)from, to, env->key, RSA_PKCS1_PADDING); + r = RSA_private_encrypt(fromlen, (unsigned char*)from, to, env->key, RSA_PKCS1_PADDING); + if (r<0) + crypto_log_errors(LOG_WARN, "generating RSA signature"); + return r; } /* Return 0 if sig is a correct signature for SHA1(data). Else return -1. @@ -667,6 +681,7 @@ int crypto_pk_asn1_encode(crypto_pk_env_t *pk, char *dest, int dest_len) 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); return -1; } @@ -696,8 +711,10 @@ crypto_pk_env_t *crypto_pk_asn1_decode(const char *str, int len) memcpy(buf,str,len); rsa = d2i_RSAPublicKey(NULL, &cp, len); tor_free(buf); - if (!rsa) - return NULL; /* XXXX log openssl error */ + if (!rsa) { + crypto_log_errors(LOG_WARN,"decoding public key"); + return NULL; + } return _crypto_new_pk_env_rsa(rsa); } @@ -715,6 +732,7 @@ int crypto_pk_get_digest(crypto_pk_env_t *pk, char *digest_out) buf = bufp = tor_malloc(len+1); len = i2d_RSAPublicKey(pk->key, &bufp); if (len < 0) { + crypto_log_errors(LOG_WARN,"encoding public key"); free(buf); return -1; } @@ -987,6 +1005,7 @@ crypto_dh_env_t *crypto_dh_new() return res; err: + crypto_log_errors(LOG_WARN, "creating DH object"); if (res && res->dh) DH_free(res->dh); /* frees p and g too */ if (res) free(res); return NULL; @@ -998,8 +1017,10 @@ int crypto_dh_get_bytes(crypto_dh_env_t *dh) } int crypto_dh_generate_public(crypto_dh_env_t *dh) { - if (!DH_generate_key(dh->dh)) + if (!DH_generate_key(dh->dh)) { + crypto_log_errors(LOG_WARN, "generating DH key"); return -1; + } return 0; } int crypto_dh_get_public(crypto_dh_env_t *dh, char *pubkey, int pubkey_len) @@ -1007,7 +1028,7 @@ int crypto_dh_get_public(crypto_dh_env_t *dh, char *pubkey, int pubkey_len) int bytes; tor_assert(dh); if (!dh->dh->pub_key) { - if (!DH_generate_key(dh->dh)) + if (crypto_dh_generate_public(dh)<0) return -1; } @@ -1053,6 +1074,7 @@ int crypto_dh_compute_secret(crypto_dh_env_t *dh, error: secret_len = -1; done: + crypto_log_errors(LOG_WARN, "completing DH handshake"); if (pubkey_bn) BN_free(pubkey_bn); tor_free(secret_tmp); @@ -1104,16 +1126,16 @@ int crypto_seed_rng() static char *filenames[] = { "/dev/srandom", "/dev/urandom", "/dev/random", NULL }; + int fd; int i, n; char buf[DIGEST_LEN+1]; - FILE *f; for (i = 0; filenames[i]; ++i) { - f = fopen(filenames[i], "rb"); - if (!f) continue; + fd = open(filenames[i], O_RDONLY, 0); + if (fd<0) continue; log_fn(LOG_INFO, "Seeding RNG from %s", filenames[i]); - n = fread(buf, 1, DIGEST_LEN, f); - fclose(f); + n = read(fd, buf, DIGEST_LEN); + close(fd); if (n != DIGEST_LEN) { log_fn(LOG_WARN, "Error reading from entropy source"); return -1; @@ -1129,8 +1151,12 @@ int crypto_seed_rng() int crypto_rand(unsigned int n, unsigned char *to) { + int r; tor_assert(to); - return (RAND_bytes(to, n) != 1); + r = RAND_bytes(to, n); + if (r == 0) + crypto_log_errors(LOG_WARN, "generating random data"); + return (r != 1); } void crypto_pseudo_rand(unsigned int n, unsigned char *to) @@ -1138,6 +1164,7 @@ void crypto_pseudo_rand(unsigned int n, unsigned char *to) tor_assert(to); if (RAND_pseudo_bytes(to, n) == -1) { log_fn(LOG_ERR, "RAND_pseudo_bytes failed unexpectedly."); + crypto_log_errors(LOG_WARN, "generating random data"); exit(1); } } @@ -1161,12 +1188,6 @@ int crypto_pseudo_rand_int(unsigned int max) { } } -/* errors */ -const char *crypto_perror() -{ - return (const char *)ERR_reason_error_string(ERR_get_error()); -} - int base64_encode(char *dest, int destlen, const char *src, int srclen) { diff --git a/src/common/crypto.h b/src/common/crypto.h index f3bd0e6a8..fd4c2d1a1 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -42,13 +42,9 @@ void crypto_free_cipher_env(crypto_cipher_env_t *env); /* public key crypto */ int crypto_pk_generate_key(crypto_pk_env_t *env); -int crypto_pk_read_private_key_from_file(crypto_pk_env_t *env, FILE *src); -int crypto_pk_read_public_key_from_file(crypto_pk_env_t *env, FILE *src); int crypto_pk_write_public_key_to_string(crypto_pk_env_t *env, char **dest, int *len); int crypto_pk_read_public_key_from_string(crypto_pk_env_t *env, const char *src, int len); -int crypto_pk_write_private_key_to_file(crypto_pk_env_t *env, FILE *dest); int crypto_pk_write_private_key_to_filename(crypto_pk_env_t *env, const char *fname); -int crypto_pk_write_public_key_to_file(crypto_pk_env_t *env, FILE *dest); int crypto_pk_check_key(crypto_pk_env_t *env); int crypto_pk_read_private_key_from_filename(crypto_pk_env_t *env, const char *keyfile); @@ -128,8 +124,6 @@ int crypto_rand(unsigned int n, unsigned char *to); void crypto_pseudo_rand(unsigned int n, unsigned char *to); int crypto_pseudo_rand_int(unsigned int max); -/* errors */ -const char *crypto_perror(); #endif /* diff --git a/src/or/circuit.c b/src/or/circuit.c index f2a94d8a1..731e54742 100644 --- a/src/or/circuit.c +++ b/src/or/circuit.c @@ -683,7 +683,7 @@ static int relay_crypt_one_payload(crypto_cipher_env_t *cipher, char *in, // log_fn(LOG_DEBUG,"before crypt: %d",rh.recognized); if(( encrypt_mode && crypto_cipher_encrypt(cipher, in, CELL_PAYLOAD_SIZE, out)) || (!encrypt_mode && crypto_cipher_decrypt(cipher, in, CELL_PAYLOAD_SIZE, out))) { - log_fn(LOG_WARN,"Error during crypt: %s", crypto_perror()); + log_fn(LOG_WARN,"Error during relay encryption"); return -1; } memcpy(in,out,CELL_PAYLOAD_SIZE); diff --git a/src/or/router.c b/src/or/router.c index 76bd3afb9..a1e0e4ce3 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -62,7 +62,7 @@ void rotate_onion_key(void) goto error; } if (crypto_pk_generate_key(prkey)) { - log(LOG_ERR, "Error generating key: %s", crypto_perror()); + log(LOG_ERR, "Error generating onion key"); goto error; } if (crypto_pk_write_private_key_to_filename(prkey, fname)) { @@ -104,7 +104,7 @@ crypto_pk_env_t *init_key_from_file(const char *fname) case FN_NOENT: log(LOG_INFO, "No key found in %s; generating fresh key.", fname); if (crypto_pk_generate_key(prkey)) { - log(LOG_ERR, "Error generating key: %s", crypto_perror()); + log(LOG_ERR, "Error generating onion key"); goto error; } if (crypto_pk_check_key(prkey) <= 0) { diff --git a/src/or/test.c b/src/or/test.c index c773e86a4..48e4a4f9a 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -242,7 +242,6 @@ test_crypto() crypto_cipher_env_t *env1, *env2; crypto_pk_env_t *pk1, *pk2; char *data1, *data2, *data3, *cp; - FILE *f; int i, j, p, len; data1 = tor_malloc(1024); @@ -376,16 +375,11 @@ test_crypto() PK_PKCS1_OAEP_PADDING)); /* File operations: save and load private key */ - f = fopen("/tmp/tor_test/pkey1", "wb"); - test_assert(! crypto_pk_write_private_key_to_file(pk1, f)); - fclose(f); - f = fopen("/tmp/tor_test/pkey1", "rb"); - test_assert(! crypto_pk_read_private_key_from_file(pk2, f)); - fclose(f); - test_eq(15, crypto_pk_private_decrypt(pk2, data1, 128, data3, - PK_PKCS1_OAEP_PADDING)); + test_assert(! crypto_pk_write_private_key_to_filename(pk1, + "/tmp/tor_test/pke1y")); + test_assert(! crypto_pk_read_private_key_from_filename(pk2, - "/tmp/tor_test/pkey1")); + "/tmp/tor_test/pke1y")); test_eq(15, crypto_pk_private_decrypt(pk2, data1, 128, data3, PK_PKCS1_OAEP_PADDING)); |