summaryrefslogtreecommitdiff
path: root/src/common/tortls.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/tortls.c')
-rw-r--r--src/common/tortls.c159
1 files changed, 86 insertions, 73 deletions
diff --git a/src/common/tortls.c b/src/common/tortls.c
index d9e71a6380..4401185c59 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -40,6 +40,7 @@ const char tortls_c_id[] =
/* DOCDOC */
typedef struct tor_tls_context_t {
SSL_CTX *ctx;
+ SSL_CTX *client_only_ctx;
} tor_tls_context_t;
/** Holds a SSL object and its associated data. Members are only
@@ -169,6 +170,7 @@ tor_tls_free_all(void)
{
if (global_tls_context) {
SSL_CTX_free(global_tls_context->ctx);
+ SSL_CTX_free(global_tls_context->client_only_ctx);
tor_free(global_tls_context);
global_tls_context = NULL;
}
@@ -232,7 +234,7 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa,
if ((nid = OBJ_txt2nid("organizationName")) == NID_undef)
goto error;
if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC,
- (unsigned char*)"Tor", -1, -1, 0)))
+ (unsigned char*)"TOR", -1, -1, 0)))
goto error;
if ((nid = OBJ_txt2nid("commonName")) == NID_undef) goto error;
if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC,
@@ -246,7 +248,7 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa,
if ((nid = OBJ_txt2nid("organizationName")) == NID_undef)
goto error;
if (!(X509_NAME_add_entry_by_NID(name_issuer, nid, MBSTRING_ASC,
- (unsigned char*)"Tor", -1, -1, 0)))
+ (unsigned char*)"TOR", -1, -1, 0)))
goto error;
if ((nid = OBJ_txt2nid("commonName")) == NID_undef) goto error;
if (!(X509_NAME_add_entry_by_NID(name_issuer, nid, MBSTRING_ASC,
@@ -299,16 +301,20 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa,
#define CIPHER_LIST SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA
#endif
-/** Create a new TLS context for use with Tor TLS handshakes.
- * <b>identity</b> should be set to the identity key used to sign the
- * certificate, and <b>nickname</b> set to the nickname to use.
+/** Create a new TLS context. If we are going to be using it as a
+ * server, it must have isServer set to true, <b>identity</b> set to the
+ * identity key used to sign that certificate, and <b>nickname</b> set to
+ * the server's nickname. If we're only going to be a client,
+ * isServer should be false, identity should be NULL, and nickname
+ * should be NULL. Return -1 if failure, else 0.
*
* You can call this function multiple times. Each time you call it,
* it generates new certificates; all new connections will use
* the new SSL context.
*/
int
-tor_tls_context_new(crypto_pk_env_t *identity, const char *nickname,
+tor_tls_context_new(crypto_pk_env_t *identity,
+ int isServer, const char *nickname,
unsigned int key_lifetime)
{
crypto_pk_env_t *rsa = NULL;
@@ -317,71 +323,86 @@ tor_tls_context_new(crypto_pk_env_t *identity, const char *nickname,
tor_tls_context_t *result = NULL;
X509 *cert = NULL, *idcert = NULL;
char nn2[128];
+ int client_only;
+ SSL_CTX **ctx;
if (!nickname)
nickname = "null";
tor_snprintf(nn2, sizeof(nn2), "%s <identity>", nickname);
tor_tls_init();
- /* Generate short-term RSA key. */
- if (!(rsa = crypto_new_pk_env()))
- goto error;
- if (crypto_pk_generate_key(rsa)<0)
- goto error;
- /* Create certificate signed by identity key. */
- cert = tor_tls_create_certificate(rsa, identity, nickname, nn2,
- key_lifetime);
- /* Create self-signed certificate for identity key. */
- idcert = tor_tls_create_certificate(identity, identity, nn2, nn2,
- IDENTITY_CERT_LIFETIME);
- if (!cert || !idcert) {
- log(LOG_WARN, LD_CRYPTO, "Error creating certificate");
- goto error;
+ if (isServer) {
+ /* Generate short-term RSA key. */
+ if (!(rsa = crypto_new_pk_env()))
+ goto error;
+ if (crypto_pk_generate_key(rsa)<0)
+ goto error;
+ /* Create certificate signed by identity key. */
+ cert = tor_tls_create_certificate(rsa, identity, nickname, nn2,
+ key_lifetime);
+ /* Create self-signed certificate for identity key. */
+ idcert = tor_tls_create_certificate(identity, identity, nn2, nn2,
+ IDENTITY_CERT_LIFETIME);
+ if (!cert || !idcert) {
+ log(LOG_WARN, LD_CRYPTO, "Error creating certificate");
+ goto error;
+ }
}
result = tor_malloc(sizeof(tor_tls_context_t));
+ result->ctx = result->client_only_ctx = NULL;
+ for (client_only=0; client_only <= 1; ++client_only) {
+ ctx = client_only ? &result->client_only_ctx : &result->ctx;
#ifdef EVERYONE_HAS_AES
- /* Tell OpenSSL to only use TLS1 */
- if (!(result->ctx = SSL_CTX_new(TLSv1_method())))
- goto error;
+ /* Tell OpenSSL to only use TLS1 */
+ if (!(*ctx = SSL_CTX_new(TLSv1_method())))
+ goto error;
#else
- /* Tell OpenSSL to use SSL3 or TLS1 but not SSL2. */
- if (!(result->ctx = SSL_CTX_new(SSLv23_method())))
- goto error;
- SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv2);
+ /* Tell OpenSSL to use SSL3 or TLS1 but not SSL2. */
+ if (!(*ctx = SSL_CTX_new(SSLv23_method())))
+ goto error;
+ SSL_CTX_set_options(*ctx, SSL_OP_NO_SSLv2);
#endif
- SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_DH_USE);
- if (!SSL_CTX_set_cipher_list(result->ctx, CIPHER_LIST))
- goto error;
- if (cert && !SSL_CTX_use_certificate(result->ctx,cert))
- goto error;
- X509_free(cert); /* We just added a reference to cert. */
- cert=NULL;
- if (idcert && !SSL_CTX_add_extra_chain_cert(result->ctx,idcert))
- goto error;
- idcert=NULL; /* The context now owns the reference to idcert */
- SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF);
- tor_assert(rsa);
- if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa,1)))
- goto error;
- if (!SSL_CTX_use_PrivateKey(result->ctx, pkey))
- goto error;
- EVP_PKEY_free(pkey);
- pkey = NULL;
- if (!SSL_CTX_check_private_key(result->ctx))
- goto error;
- dh = crypto_dh_new();
- SSL_CTX_set_tmp_dh(result->ctx, _crypto_dh_env_get_dh(dh));
- crypto_dh_free(dh);
- SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER,
- always_accept_verify_cb);
- /* let us realloc bufs that we're writing from */
- SSL_CTX_set_mode(result->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+#ifndef ENABLE_0119_PARANOIA_A
+ SSL_CTX_set_options(*ctx, SSL_OP_SINGLE_DH_USE);
+#endif
+ if (!SSL_CTX_set_cipher_list(*ctx, CIPHER_LIST))
+ goto error;
+ if (!client_only) {
+ if (cert && !SSL_CTX_use_certificate(*ctx,cert))
+ goto error;
+ X509_free(cert); /* We just added a reference to cert. */
+ cert=NULL;
+ if (idcert && !SSL_CTX_add_extra_chain_cert(*ctx,idcert))
+ goto error;
+ idcert=NULL; /* The context now owns the reference to idcert */
+ }
+ SSL_CTX_set_session_cache_mode(*ctx, SSL_SESS_CACHE_OFF);
+ if (isServer && !client_only) {
+ tor_assert(rsa);
+ if (!(pkey = _crypto_pk_env_get_evp_pkey(rsa,1)))
+ goto error;
+ if (!SSL_CTX_use_PrivateKey(*ctx, pkey))
+ goto error;
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ if (!SSL_CTX_check_private_key(*ctx))
+ goto error;
+ }
+ dh = crypto_dh_new();
+ SSL_CTX_set_tmp_dh(*ctx, _crypto_dh_env_get_dh(dh));
+ crypto_dh_free(dh);
+ SSL_CTX_set_verify(*ctx, SSL_VERIFY_PEER,
+ always_accept_verify_cb);
+ /* let us realloc bufs that we're writing from */
+ SSL_CTX_set_mode(*ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+ }
/* Free the old context if one exists. */
if (global_tls_context) {
/* This is safe even if there are open connections: OpenSSL does
* reference counting with SSL and SSL_CTX objects. */
SSL_CTX_free(global_tls_context->ctx);
+ SSL_CTX_free(global_tls_context->client_only_ctx);
tor_free(global_tls_context);
}
global_tls_context = result;
@@ -399,6 +420,8 @@ tor_tls_context_new(crypto_pk_env_t *identity, const char *nickname,
crypto_dh_free(dh);
if (result && result->ctx)
SSL_CTX_free(result->ctx);
+ if (result && result->client_only_ctx)
+ SSL_CTX_free(result->client_only_ctx);
if (result)
tor_free(result);
if (cert)
@@ -412,29 +435,20 @@ tor_tls_context_new(crypto_pk_env_t *identity, const char *nickname,
* determine whether it is functioning as a server.
*/
tor_tls_t *
-tor_tls_new(int sock, int isServer)
+tor_tls_new(int sock, int isServer, int use_no_cert)
{
- BIO *bio = NULL;
tor_tls_t *result = tor_malloc(sizeof(tor_tls_t));
-
+ SSL_CTX *ctx;
tor_assert(global_tls_context); /* make sure somebody made it first */
- if (!(result->ssl = SSL_new(global_tls_context->ctx))) {
+ ctx = use_no_cert ? global_tls_context->client_only_ctx
+ : global_tls_context->ctx;
+ if (!(result->ssl = SSL_new(ctx))) {
tls_log_errors(LOG_WARN, "generating TLS context");
tor_free(result);
return NULL;
}
result->socket = sock;
-#ifdef USE_BSOCKETS
- bio = BIO_new_bsocket(sock, BIO_NOCLOSE);
-#else
- bio = BIO_new_socket(sock, BIO_NOCLOSE);
-#endif
- if (! bio) {
- tls_log_errors(LOG_WARN, "opening BIO");
- tor_free(result);
- return NULL;
- }
- SSL_set_bio(result->ssl, bio, bio);
+ SSL_set_fd(result->ssl, sock);
result->state = TOR_TLS_ST_HANDSHAKE;
result->isServer = isServer;
result->wantwrite_n = 0;
@@ -543,8 +557,7 @@ tor_tls_handshake(tor_tls_t *tls)
}
r = tor_tls_get_error(tls,r,0, "handshaking", LOG_INFO);
if (ERR_peek_error() != 0) {
- tls_log_errors(tls->isServer ? LOG_INFO : LOG_WARN,
- "handshaking");
+ tls_log_errors(LOG_WARN, "handshaking");
return TOR_TLS_ERROR;
}
if (r == TOR_TLS_DONE) {
@@ -704,7 +717,7 @@ log_cert_lifetime(X509 *cert, const char *problem)
BIO_get_mem_ptr(bio, &buf);
s1 = tor_strndup(buf->data, buf->length);
- (void)BIO_reset(bio);
+ BIO_reset(bio);
if (!(ASN1_TIME_print(bio, X509_get_notAfter(cert)))) {
tls_log_errors(LOG_WARN, "printing certificate lifetime");
goto end;
@@ -869,7 +882,7 @@ tor_tls_get_n_bytes_written(tor_tls_t *tls)
}
/** Implement check_no_tls_errors: If there are any pending OpenSSL
- * errors, log an error message. */
+ * errors, log an error message and assert(0). */
void
_check_no_tls_errors(const char *fname, int line)
{