/* Copyright (c) 2003, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define TORTLS_PRIVATE #include "lib/tls/x509.h" #include "lib/tls/tortls.h" #include "lib/tls/tortls_st.h" #include "lib/tls/tortls_internal.h" #include "lib/log/util_bug.h" #include "lib/intmath/cmp.h" /** 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; /**@}*/ /** * Return the appropriate TLS context. */ tor_tls_context_t * tor_tls_context_get(int is_server) { return is_server ? server_tls_context : client_tls_context; } /** Increase the reference count of ctx. */ void tor_tls_context_incref(tor_tls_context_t *ctx) { ++ctx->refcnt; } /** Free all global TLS structures. */ void tor_tls_free_all(void) { check_no_tls_errors(); 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); } } /** Given a TOR_TLS_* error code, return a string equivalent. */ const char * tor_tls_err_to_string(int err) { if (err >= 0) return "[Not an error.]"; switch (err) { case TOR_TLS_ERROR_MISC: return "misc error"; case TOR_TLS_ERROR_IO: return "unexpected close"; case TOR_TLS_ERROR_CONNREFUSED: return "connection refused"; case TOR_TLS_ERROR_CONNRESET: return "connection reset"; case TOR_TLS_ERROR_NO_ROUTE: return "host unreachable"; case TOR_TLS_ERROR_TIMEOUT: return "connection timed out"; case TOR_TLS_CLOSE: return "closed"; case TOR_TLS_WANTREAD: return "want to read"; case TOR_TLS_WANTWRITE: return "want to write"; default: return "(unknown error code)"; } } /** Create new global client and server TLS contexts. * * If server_identity is NULL, this will not generate a server * TLS context. If TOR_TLS_CTX_IS_PUBLIC_SERVER is set in flags, use * the same TLS context for incoming and outgoing connections, and * ignore client_identity. If one of TOR_TLS_CTX_USE_ECDHE_P{224,256} * is set in flags, use that ECDHE group if possible; otherwise use * the default ECDHE group. */ int tor_tls_context_init(unsigned flags, crypto_pk_t *client_identity, crypto_pk_t *server_identity, unsigned int key_lifetime) { int rv1 = 0; int rv2 = 0; const int is_public_server = flags & TOR_TLS_CTX_IS_PUBLIC_SERVER; check_no_tls_errors(); 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, flags, 0); 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, flags, 0); } 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, flags, 1); } tls_log_errors(NULL, LOG_WARN, LD_CRYPTO, "constructing a TLS context"); return MIN(rv1, rv2); } /** Make future log messages about tls display the address * address. */ void tor_tls_set_logged_address(tor_tls_t *tls, const char *address) { tor_assert(tls); tor_free(tls->address); tls->address = tor_strdup(address); } /** Return whether this tls initiated the connect (client) or * received it (server). */ int tor_tls_is_server(tor_tls_t *tls) { tor_assert(tls); return tls->isServer; }