|
@@ -190,12 +190,16 @@ static X509* tor_tls_create_certificate(crypto_pk_env_t *rsa,
|
|
|
const char *cname_sign,
|
|
|
unsigned int lifetime);
|
|
|
static void tor_tls_unblock_renegotiation(tor_tls_t *tls);
|
|
|
+static int tor_tls_context_init_one(tor_tls_context_t **ppcontext,
|
|
|
+ crypto_pk_env_t *identity,
|
|
|
+ unsigned int key_lifetime);
|
|
|
static tor_tls_context_t *tor_tls_context_new(crypto_pk_env_t *identity,
|
|
|
unsigned int key_lifetime);
|
|
|
|
|
|
-/** Global tls context. We keep it here because nobody else needs to
|
|
|
- * touch it. */
|
|
|
-static tor_tls_context_t *global_tls_context = NULL;
|
|
|
+/** Global TLS contexts. We keep them here because nobody else needs
|
|
|
+ * to touch them. */
|
|
|
+static tor_tls_context_t *server_tls_context = NULL;
|
|
|
+static tor_tls_context_t *client_tls_context = NULL;
|
|
|
/** True iff tor_tls_init() has been called. */
|
|
|
static int tls_library_is_initialized = 0;
|
|
|
|
|
@@ -431,9 +435,15 @@ tor_tls_init(void)
|
|
|
void
|
|
|
tor_tls_free_all(void)
|
|
|
{
|
|
|
- if (global_tls_context) {
|
|
|
- tor_tls_context_decref(global_tls_context);
|
|
|
- global_tls_context = NULL;
|
|
|
+ if (server_tls_context) {
|
|
|
+ tor_tls_context_t *ctx = server_tls_context;
|
|
|
+ server_tls_context = NULL;
|
|
|
+ tor_tls_context_decref(ctx);
|
|
|
+ }
|
|
|
+ if (client_tls_context) {
|
|
|
+ tor_tls_context_t *ctx = client_tls_context;
|
|
|
+ client_tls_context = NULL;
|
|
|
+ tor_tls_context_decref(ctx);
|
|
|
}
|
|
|
if (!HT_EMPTY(&tlsmap_root)) {
|
|
|
log_warn(LD_MM, "Still have entries in the tlsmap at shutdown.");
|
|
@@ -620,21 +630,80 @@ tor_tls_context_incref(tor_tls_context_t *ctx)
|
|
|
++ctx->refcnt;
|
|
|
}
|
|
|
|
|
|
+/** Create new global client and server TLS contexts.
|
|
|
+ *
|
|
|
+ * If <b>server_identity</b> is NULL, this will not generate a server
|
|
|
+ * TLS context. If <b>is_public_server</b> is non-zero, this will use
|
|
|
+ * the same TLS context for incoming and outgoing connections, and
|
|
|
+ * ignore <b>client_identity</b>. */
|
|
|
+int
|
|
|
+tor_tls_context_init(int is_public_server,
|
|
|
+ crypto_pk_env_t *client_identity,
|
|
|
+ crypto_pk_env_t *server_identity,
|
|
|
+ unsigned int key_lifetime)
|
|
|
+{
|
|
|
+ int rv1 = 0;
|
|
|
+ int rv2 = 0;
|
|
|
+
|
|
|
+ if (is_public_server) {
|
|
|
+ tor_tls_context_t *new_ctx;
|
|
|
+ tor_tls_context_t *old_ctx;
|
|
|
+
|
|
|
+ tor_assert(server_identity != NULL);
|
|
|
+
|
|
|
+ rv1 = tor_tls_context_init_one(&server_tls_context,
|
|
|
+ server_identity,
|
|
|
+ key_lifetime);
|
|
|
+
|
|
|
+ if (rv1 >= 0) {
|
|
|
+ new_ctx = server_tls_context;
|
|
|
+ tor_tls_context_incref(new_ctx);
|
|
|
+ old_ctx = client_tls_context;
|
|
|
+ client_tls_context = new_ctx;
|
|
|
+
|
|
|
+ if (old_ctx != NULL) {
|
|
|
+ tor_tls_context_decref(old_ctx);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (server_identity != NULL) {
|
|
|
+ rv1 = tor_tls_context_init_one(&server_tls_context,
|
|
|
+ server_identity,
|
|
|
+ key_lifetime);
|
|
|
+ } else {
|
|
|
+ tor_tls_context_t *old_ctx = server_tls_context;
|
|
|
+ server_tls_context = NULL;
|
|
|
+
|
|
|
+ if (old_ctx != NULL) {
|
|
|
+ tor_tls_context_decref(old_ctx);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ rv2 = tor_tls_context_init_one(&client_tls_context,
|
|
|
+ client_identity,
|
|
|
+ key_lifetime);
|
|
|
+ }
|
|
|
+
|
|
|
+ return MIN(rv1, rv2);
|
|
|
+}
|
|
|
+
|
|
|
/** Create a new global TLS context.
|
|
|
*
|
|
|
* 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_init(crypto_pk_env_t *identity, unsigned int key_lifetime)
|
|
|
+static int
|
|
|
+tor_tls_context_init_one(tor_tls_context_t **ppcontext,
|
|
|
+ crypto_pk_env_t *identity,
|
|
|
+ unsigned int key_lifetime)
|
|
|
{
|
|
|
tor_tls_context_t *new_ctx = tor_tls_context_new(identity,
|
|
|
key_lifetime);
|
|
|
- tor_tls_context_t *old_ctx = global_tls_context;
|
|
|
+ tor_tls_context_t *old_ctx = *ppcontext;
|
|
|
|
|
|
if (new_ctx != NULL) {
|
|
|
- global_tls_context = new_ctx;
|
|
|
+ *ppcontext = new_ctx;
|
|
|
|
|
|
/* Free the old context if one existed. */
|
|
|
if (old_ctx != NULL) {
|
|
@@ -946,9 +1015,11 @@ tor_tls_new(int sock, int isServer)
|
|
|
{
|
|
|
BIO *bio = NULL;
|
|
|
tor_tls_t *result = tor_malloc_zero(sizeof(tor_tls_t));
|
|
|
+ tor_tls_context_t *context = isServer ? server_tls_context :
|
|
|
+ client_tls_context;
|
|
|
|
|
|
- tor_assert(global_tls_context); /* make sure somebody made it first */
|
|
|
- if (!(result->ssl = SSL_new(global_tls_context->ctx))) {
|
|
|
+ tor_assert(context); /* make sure somebody made it first */
|
|
|
+ if (!(result->ssl = SSL_new(context->ctx))) {
|
|
|
tls_log_errors(NULL, LOG_WARN, LD_NET, "creating SSL object");
|
|
|
tor_free(result);
|
|
|
return NULL;
|
|
@@ -988,8 +1059,8 @@ tor_tls_new(int sock, int isServer)
|
|
|
}
|
|
|
HT_INSERT(tlsmap, &tlsmap_root, result);
|
|
|
SSL_set_bio(result->ssl, bio, bio);
|
|
|
- tor_tls_context_incref(global_tls_context);
|
|
|
- result->context = global_tls_context;
|
|
|
+ tor_tls_context_incref(context);
|
|
|
+ result->context = context;
|
|
|
result->state = TOR_TLS_ST_HANDSHAKE;
|
|
|
result->isServer = isServer;
|
|
|
result->wantwrite_n = 0;
|