diff options
Diffstat (limited to 'src/common/tortls.c')
-rw-r--r-- | src/common/tortls.c | 1104 |
1 files changed, 396 insertions, 708 deletions
diff --git a/src/common/tortls.c b/src/common/tortls.c index 221b47e009..89ad6af939 100644 --- a/src/common/tortls.c +++ b/src/common/tortls.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2013, The Tor Project, Inc. */ + * Copyright (c) 2007-2016, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -16,22 +16,12 @@ #include "orconfig.h" -#if defined (WINCE) -#include <WinSock2.h> -#endif +#define TORTLS_PRIVATE #include <assert.h> #ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/ - #ifndef _WIN32_WINNT - #define _WIN32_WINNT 0x0501 - #endif - #define WIN32_LEAN_AND_MEAN - #if defined(_MSC_VER) && (_MSC_VER < 1300) - #include <winsock.h> - #else - #include <winsock2.h> - #include <ws2tcpip.h> - #endif + #include <winsock2.h> + #include <ws2tcpip.h> #endif #ifdef __GNUC__ @@ -47,13 +37,21 @@ #pragma GCC diagnostic ignored "-Wredundant-decls" #endif +#include <openssl/opensslv.h> +#include "crypto.h" + +#ifdef OPENSSL_NO_EC +#error "We require OpenSSL with ECC support" +#endif + #include <openssl/ssl.h> #include <openssl/ssl3.h> #include <openssl/err.h> #include <openssl/tls1.h> #include <openssl/asn1.h> #include <openssl/bio.h> -#include <openssl/opensslv.h> +#include <openssl/bn.h> +#include <openssl/rsa.h> #if __GNUC__ && GCC_VERSION >= 402 #if GCC_VERSION >= 406 @@ -70,21 +68,17 @@ #include "compat_libevent.h" #endif -#include "crypto.h" +#define TORTLS_PRIVATE #include "tortls.h" #include "util.h" #include "torlog.h" #include "container.h" #include <string.h> -#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8) -#error "We require OpenSSL >= 0.9.8" -#endif - -/* Enable the "v2" TLS handshake. - */ -#define V2_HANDSHAKE_SERVER -#define V2_HANDSHAKE_CLIENT +#define X509_get_notBefore_const(cert) \ + ((const ASN1_TIME*) X509_get_notBefore((X509 *)cert)) +#define X509_get_notAfter_const(cert) \ + ((const ASN1_TIME*) X509_get_notAfter((X509 *)cert)) /* Copied from or.h */ #define LEGAL_NICKNAME_CHARACTERS \ @@ -95,10 +89,8 @@ #define ADDR(tls) (((tls) && (tls)->address) ? tls->address : "peer") -#if (OPENSSL_VERSION_NUMBER < OPENSSL_V(0,9,8,'s') || \ - (OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(0,9,9) && \ - OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,0,'f'))) -/* This is a version of OpenSSL before 0.9.8s/1.0.0f. It does not have +#if OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,0,'f') +/* This is a version of OpenSSL before 1.0.0f. It does not have * the CVE-2011-4576 fix, and as such it can't use RELEASE_BUFFERS and * SSL3 safely at the same time. */ @@ -116,36 +108,6 @@ #define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x0010 #endif -/** Does the run-time openssl version look like we need - * SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION? */ -static int use_unsafe_renegotiation_op = 0; -/** Does the run-time openssl version look like we need - * SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION? */ -static int use_unsafe_renegotiation_flag = 0; - -/** Structure that we use for a single certificate. */ -struct tor_cert_t { - X509 *cert; - uint8_t *encoded; - size_t encoded_len; - unsigned pkey_digests_set : 1; - digests_t cert_digests; - digests_t pkey_digests; -}; - -/** Holds a SSL_CTX object and related state used to configure TLS - * connections. - */ -typedef struct tor_tls_context_t { - int refcnt; - SSL_CTX *ctx; - tor_cert_t *my_link_cert; - tor_cert_t *my_id_cert; - tor_cert_t *my_auth_cert; - crypto_pk_t *link_key; - crypto_pk_t *auth_key; -} tor_tls_context_t; - /** Return values for tor_tls_classify_client_ciphers. * * @{ @@ -164,70 +126,12 @@ typedef struct tor_tls_context_t { #define CIPHERS_UNRESTRICTED 3 /** @} */ -#define TOR_TLS_MAGIC 0x71571571 - -typedef enum { - TOR_TLS_ST_HANDSHAKE, TOR_TLS_ST_OPEN, TOR_TLS_ST_GOTCLOSE, - TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED, TOR_TLS_ST_RENEGOTIATE, - TOR_TLS_ST_BUFFEREVENT -} tor_tls_state_t; -#define tor_tls_state_bitfield_t ENUM_BF(tor_tls_state_t) - -/** Holds a SSL object and its associated data. Members are only - * accessed from within tortls.c. - */ -struct tor_tls_t { - uint32_t magic; - tor_tls_context_t *context; /** A link to the context object for this tls. */ - SSL *ssl; /**< An OpenSSL SSL object. */ - int socket; /**< The underlying file descriptor for this TLS connection. */ - char *address; /**< An address to log when describing this connection. */ - tor_tls_state_bitfield_t state : 3; /**< The current SSL state, - * depending on which operations - * have completed successfully. */ - unsigned int isServer:1; /**< True iff this is a server-side connection */ - unsigned int wasV2Handshake:1; /**< True iff the original handshake for - * this connection used the updated version - * of the connection protocol (client sends - * different cipher list, server sends only - * one certificate). */ - /** True iff we should call negotiated_callback when we're done reading. */ - unsigned int got_renegotiate:1; - /** Return value from tor_tls_classify_client_ciphers, or 0 if we haven't - * called that function yet. */ - int8_t client_cipher_list_type; - /** Incremented every time we start the server side of a handshake. */ - uint8_t server_handshake_count; - size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last - * time. */ - /** Last values retrieved from BIO_number_read()/write(); see - * tor_tls_get_n_raw_bytes() for usage. - */ - unsigned long last_write_count; - unsigned long last_read_count; - /** If set, a callback to invoke whenever the client tries to renegotiate - * the handshake. */ - void (*negotiated_callback)(tor_tls_t *tls, void *arg); - /** Argument to pass to negotiated_callback. */ - void *callback_arg; -}; - -#ifdef V2_HANDSHAKE_CLIENT -/** An array of fake SSL_CIPHER objects that we use in order to trick OpenSSL - * in client mode into advertising the ciphers we want. See - * rectify_client_ciphers() for details. */ -static SSL_CIPHER *CLIENT_CIPHER_DUMMIES = NULL; -/** A stack of SSL_CIPHER objects, some real, some fake. - * See rectify_client_ciphers() for details. */ -static STACK_OF(SSL_CIPHER) *CLIENT_CIPHER_STACK = NULL; -#endif - /** The ex_data index in which we store a pointer to an SSL object's * corresponding tor_tls_t object. */ -static int tor_tls_object_ex_data_index = -1; +STATIC int tor_tls_object_ex_data_index = -1; /** Helper: Allocate tor_tls_object_ex_data_index. */ -static void +STATIC void tor_tls_allocate_tor_tls_object_ex_data_index(void) { if (tor_tls_object_ex_data_index == -1) { @@ -239,7 +143,7 @@ tor_tls_allocate_tor_tls_object_ex_data_index(void) /** Helper: given a SSL* pointer, return the tor_tls_t object using that * pointer. */ -static INLINE tor_tls_t * +STATIC tor_tls_t * tor_tls_get_by_ssl(const SSL *ssl) { tor_tls_t *result = SSL_get_ex_data(ssl, tor_tls_object_ex_data_index); @@ -250,21 +154,7 @@ tor_tls_get_by_ssl(const SSL *ssl) static void tor_tls_context_decref(tor_tls_context_t *ctx); static void tor_tls_context_incref(tor_tls_context_t *ctx); -static X509* tor_tls_create_certificate(crypto_pk_t *rsa, - crypto_pk_t *rsa_sign, - const char *cname, - const char *cname_sign, - unsigned int cert_lifetime); - -static int tor_tls_context_init_one(tor_tls_context_t **ppcontext, - crypto_pk_t *identity, - unsigned int key_lifetime, - unsigned int flags, - int is_client); -static tor_tls_context_t *tor_tls_context_new(crypto_pk_t *identity, - unsigned int key_lifetime, - unsigned int flags, - int is_client); + static int check_cert_lifetime_internal(int severity, const X509 *cert, int past_tolerance, int future_tolerance); @@ -272,8 +162,8 @@ static int check_cert_lifetime_internal(int severity, const X509 *cert, * to touch them. * * @{ */ -static tor_tls_context_t *server_tls_context = NULL; -static tor_tls_context_t *client_tls_context = NULL; +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. */ @@ -338,7 +228,9 @@ tor_tls_log_one_error(tor_tls_t *tls, unsigned long err, case SSL_R_HTTP_REQUEST: case SSL_R_HTTPS_PROXY_REQUEST: case SSL_R_RECORD_LENGTH_MISMATCH: +#ifndef OPENSSL_1_1_API case SSL_R_RECORD_TOO_LARGE: +#endif case SSL_R_UNKNOWN_PROTOCOL: case SSL_R_UNSUPPORTED_PROTOCOL: severity = LOG_INFO; @@ -367,7 +259,7 @@ tor_tls_log_one_error(tor_tls_t *tls, unsigned long err, /** Log all pending tls errors at level <b>severity</b> in log domain * <b>domain</b>. Use <b>doing</b> to describe our current activities. */ -static void +STATIC void tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing) { unsigned long err; @@ -379,7 +271,7 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing) /** Convert an errno (or a WSAerrno on windows) into a TOR_TLS_* error * code. */ -static int +STATIC int tor_errno_to_tls_error(int e) { switch (e) { @@ -430,7 +322,7 @@ tor_tls_err_to_string(int err) * If an error has occurred, log it at level <b>severity</b> and describe the * current action as <b>doing</b>. */ -static int +STATIC int tor_tls_get_error(tor_tls_t *tls, int r, int extra, const char *doing, int severity, int domain) { @@ -478,66 +370,17 @@ tor_tls_get_error(tor_tls_t *tls, int r, int extra, static void tor_tls_init(void) { + check_no_tls_errors(); + if (!tls_library_is_initialized) { - long version; SSL_library_init(); SSL_load_error_strings(); - version = SSLeay(); - - /* OpenSSL 0.9.8l introduced SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION - * here, but without thinking too hard about it: it turns out that the - * flag in question needed to be set at the last minute, and that it - * conflicted with an existing flag number that had already been added - * in the OpenSSL 1.0.0 betas. OpenSSL 0.9.8m thoughtfully replaced - * the flag with an option and (it seems) broke anything that used - * SSL3_FLAGS_* for the purpose. So we need to know how to do both, - * and we mustn't use the SSL3_FLAGS option with anything besides - * OpenSSL 0.9.8l. - * - * No, we can't just set flag 0x0010 everywhere. It breaks Tor with - * OpenSSL 1.0.0beta3 and later. On the other hand, we might be able to - * set option 0x00040000L everywhere. - * - * No, we can't simply detect whether the flag or the option is present - * in the headers at build-time: some vendors (notably Apple) like to - * leave their headers out of sync with their libraries. - * - * Yes, it _is_ almost as if the OpenSSL developers decided that no - * program should be allowed to use renegotiation unless it first passed - * a test of intelligence and determination. - */ - if (version > OPENSSL_V(0,9,8,'k') && version <= OPENSSL_V(0,9,8,'l')) { - log_info(LD_GENERAL, "OpenSSL %s looks like version 0.9.8l, but " - "some vendors have backported renegotiation code from " - "0.9.8m without updating the version number. " - "I will try SSL3_FLAGS and SSL_OP to enable renegotation.", - SSLeay_version(SSLEAY_VERSION)); - use_unsafe_renegotiation_flag = 1; - use_unsafe_renegotiation_op = 1; - } else if (version > OPENSSL_V(0,9,8,'l')) { - log_info(LD_GENERAL, "OpenSSL %s looks like version 0.9.8m or later; " - "I will try SSL_OP to enable renegotiation", - SSLeay_version(SSLEAY_VERSION)); - use_unsafe_renegotiation_op = 1; - } else if (version <= OPENSSL_V(0,9,8,'k')) { - log_info(LD_GENERAL, "OpenSSL %s [%lx] looks like it's older than " - "0.9.8l, but some vendors have backported 0.9.8l's " - "renegotiation code to earlier versions, and some have " - "backported the code from 0.9.8m or 0.9.8n. I'll set both " - "SSL3_FLAGS and SSL_OP just to be safe.", - SSLeay_version(SSLEAY_VERSION), version); - use_unsafe_renegotiation_flag = 1; - use_unsafe_renegotiation_op = 1; - } else { - /* this is dead code, yes? */ - log_info(LD_GENERAL, "OpenSSL %s has version %lx", - SSLeay_version(SSLEAY_VERSION), version); - } - #if (SIZEOF_VOID_P >= 8 && \ - !defined(OPENSSL_NO_EC) && \ OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1)) + long version = OpenSSL_version_num(); + + /* LCOV_EXCL_START : we can't test these lines on the same machine */ if (version >= OPENSSL_V_SERIES(1,0,1)) { /* Warn if we could *almost* be running with much faster ECDH. If we're built for a 64-bit target, using OpenSSL 1.0.1, but we @@ -564,6 +407,7 @@ tor_tls_init(void) "support (using the enable-ec_nistp_64_gcc_128 option " "when configuring it) would make ECDH much faster."); } + /* LCOV_EXCL_STOP */ #endif tor_tls_allocate_tor_tls_object_ex_data_index(); @@ -576,6 +420,8 @@ tor_tls_init(void) 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; @@ -586,19 +432,13 @@ tor_tls_free_all(void) client_tls_context = NULL; tor_tls_context_decref(ctx); } -#ifdef V2_HANDSHAKE_CLIENT - if (CLIENT_CIPHER_DUMMIES) - tor_free(CLIENT_CIPHER_DUMMIES); - if (CLIENT_CIPHER_STACK) - sk_SSL_CIPHER_free(CLIENT_CIPHER_STACK); -#endif } /** We need to give OpenSSL a callback to verify certificates. This is * it: We always accept peer certs and complete the handshake. We * don't validate them until later. */ -static int +STATIC int always_accept_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) { @@ -613,16 +453,20 @@ tor_x509_name_new(const char *cname) { int nid; X509_NAME *name; + /* LCOV_EXCL_BR_START : these branches will only fail on OOM errors */ if (!(name = X509_NAME_new())) return NULL; if ((nid = OBJ_txt2nid("commonName")) == NID_undef) goto error; if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, (unsigned char*)cname, -1, -1, 0))) goto error; + /* LCOV_EXCL_BR_STOP */ return name; error: + /* LCOV_EXCL_START : these lines will only execute on out of memory errors*/ X509_NAME_free(name); return NULL; + /* LCOV_EXCL_STOP */ } /** Generate and sign an X509 certificate with the public key <b>rsa</b>, @@ -633,12 +477,12 @@ tor_x509_name_new(const char *cname) * * Return a certificate on success, NULL on failure. */ -static X509 * -tor_tls_create_certificate(crypto_pk_t *rsa, - crypto_pk_t *rsa_sign, - const char *cname, - const char *cname_sign, - unsigned int cert_lifetime) +MOCK_IMPL(STATIC X509 *, + tor_tls_create_certificate,(crypto_pk_t *rsa, + crypto_pk_t *rsa_sign, + const char *cname, + const char *cname_sign, + unsigned int cert_lifetime)) { /* OpenSSL generates self-signed certificates with random 64-bit serial * numbers, so let's do that too. */ @@ -657,7 +501,8 @@ tor_tls_create_certificate(crypto_pk_t *rsa, * than having it start right now. Don't choose quite uniformly, since * then we might pick a time where we're about to expire. Lastly, be * sure to start on a day boundary. */ - start_time = time(NULL) - crypto_rand_int(cert_lifetime) + 2*24*3600; + time_t now = time(NULL); + start_time = crypto_rand_time_range(now - cert_lifetime, now) + 2*24*3600; start_time -= start_time % (24*3600); tor_assert(rsa); @@ -674,8 +519,7 @@ tor_tls_create_certificate(crypto_pk_t *rsa, goto error; { /* our serial number is 8 random bytes. */ - if (crypto_rand((char *)serial_tmp, sizeof(serial_tmp)) < 0) - goto error; + crypto_rand((char *)serial_tmp, sizeof(serial_tmp)); if (!(serial_number = BN_bin2bn(serial_tmp, sizeof(serial_tmp), NULL))) goto error; if (!(BN_to_ASN1_INTEGER(serial_number, X509_get_serialNumber(x509)))) @@ -781,13 +625,12 @@ const char UNRESTRICTED_SERVER_CIPHER_LIST[] = * (SSL3_TXT_RSA_NULL_SHA). If you do this, you won't be able to communicate * with any of the "real" Tors, though. */ -#ifdef V2_HANDSHAKE_CLIENT #define CIPHER(id, name) name ":" #define XCIPHER(id, name) /** List of ciphers that clients should advertise, omitting items that * our OpenSSL doesn't know about. */ static const char CLIENT_CIPHER_LIST[] = -#include "./ciphers.inc" +#include "ciphers.inc" /* Tell it not to use SSLv2 ciphers, so that it can select an SSLv3 version * of any cipher we say. */ "!SSLv2" @@ -795,32 +638,9 @@ static const char CLIENT_CIPHER_LIST[] = #undef CIPHER #undef XCIPHER -/** Holds a cipher that we want to advertise, and its 2-byte ID. */ -typedef struct cipher_info_t { unsigned id; const char *name; } cipher_info_t; -/** A list of all the ciphers that clients should advertise, including items - * that OpenSSL might not know about. */ -static const cipher_info_t CLIENT_CIPHER_INFO_LIST[] = { -#define CIPHER(id, name) { id, name }, -#define XCIPHER(id, name) { id, #name }, -#include "./ciphers.inc" -#undef CIPHER -#undef XCIPHER -}; - -/** The length of CLIENT_CIPHER_INFO_LIST and CLIENT_CIPHER_DUMMIES. */ -static const int N_CLIENT_CIPHERS = - sizeof(CLIENT_CIPHER_INFO_LIST)/sizeof(CLIENT_CIPHER_INFO_LIST[0]); -#endif - -#ifndef V2_HANDSHAKE_CLIENT -#undef CLIENT_CIPHER_LIST -#define CLIENT_CIPHER_LIST (TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":" \ - SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) -#endif - /** Free all storage held in <b>cert</b> */ void -tor_cert_free(tor_cert_t *cert) +tor_x509_cert_free(tor_x509_cert_t *cert) { if (! cert) return; @@ -828,18 +648,20 @@ tor_cert_free(tor_cert_t *cert) X509_free(cert->cert); tor_free(cert->encoded); memwipe(cert, 0x03, sizeof(*cert)); + /* LCOV_EXCL_BR_START since cert will never be NULL here */ tor_free(cert); + /* LCOV_EXCL_BR_STOP */ } /** - * Allocate a new tor_cert_t to hold the certificate "x509_cert". + * Allocate a new tor_x509_cert_t to hold the certificate "x509_cert". * * Steals a reference to x509_cert. */ -static tor_cert_t * -tor_cert_new(X509 *x509_cert) +MOCK_IMPL(STATIC tor_x509_cert_t *, + tor_x509_cert_new,(X509 *x509_cert)) { - tor_cert_t *cert; + tor_x509_cert_t *cert; EVP_PKEY *pkey; RSA *rsa; int length; @@ -849,12 +671,14 @@ tor_cert_new(X509 *x509_cert) return NULL; length = i2d_X509(x509_cert, &buf); - cert = tor_malloc_zero(sizeof(tor_cert_t)); + cert = tor_malloc_zero(sizeof(tor_x509_cert_t)); if (length <= 0 || buf == NULL) { + /* LCOV_EXCL_START for the same reason as the exclusion above */ tor_free(cert); log_err(LD_CRYPTO, "Couldn't get length of encoded x509 certificate"); X509_free(x509_cert); return NULL; + /* LCOV_EXCL_STOP */ } cert->encoded_len = (size_t) length; cert->encoded = tor_malloc(length); @@ -863,13 +687,13 @@ tor_cert_new(X509 *x509_cert) cert->cert = x509_cert; - crypto_digest_all(&cert->cert_digests, + crypto_common_digests(&cert->cert_digests, (char*)cert->encoded, cert->encoded_len); if ((pkey = X509_get_pubkey(x509_cert)) && (rsa = EVP_PKEY_get1_RSA(pkey))) { crypto_pk_t *pk = crypto_new_pk_from_rsa_(rsa); - crypto_pk_get_all_digests(pk, &cert->pkey_digests); + crypto_pk_get_common_digests(pk, &cert->pkey_digests); cert->pkey_digests_set = 1; crypto_pk_free(pk); EVP_PKEY_free(pkey); @@ -879,44 +703,48 @@ tor_cert_new(X509 *x509_cert) } /** Read a DER-encoded X509 cert, of length exactly <b>certificate_len</b>, - * from a <b>certificate</b>. Return a newly allocated tor_cert_t on success - * and NULL on failure. */ -tor_cert_t * -tor_cert_decode(const uint8_t *certificate, size_t certificate_len) + * from a <b>certificate</b>. Return a newly allocated tor_x509_cert_t on + * success and NULL on failure. */ +tor_x509_cert_t * +tor_x509_cert_decode(const uint8_t *certificate, size_t certificate_len) { X509 *x509; const unsigned char *cp = (const unsigned char *)certificate; - tor_cert_t *newcert; + tor_x509_cert_t *newcert; tor_assert(certificate); + check_no_tls_errors(); if (certificate_len > INT_MAX) - return NULL; + goto err; x509 = d2i_X509(NULL, &cp, (int)certificate_len); if (!x509) - return NULL; /* Couldn't decode */ + goto err; /* Couldn't decode */ if (cp - certificate != (int)certificate_len) { X509_free(x509); - return NULL; /* Didn't use all the bytes */ + goto err; /* Didn't use all the bytes */ } - newcert = tor_cert_new(x509); + newcert = tor_x509_cert_new(x509); if (!newcert) { - return NULL; + goto err; } if (newcert->encoded_len != certificate_len || fast_memneq(newcert->encoded, certificate, certificate_len)) { /* Cert wasn't in DER */ - tor_cert_free(newcert); - return NULL; + tor_x509_cert_free(newcert); + goto err; } return newcert; + err: + tls_log_errors(NULL, LOG_INFO, LD_CRYPTO, "decoding a certificate"); + return NULL; } /** Set *<b>encoded_out</b> and *<b>size_out</b> to <b>cert</b>'s encoded DER * representation and length, respectively. */ void -tor_cert_get_der(const tor_cert_t *cert, +tor_x509_cert_get_der(const tor_x509_cert_t *cert, const uint8_t **encoded_out, size_t *size_out) { tor_assert(cert); @@ -928,8 +756,8 @@ tor_cert_get_der(const tor_cert_t *cert, /** Return a set of digests for the public key in <b>cert</b>, or NULL if this * cert's public key is not one we know how to take the digest of. */ -const digests_t * -tor_cert_get_id_digests(const tor_cert_t *cert) +const common_digests_t * +tor_x509_cert_get_id_digests(const tor_x509_cert_t *cert) { if (cert->pkey_digests_set) return &cert->pkey_digests; @@ -938,8 +766,8 @@ tor_cert_get_id_digests(const tor_cert_t *cert) } /** Return a set of digests for the public key in <b>cert</b>. */ -const digests_t * -tor_cert_get_cert_digests(const tor_cert_t *cert) +const common_digests_t * +tor_x509_cert_get_cert_digests(const tor_x509_cert_t *cert) { return &cert->cert_digests; } @@ -952,12 +780,14 @@ tor_tls_context_decref(tor_tls_context_t *ctx) tor_assert(ctx); if (--ctx->refcnt == 0) { SSL_CTX_free(ctx->ctx); - tor_cert_free(ctx->my_link_cert); - tor_cert_free(ctx->my_id_cert); - tor_cert_free(ctx->my_auth_cert); + tor_x509_cert_free(ctx->my_link_cert); + tor_x509_cert_free(ctx->my_id_cert); + tor_x509_cert_free(ctx->my_auth_cert); crypto_pk_free(ctx->link_key); crypto_pk_free(ctx->auth_key); + /* LCOV_EXCL_BR_START since ctx will never be NULL here */ tor_free(ctx); + /* LCOV_EXCL_BR_STOP */ } } @@ -968,8 +798,8 @@ tor_tls_context_decref(tor_tls_context_t *ctx) * client mode. */ int tor_tls_get_my_certs(int server, - const tor_cert_t **link_cert_out, - const tor_cert_t **id_cert_out) + const tor_x509_cert_t **link_cert_out, + const tor_x509_cert_t **id_cert_out) { tor_tls_context_t *ctx = server ? server_tls_context : client_tls_context; if (! ctx) @@ -998,7 +828,7 @@ tor_tls_get_my_client_auth_key(void) * certifies. Return NULL if the cert's key is not RSA. */ crypto_pk_t * -tor_tls_cert_get_key(tor_cert_t *cert) +tor_tls_cert_get_key(tor_x509_cert_t *cert) { crypto_pk_t *result = NULL; EVP_PKEY *pkey = X509_get_pubkey(cert->cert); @@ -1018,8 +848,8 @@ tor_tls_cert_get_key(tor_cert_t *cert) /** Return true iff the other side of <b>tls</b> has authenticated to us, and * the key certified in <b>cert</b> is the same as the key they used to do it. */ -int -tor_tls_cert_matches_key(const tor_tls_t *tls, const tor_cert_t *cert) +MOCK_IMPL(int, +tor_tls_cert_matches_key,(const tor_tls_t *tls, const tor_x509_cert_t *cert)) { X509 *peercert = SSL_get_peer_certificate(tls->ssl); EVP_PKEY *link_key = NULL, *cert_key = NULL; @@ -1048,37 +878,46 @@ tor_tls_cert_matches_key(const tor_tls_t *tls, const tor_cert_t *cert) * we couldn't check it. */ int tor_tls_cert_is_valid(int severity, - const tor_cert_t *cert, - const tor_cert_t *signing_cert, + const tor_x509_cert_t *cert, + const tor_x509_cert_t *signing_cert, int check_rsa_1024) { + check_no_tls_errors(); EVP_PKEY *cert_key; - EVP_PKEY *signing_key = X509_get_pubkey(signing_cert->cert); int r, key_ok = 0; + + if (!signing_cert || !cert) + goto bad; + + EVP_PKEY *signing_key = X509_get_pubkey(signing_cert->cert); if (!signing_key) - return 0; + goto bad; r = X509_verify(cert->cert, signing_key); EVP_PKEY_free(signing_key); if (r <= 0) - return 0; + goto bad; /* okay, the signature checked out right. Now let's check the check the * lifetime. */ if (check_cert_lifetime_internal(severity, cert->cert, 48*60*60, 30*24*60*60) < 0) - return 0; + goto bad; cert_key = X509_get_pubkey(cert->cert); if (check_rsa_1024 && cert_key) { RSA *rsa = EVP_PKEY_get1_RSA(cert_key); +#ifdef OPENSSL_1_1_API + if (rsa && RSA_bits(rsa) == 1024) +#else if (rsa && BN_num_bits(rsa->n) == 1024) +#endif key_ok = 1; if (rsa) RSA_free(rsa); } else if (cert_key) { int min_bits = 1024; #ifdef EVP_PKEY_EC - if (EVP_PKEY_type(cert_key->type) == EVP_PKEY_EC) + if (EVP_PKEY_base_id(cert_key) == EVP_PKEY_EC) min_bits = 128; #endif if (EVP_PKEY_bits(cert_key) >= min_bits) @@ -1086,11 +925,14 @@ tor_tls_cert_is_valid(int severity, } EVP_PKEY_free(cert_key); if (!key_ok) - return 0; + goto bad; /* XXXX compare DNs or anything? */ return 1; + bad: + tls_log_errors(NULL, LOG_INFO, LD_CRYPTO, "checking a certificate"); + return 0; } /** Increase the reference count of <b>ctx</b>. */ @@ -1117,6 +959,7 @@ tor_tls_context_init(unsigned flags, 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; @@ -1161,6 +1004,7 @@ tor_tls_context_init(unsigned flags, 1); } + tls_log_errors(NULL, LOG_WARN, LD_CRYPTO, "constructing a TLS context"); return MIN(rv1, rv2); } @@ -1170,7 +1014,7 @@ tor_tls_context_init(unsigned flags, * it generates new certificates; all new connections will use * the new SSL context. */ -static int +STATIC int tor_tls_context_init_one(tor_tls_context_t **ppcontext, crypto_pk_t *identity, unsigned int key_lifetime, @@ -1197,11 +1041,14 @@ tor_tls_context_init_one(tor_tls_context_t **ppcontext, return ((new_ctx != NULL) ? 0 : -1); } +/** The group we should use for ecdhe when none was selected. */ +#define NID_tor_default_ecdhe_group NID_X9_62_prime256v1 + /** 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. */ -static tor_tls_context_t * +STATIC tor_tls_context_t * tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, unsigned flags, int is_client) { @@ -1249,9 +1096,9 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, result = tor_malloc_zero(sizeof(tor_tls_context_t)); result->refcnt = 1; if (!is_client) { - result->my_link_cert = tor_cert_new(X509_dup(cert)); - result->my_id_cert = tor_cert_new(X509_dup(idcert)); - result->my_auth_cert = tor_cert_new(X509_dup(authcert)); + result->my_link_cert = tor_x509_cert_new(X509_dup(cert)); + result->my_id_cert = tor_x509_cert_new(X509_dup(idcert)); + result->my_auth_cert = tor_x509_cert_new(X509_dup(authcert)); if (!result->my_link_cert || !result->my_id_cert || !result->my_auth_cert) goto error; result->link_key = crypto_pk_dup_key(rsa); @@ -1268,8 +1115,13 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, #endif /* Tell OpenSSL to use TLS 1.0 or later but not SSL2 or SSL3. */ +#ifdef HAVE_TLS_METHOD + if (!(result->ctx = SSL_CTX_new(TLS_method()))) + goto error; +#else if (!(result->ctx = SSL_CTX_new(SSLv23_method()))) goto error; +#endif SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv2); SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv3); @@ -1277,23 +1129,6 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, * historically been chosen for fingerprinting resistance. */ SSL_CTX_set_options(result->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); - /* Disable TLS1.1 and TLS1.2 if they exist. We need to do this to - * workaround a bug present in all OpenSSL 1.0.1 versions (as of 1 - * June 2012), wherein renegotiating while using one of these TLS - * protocols will cause the client to send a TLS 1.0 ServerHello - * rather than a ServerHello written with the appropriate protocol - * version. Once some version of OpenSSL does TLS1.1 and TLS1.2 - * renegotiation properly, we can turn them back on when built with - * that version. */ -#if OPENSSL_VERSION_NUMBER < OPENSSL_V(1,0,1,'e') -#ifdef SSL_OP_NO_TLSv1_2 - SSL_CTX_set_options(result->ctx, SSL_OP_NO_TLSv1_2); -#endif -#ifdef SSL_OP_NO_TLSv1_1 - SSL_CTX_set_options(result->ctx, SSL_OP_NO_TLSv1_1); -#endif -#endif - /* Disable TLS tickets if they're supported. We never want to use them; * using them can make our perfect forward secrecy a little worse, *and* * create an opportunity to fingerprint us (since it's unusual to use them @@ -1310,24 +1145,6 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, } #endif - /* XXX This block is now obsolete. */ - if ( -#ifdef DISABLE_SSL3_HANDSHAKE - 1 || -#endif - SSLeay() < OPENSSL_V(0,9,8,'s') || - (SSLeay() >= OPENSSL_V_SERIES(0,9,9) && - SSLeay() < OPENSSL_V(1,0,0,'f'))) { - /* And not SSL3 if it's subject to CVE-2011-4576. */ - log_info(LD_NET, "Disabling SSLv3 because this OpenSSL version " - "might otherwise be vulnerable to CVE-2011-4576 " - "(compile-time version %08lx (%s); " - "runtime version %08lx (%s))", - (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT, - (unsigned long)SSLeay(), SSLeay_version(SSLEAY_VERSION)); - SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv3); - } - SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_DH_USE); SSL_CTX_set_options(result->ctx, SSL_OP_SINGLE_ECDH_USE); @@ -1338,16 +1155,21 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, /* Yes, we know what we are doing here. No, we do not treat a renegotiation * as authenticating any earlier-received data. */ - if (use_unsafe_renegotiation_op) { + { SSL_CTX_set_options(result->ctx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); } +#ifdef SSL_OP_NO_COMPRESSION + SSL_CTX_set_options(result->ctx, SSL_OP_NO_COMPRESSION); +#endif +#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,1,0) #ifndef OPENSSL_NO_COMP /* Don't actually allow compression; it uses ram and time, but the data * we transmit is all encrypted anyway. */ if (result->ctx->comp_methods) result->ctx->comp_methods = NULL; #endif +#endif #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(result->ctx, SSL_MODE_RELEASE_BUFFERS); #endif @@ -1382,8 +1204,6 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, SSL_CTX_set_tmp_dh(result->ctx, crypto_dh_get_dh_(dh)); crypto_dh_free(dh); } -#if (!defined(OPENSSL_NO_EC) && \ - OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0)) if (! is_client) { int nid; EC_KEY *ec_key; @@ -1392,16 +1212,13 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, else if (flags & TOR_TLS_CTX_USE_ECDHE_P256) nid = NID_X9_62_prime256v1; else - nid = NID_X9_62_prime256v1; + nid = NID_tor_default_ecdhe_group; /* Use P-256 for ECDHE. */ ec_key = EC_KEY_new_by_curve_name(nid); if (ec_key != NULL) /*XXXX Handle errors? */ SSL_CTX_set_tmp_ecdh(result->ctx, ec_key); EC_KEY_free(ec_key); } -#else - (void)flags; -#endif SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER, always_accept_verify_cb); /* let us realloc bufs that we're writing from */ @@ -1438,11 +1255,13 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, } /** Invoked when a TLS state changes: log the change at severity 'debug' */ -static void +STATIC void tor_tls_debug_state_callback(const SSL *ssl, int type, int val) { + /* LCOV_EXCL_START since this depends on whether debug is captured or not */ log_debug(LD_HANDSHAKE, "SSL %p is now in state %s [type=%d,val=%d].", ssl, SSL_state_string_long(ssl), type, val); + /* LCOV_EXCL_STOP */ } /* Return the name of the negotiated ciphersuite in use on <b>tls</b> */ @@ -1452,13 +1271,11 @@ tor_tls_get_ciphersuite_name(tor_tls_t *tls) return SSL_get_cipher(tls->ssl); } -#ifdef V2_HANDSHAKE_SERVER - /* Here's the old V2 cipher list we sent from 0.2.1.1-alpha up to * 0.2.3.17-beta. If a client is using this list, we can't believe the ciphers * that it claims to support. We'll prune this list to remove the ciphers * *we* don't recognize. */ -static uint16_t v2_cipher_list[] = { +STATIC uint16_t v2_cipher_list[] = { 0xc00a, /* TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA */ 0xc014, /* TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA */ 0x0039, /* TLS1_TXT_DHE_RSA_WITH_AES_256_SHA */ @@ -1494,11 +1311,27 @@ static int v2_cipher_list_pruned = 0; /** Return 0 if <b>m</b> does not support the cipher with ID <b>cipher</b>; * return 1 if it does support it, or if we have no way to tell. */ -static int -find_cipher_by_id(const SSL_METHOD *m, uint16_t cipher) +STATIC int +find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher) { const SSL_CIPHER *c; -#ifdef HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR +#ifdef HAVE_SSL_CIPHER_FIND + (void) m; + { + unsigned char cipherid[3]; + tor_assert(ssl); + set_uint16(cipherid, htons(cipher)); + cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting + * with a two-byte 'cipherid', it may look for a v2 + * cipher with the appropriate 3 bytes. */ + c = SSL_CIPHER_find((SSL*)ssl, cipherid); + if (c) + tor_assert((SSL_CIPHER_get_id(c) & 0xffff) == cipher); + return c != NULL; + } +#else + +# if defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR) if (m && m->get_cipher_by_char) { unsigned char cipherid[3]; set_uint16(cipherid, htons(cipher)); @@ -1509,8 +1342,9 @@ find_cipher_by_id(const SSL_METHOD *m, uint16_t cipher) if (c) tor_assert((c->id & 0xffff) == cipher); return c != NULL; - } else -#endif + } +# endif +# ifndef OPENSSL_1_1_API if (m && m->get_cipher && m->num_ciphers) { /* It would seem that some of the "let's-clean-up-openssl" forks have * removed the get_cipher_by_char function. Okay, so now you get a @@ -1524,23 +1358,31 @@ find_cipher_by_id(const SSL_METHOD *m, uint16_t cipher) } } return 0; - } else { - return 1; /* No way to search */ } +# endif + (void) ssl; + (void) m; + (void) cipher; + return 1; /* No way to search */ +#endif } /** Remove from v2_cipher_list every cipher that we don't support, so that * comparing v2_cipher_list to a client's cipher list will give a sensible * result. */ static void -prune_v2_cipher_list(void) +prune_v2_cipher_list(const SSL *ssl) { uint16_t *inp, *outp; +#ifdef HAVE_TLS_METHOD + const SSL_METHOD *m = TLS_method(); +#else const SSL_METHOD *m = SSLv23_method(); +#endif inp = outp = v2_cipher_list; while (*inp) { - if (find_cipher_by_id(m, *inp)) { + if (find_cipher_by_id(ssl, m, *inp)) { *outp++ = *inp++; } else { inp++; @@ -1555,14 +1397,14 @@ prune_v2_cipher_list(void) * client it is. Return one of CIPHERS_ERR, CIPHERS_V1, CIPHERS_V2, * CIPHERS_UNRESTRICTED. **/ -static int +STATIC int tor_tls_classify_client_ciphers(const SSL *ssl, STACK_OF(SSL_CIPHER) *peer_ciphers) { int i, res; tor_tls_t *tor_tls; if (PREDICT_UNLIKELY(!v2_cipher_list_pruned)) - prune_v2_cipher_list(); + prune_v2_cipher_list(ssl); tor_tls = tor_tls_get_by_ssl(ssl); if (tor_tls && tor_tls->client_cipher_list_type) @@ -1578,7 +1420,7 @@ tor_tls_classify_client_ciphers(const SSL *ssl, /* Now we need to see if there are any ciphers whose presence means we're * dealing with an updated Tor. */ for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) { - SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i); + const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i); const char *ciphername = SSL_CIPHER_get_name(cipher); if (strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) && strcmp(ciphername, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA) && @@ -1595,8 +1437,8 @@ tor_tls_classify_client_ciphers(const SSL *ssl, { const uint16_t *v2_cipher = v2_cipher_list; for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) { - SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i); - uint16_t id = cipher->id & 0xffff; + const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i); + uint16_t id = SSL_CIPHER_get_id(cipher) & 0xffff; if (id == 0x00ff) /* extended renegotiation indicator. */ continue; if (!id || id != *v2_cipher) { @@ -1617,7 +1459,7 @@ tor_tls_classify_client_ciphers(const SSL *ssl, smartlist_t *elts = smartlist_new(); char *s; for (i = 0; i < sk_SSL_CIPHER_num(peer_ciphers); ++i) { - SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i); + const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(peer_ciphers, i); const char *ciphername = SSL_CIPHER_get_name(cipher); smartlist_add(elts, (char*)ciphername); } @@ -1637,16 +1479,22 @@ tor_tls_classify_client_ciphers(const SSL *ssl, /** Return true iff the cipher list suggested by the client for <b>ssl</b> is * a list that indicates that the client knows how to do the v2 TLS connection * handshake. */ -static int +STATIC int tor_tls_client_is_using_v2_ciphers(const SSL *ssl) { + STACK_OF(SSL_CIPHER) *ciphers; +#ifdef HAVE_SSL_GET_CLIENT_CIPHERS + ciphers = SSL_get_client_ciphers(ssl); +#else SSL_SESSION *session; if (!(session = SSL_get_session((SSL *)ssl))) { log_info(LD_NET, "No session on TLS?"); return CIPHERS_ERR; } + ciphers = session->ciphers; +#endif - return tor_tls_classify_client_ciphers(ssl, session->ciphers) >= CIPHERS_V2; + return tor_tls_classify_client_ciphers(ssl, ciphers) >= CIPHERS_V2; } /** Invoked when we're accepting a connection on <b>ssl</b>, and the connection @@ -1655,7 +1503,7 @@ tor_tls_client_is_using_v2_ciphers(const SSL *ssl) * do not send or request extra certificates in v2 handshakes.</li> * <li>To detect renegotiation</li></ul> */ -static void +STATIC void tor_tls_server_info_callback(const SSL *ssl, int type, int val) { tor_tls_t *tls; @@ -1665,10 +1513,10 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val) if (type != SSL_CB_ACCEPT_LOOP) return; - if ((ssl->state != SSL3_ST_SW_SRVR_HELLO_A) && - (ssl->state != SSL3_ST_SW_SRVR_HELLO_B)) - return; + OSSL_HANDSHAKE_STATE ssl_state = SSL_get_state(ssl); + if (! STATE_IS_SW_SERVER_HELLO(ssl_state)) + return; tls = tor_tls_get_by_ssl(ssl); if (tls) { /* Check whether we're watching for renegotiates. If so, this is one! */ @@ -1697,18 +1545,14 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val) if (tls) { tls->wasV2Handshake = 1; -#ifdef USE_BUFFEREVENTS - if (use_unsafe_renegotiation_flag) - tls->ssl->s3->flags |= SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; -#endif } else { + /* LCOV_EXCL_START this line is not reachable */ log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!"); + /* LCOV_EXCL_STOP */ } } } -#endif -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0) /** Callback to get invoked on a server after we've read the list of ciphers * the client supports, but before we pick our own ciphersuite. * @@ -1721,10 +1565,11 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val) * authentication on the fly. But as long as we return 0, we won't actually be * setting up a shared secret, and all will be fine. */ -static int +STATIC int tor_tls_session_secret_cb(SSL *ssl, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, - SSL_CIPHER **cipher, void *arg) + CONST_IF_OPENSSL_1_1_API SSL_CIPHER **cipher, + void *arg) { (void) secret; (void) secret_len; @@ -1746,128 +1591,6 @@ tor_tls_setup_session_secret_cb(tor_tls_t *tls) { SSL_set_session_secret_cb(tls->ssl, tor_tls_session_secret_cb, NULL); } -#else -#define tor_tls_setup_session_secret_cb(tls) STMT_NIL -#endif - -/** Explain which ciphers we're missing. */ -static void -log_unsupported_ciphers(smartlist_t *unsupported) -{ - char *joined; - - log_notice(LD_NET, "We weren't able to find support for all of the " - "TLS ciphersuites that we wanted to advertise. This won't " - "hurt security, but it might make your Tor (if run as a client) " - "more easy for censors to block."); - - if (SSLeay() < 0x10000000L) { - log_notice(LD_NET, "To correct this, use a more recent OpenSSL, " - "built without disabling any secure ciphers or features."); - } else { - log_notice(LD_NET, "To correct this, use a version of OpenSSL " - "built with none of its ciphers disabled."); - } - - joined = smartlist_join_strings(unsupported, ":", 0, NULL); - log_info(LD_NET, "The unsupported ciphers were: %s", joined); - tor_free(joined); -} - -/** Replace *<b>ciphers</b> with a new list of SSL ciphersuites: specifically, - * a list designed to mimic a common web browser. We might not be able to do - * that if OpenSSL doesn't support all the ciphers we want. Some of the - * ciphers in the list won't actually be implemented by OpenSSL: that's okay - * so long as the server doesn't select them. - * - * [If the server <b>does</b> select a bogus cipher, we won't crash or - * anything; we'll just fail later when we try to look up the cipher in - * ssl->cipher_list_by_id.] - */ -static void -rectify_client_ciphers(STACK_OF(SSL_CIPHER) **ciphers) -{ -#ifdef V2_HANDSHAKE_CLIENT - if (PREDICT_UNLIKELY(!CLIENT_CIPHER_STACK)) { - /* We need to set CLIENT_CIPHER_STACK to an array of the ciphers - * we want to use/advertise. */ - int i = 0, j = 0; - smartlist_t *unsupported = smartlist_new(); - - /* First, create a dummy SSL_CIPHER for every cipher. */ - CLIENT_CIPHER_DUMMIES = - tor_malloc_zero(sizeof(SSL_CIPHER)*N_CLIENT_CIPHERS); - for (i=0; i < N_CLIENT_CIPHERS; ++i) { - CLIENT_CIPHER_DUMMIES[i].valid = 1; - /* The "3<<24" here signifies that the cipher is supposed to work with - * SSL3 and TLS1. */ - CLIENT_CIPHER_DUMMIES[i].id = CLIENT_CIPHER_INFO_LIST[i].id | (3<<24); - CLIENT_CIPHER_DUMMIES[i].name = CLIENT_CIPHER_INFO_LIST[i].name; - } - - CLIENT_CIPHER_STACK = sk_SSL_CIPHER_new_null(); - tor_assert(CLIENT_CIPHER_STACK); - - log_debug(LD_NET, "List was: %s", CLIENT_CIPHER_LIST); - for (j = 0; j < sk_SSL_CIPHER_num(*ciphers); ++j) { - SSL_CIPHER *cipher = sk_SSL_CIPHER_value(*ciphers, j); - log_debug(LD_NET, "Cipher %d: %lx %s", j, cipher->id, cipher->name); - } - - /* Then copy as many ciphers as we can from the good list, inserting - * dummies as needed. Let j be an index into list of ciphers we have - * (*ciphers) and let i be an index into the ciphers we want - * (CLIENT_INFO_CIPHER_LIST). We are building a list of ciphers in - * CLIENT_CIPHER_STACK. - */ - for (i = j = 0; i < N_CLIENT_CIPHERS; ) { - SSL_CIPHER *cipher = NULL; - if (j < sk_SSL_CIPHER_num(*ciphers)) - cipher = sk_SSL_CIPHER_value(*ciphers, j); - if (cipher && ((cipher->id >> 24) & 0xff) != 3) { - /* Skip over non-v3 ciphers entirely. (This should no longer be - * needed, thanks to saying !SSLv2 above.) */ - log_debug(LD_NET, "Skipping v%d cipher %s", - (int)((cipher->id>>24) & 0xff), - cipher->name); - ++j; - } else if (cipher && - (cipher->id & 0xffff) == CLIENT_CIPHER_INFO_LIST[i].id) { - /* "cipher" is the cipher we expect. Put it on the list. */ - log_debug(LD_NET, "Found cipher %s", cipher->name); - sk_SSL_CIPHER_push(CLIENT_CIPHER_STACK, cipher); - ++j; - ++i; - } else if (!strcmp(CLIENT_CIPHER_DUMMIES[i].name, - "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA")) { - /* We found bogus cipher 0xfeff, which OpenSSL doesn't support and - * never has. For this one, we need a dummy. */ - log_debug(LD_NET, "Inserting fake %s", CLIENT_CIPHER_DUMMIES[i].name); - sk_SSL_CIPHER_push(CLIENT_CIPHER_STACK, &CLIENT_CIPHER_DUMMIES[i]); - ++i; - } else { - /* OpenSSL doesn't have this one. */ - log_debug(LD_NET, "Completely omitting unsupported cipher %s", - CLIENT_CIPHER_INFO_LIST[i].name); - smartlist_add(unsupported, (char*) CLIENT_CIPHER_INFO_LIST[i].name); - ++i; - } - } - - if (smartlist_len(unsupported)) - log_unsupported_ciphers(unsupported); - - smartlist_free(unsupported); - } - - sk_SSL_CIPHER_free(*ciphers); - *ciphers = sk_SSL_CIPHER_dup(CLIENT_CIPHER_STACK); - tor_assert(*ciphers); - -#else - (void)ciphers; -#endif -} /** Create a new TLS object from a file descriptor, and a flag to * determine whether it is functioning as a server. @@ -1881,11 +1604,12 @@ tor_tls_new(int sock, int isServer) client_tls_context; result->magic = TOR_TLS_MAGIC; + check_no_tls_errors(); 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; + goto err; } #ifdef SSL_set_tlsext_host_name @@ -1905,10 +1629,8 @@ tor_tls_new(int sock, int isServer) #endif SSL_free(result->ssl); tor_free(result); - return NULL; + goto err; } - if (!isServer) - rectify_client_ciphers(&result->ssl->cipher_list); result->socket = sock; bio = BIO_new_socket(sock, BIO_NOCLOSE); if (! bio) { @@ -1918,7 +1640,7 @@ tor_tls_new(int sock, int isServer) #endif SSL_free(result->ssl); tor_free(result); - return NULL; + goto err; } { int set_worked = @@ -1934,24 +1656,25 @@ tor_tls_new(int sock, int isServer) result->state = TOR_TLS_ST_HANDSHAKE; result->isServer = isServer; result->wantwrite_n = 0; - result->last_write_count = BIO_number_written(bio); - result->last_read_count = BIO_number_read(bio); + result->last_write_count = (unsigned long) BIO_number_written(bio); + result->last_read_count = (unsigned long) BIO_number_read(bio); if (result->last_write_count || result->last_read_count) { log_warn(LD_NET, "Newly created BIO has read count %lu, write count %lu", result->last_read_count, result->last_write_count); } -#ifdef V2_HANDSHAKE_SERVER if (isServer) { SSL_set_info_callback(result->ssl, tor_tls_server_info_callback); - } else -#endif - { + } else { SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback); } if (isServer) tor_tls_setup_session_secret_cb(result); + goto done; + err: + result = NULL; + done: /* Not expected to get called. */ tls_log_errors(NULL, LOG_WARN, LD_NET, "creating tor_tls_t object"); return result; @@ -1980,13 +1703,11 @@ tor_tls_set_renegotiate_callback(tor_tls_t *tls, tls->negotiated_callback = cb; tls->callback_arg = arg; tls->got_renegotiate = 0; -#ifdef V2_HANDSHAKE_SERVER if (cb) { SSL_set_info_callback(tls->ssl, tor_tls_server_info_callback); } else { SSL_set_info_callback(tls->ssl, tor_tls_debug_state_callback); } -#endif } /** If this version of openssl requires it, turn on renegotiation on @@ -1997,13 +1718,8 @@ tor_tls_unblock_renegotiation(tor_tls_t *tls) { /* Yes, we know what we are doing here. No, we do not treat a renegotiation * as authenticating any earlier-received data. */ - if (use_unsafe_renegotiation_flag) { - tls->ssl->s3->flags |= SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; - } - if (use_unsafe_renegotiation_op) { - SSL_set_options(tls->ssl, - SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); - } + SSL_set_options(tls->ssl, + SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); } /** If this version of openssl supports it, turn off renegotiation on @@ -2013,21 +1729,24 @@ tor_tls_unblock_renegotiation(tor_tls_t *tls) void tor_tls_block_renegotiation(tor_tls_t *tls) { +#ifdef SUPPORT_UNSAFE_RENEGOTIATION_FLAG tls->ssl->s3->flags &= ~SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; +#else + (void) tls; +#endif } /** Assert that the flags that allow legacy renegotiation are still set */ void tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls) { - if (use_unsafe_renegotiation_flag) { - tor_assert(0 != (tls->ssl->s3->flags & - SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)); - } - if (use_unsafe_renegotiation_op) { - long options = SSL_get_options(tls->ssl); - tor_assert(0 != (options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)); - } +#if defined(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) && \ + SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION != 0 + long options = SSL_get_options(tls->ssl); + tor_assert(0 != (options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)); +#else + (void) tls; +#endif } /** Return whether this tls initiated the connect (client) or @@ -2070,8 +1789,8 @@ tor_tls_free(tor_tls_t *tls) * number of characters read. On failure, returns TOR_TLS_ERROR, * TOR_TLS_CLOSE, TOR_TLS_WANTREAD, or TOR_TLS_WANTWRITE. */ -int -tor_tls_read(tor_tls_t *tls, char *cp, size_t len) +MOCK_IMPL(int, +tor_tls_read,(tor_tls_t *tls, char *cp, size_t len)) { int r, err; tor_assert(tls); @@ -2080,7 +1799,6 @@ tor_tls_read(tor_tls_t *tls, char *cp, size_t len) tor_assert(len<INT_MAX); r = SSL_read(tls->ssl, cp, (int)len); if (r > 0) { -#ifdef V2_HANDSHAKE_SERVER if (tls->got_renegotiate) { /* Renegotiation happened! */ log_info(LD_NET, "Got a TLS renegotiation from %s", ADDR(tls)); @@ -2088,7 +1806,6 @@ tor_tls_read(tor_tls_t *tls, char *cp, size_t len) tls->negotiated_callback(tls, tls->callback_arg); tls->got_renegotiate = 0; } -#endif return r; } err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET); @@ -2105,10 +1822,10 @@ tor_tls_read(tor_tls_t *tls, char *cp, size_t len) /** Total number of bytes that we've used TLS to send. Used to track TLS * overhead. */ -static uint64_t total_bytes_written_over_tls = 0; +STATIC uint64_t total_bytes_written_over_tls = 0; /** Total number of bytes that TLS has put on the network for us. Used to * track TLS overhead. */ -static uint64_t total_bytes_written_by_tls = 0; +STATIC uint64_t total_bytes_written_by_tls = 0; /** Underlying function for TLS writing. Write up to <b>n</b> * characters from <b>cp</b> onto <b>tls</b>. On success, returns the @@ -2153,12 +1870,14 @@ int tor_tls_handshake(tor_tls_t *tls) { int r; - int oldstate; tor_assert(tls); tor_assert(tls->ssl); tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE); + check_no_tls_errors(); - oldstate = tls->ssl->state; + + OSSL_HANDSHAKE_STATE oldstate = SSL_get_state(tls->ssl); + if (tls->isServer) { log_debug(LD_HANDSHAKE, "About to call SSL_accept on %p (%s)", tls, SSL_state_string_long(tls->ssl)); @@ -2168,7 +1887,10 @@ tor_tls_handshake(tor_tls_t *tls) SSL_state_string_long(tls->ssl)); r = SSL_connect(tls->ssl); } - if (oldstate != tls->ssl->state) + + OSSL_HANDSHAKE_STATE newstate = SSL_get_state(tls->ssl); + + if (oldstate != newstate) log_debug(LD_HANDSHAKE, "After call, %p was in state %s", tls, SSL_state_string_long(tls->ssl)); /* We need to call this here and not earlier, since OpenSSL has a penchant @@ -2199,12 +1921,11 @@ int tor_tls_finish_handshake(tor_tls_t *tls) { int r = TOR_TLS_DONE; + check_no_tls_errors(); if (tls->isServer) { SSL_set_info_callback(tls->ssl, NULL); SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, always_accept_verify_cb); - /* There doesn't seem to be a clear OpenSSL API to clear mode flags. */ - tls->ssl->mode &= ~SSL_MODE_NO_AUTO_CHAIN; -#ifdef V2_HANDSHAKE_SERVER + SSL_clear_mode(tls->ssl, SSL_MODE_NO_AUTO_CHAIN); if (tor_tls_client_is_using_v2_ciphers(tls->ssl)) { /* This check is redundant, but back when we did it in the callback, * we might have not been able to look up the tor_tls_t if the code @@ -2219,78 +1940,19 @@ tor_tls_finish_handshake(tor_tls_t *tls) } else { tls->wasV2Handshake = 0; } -#endif } else { -#ifdef V2_HANDSHAKE_CLIENT - /* If we got no ID cert, we're a v2 handshake. */ - X509 *cert = SSL_get_peer_certificate(tls->ssl); - STACK_OF(X509) *chain = SSL_get_peer_cert_chain(tls->ssl); - int n_certs = sk_X509_num(chain); - if (n_certs > 1 || (n_certs == 1 && cert != sk_X509_value(chain, 0))) { - log_debug(LD_HANDSHAKE, "Server sent back multiple certificates; it " - "looks like a v1 handshake on %p", tls); - tls->wasV2Handshake = 0; - } else { - log_debug(LD_HANDSHAKE, - "Server sent back a single certificate; looks like " - "a v2 handshake on %p.", tls); - tls->wasV2Handshake = 1; - } - if (cert) - X509_free(cert); -#endif + /* Client-side */ + tls->wasV2Handshake = 1; + /* XXXX this can move, probably? -NM */ if (SSL_set_cipher_list(tls->ssl, SERVER_CIPHER_LIST) == 0) { tls_log_errors(NULL, LOG_WARN, LD_HANDSHAKE, "re-setting ciphers"); r = TOR_TLS_ERROR_MISC; } } + tls_log_errors(NULL, LOG_WARN, LD_NET, "finishing the handshake"); return r; } -#ifdef USE_BUFFEREVENTS -/** Put <b>tls</b>, which must be a client connection, into renegotiation - * mode. */ -int -tor_tls_start_renegotiating(tor_tls_t *tls) -{ - int r = SSL_renegotiate(tls->ssl); - if (r <= 0) { - return tor_tls_get_error(tls, r, 0, "renegotiating", LOG_WARN, - LD_HANDSHAKE); - } - return 0; -} -#endif - -/** Client only: Renegotiate a TLS session. When finished, returns - * TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD, or - * TOR_TLS_WANTWRITE. - */ -int -tor_tls_renegotiate(tor_tls_t *tls) -{ - int r; - tor_assert(tls); - /* We could do server-initiated renegotiation too, but that would be tricky. - * Instead of "SSL_renegotiate, then SSL_do_handshake until done" */ - tor_assert(!tls->isServer); - if (tls->state != TOR_TLS_ST_RENEGOTIATE) { - int r = SSL_renegotiate(tls->ssl); - if (r <= 0) { - return tor_tls_get_error(tls, r, 0, "renegotiating", LOG_WARN, - LD_HANDSHAKE); - } - tls->state = TOR_TLS_ST_RENEGOTIATE; - } - r = SSL_do_handshake(tls->ssl); - if (r == 1) { - tls->state = TOR_TLS_ST_OPEN; - return TOR_TLS_DONE; - } else - return tor_tls_get_error(tls, r, 0, "renegotiating handshake", LOG_INFO, - LD_HANDSHAKE); -} - /** Shut down an open tls connection <b>tls</b>. When finished, returns * TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD, * or TOR_TLS_WANTWRITE. @@ -2302,6 +1964,7 @@ tor_tls_shutdown(tor_tls_t *tls) char buf[128]; tor_assert(tls); tor_assert(tls->ssl); + check_no_tls_errors(); while (1) { if (tls->state == TOR_TLS_ST_SENTCLOSE) { @@ -2368,15 +2031,15 @@ tor_tls_peer_has_cert(tor_tls_t *tls) } /** Return the peer certificate, or NULL if there isn't one. */ -tor_cert_t * -tor_tls_get_peer_cert(tor_tls_t *tls) +MOCK_IMPL(tor_x509_cert_t *, +tor_tls_get_peer_cert,(tor_tls_t *tls)) { X509 *cert; cert = SSL_get_peer_certificate(tls->ssl); tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "getting peer certificate"); if (!cert) return NULL; - return tor_cert_new(cert); + return tor_x509_cert_new(cert); } /** Warn that a certificate lifetime extends through a certain range. */ @@ -2400,7 +2063,7 @@ log_cert_lifetime(int severity, const X509 *cert, const char *problem) if (!(bio = BIO_new(BIO_s_mem()))) { log_warn(LD_GENERAL, "Couldn't allocate BIO!"); goto end; } - if (!(ASN1_TIME_print(bio, X509_get_notBefore(cert)))) { + if (!(ASN1_TIME_print(bio, X509_get_notBefore_const(cert)))) { tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime"); goto end; } @@ -2408,7 +2071,7 @@ log_cert_lifetime(int severity, const X509 *cert, const char *problem) s1 = tor_strndup(buf->data, buf->length); (void)BIO_reset(bio); - if (!(ASN1_TIME_print(bio, X509_get_notAfter(cert)))) { + if (!(ASN1_TIME_print(bio, X509_get_notAfter_const(cert)))) { tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime"); goto end; } @@ -2443,15 +2106,14 @@ log_cert_lifetime(int severity, const X509 *cert, const char *problem) * * Note that a reference is added to cert_out, so it needs to be * freed. id_cert_out doesn't. */ -static void -try_to_extract_certs_from_tls(int severity, tor_tls_t *tls, - X509 **cert_out, X509 **id_cert_out) +MOCK_IMPL(STATIC void, +try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls, + X509 **cert_out, X509 **id_cert_out)) { X509 *cert = NULL, *id_cert = NULL; STACK_OF(X509) *chain = NULL; int num_in_chain, i; *cert_out = *id_cert_out = NULL; - if (!(cert = SSL_get_peer_certificate(tls->ssl))) return; *cert_out = cert; @@ -2489,6 +2151,7 @@ tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity_key) RSA *rsa; int r = -1; + check_no_tls_errors(); *identity_key = NULL; try_to_extract_certs_from_tls(severity, tls, &cert, &id_cert); @@ -2570,12 +2233,12 @@ check_cert_lifetime_internal(int severity, const X509 *cert, now = time(NULL); t = now + future_tolerance; - if (X509_cmp_time(X509_get_notBefore(cert), &t) > 0) { + if (X509_cmp_time(X509_get_notBefore_const(cert), &t) > 0) { log_cert_lifetime(severity, cert, "not yet valid"); return -1; } t = now - past_tolerance; - if (X509_cmp_time(X509_get_notAfter(cert), &t) < 0) { + if (X509_cmp_time(X509_get_notAfter_const(cert), &t) < 0) { log_cert_lifetime(severity, cert, "already expired"); return -1; } @@ -2608,7 +2271,7 @@ tor_tls_get_n_raw_bytes(tor_tls_t *tls, size_t *n_read, size_t *n_written) { BIO *wbio, *tmpbio; unsigned long r, w; - r = BIO_number_read(SSL_get_rbio(tls->ssl)); + r = (unsigned long) BIO_number_read(SSL_get_rbio(tls->ssl)); /* We want the number of bytes actually for real written. Unfortunately, * sometimes OpenSSL replaces the wbio on tls->ssl with a buffering bio, * which makes the answer turn out wrong. Let's cope with that. Note @@ -2617,9 +2280,19 @@ tor_tls_get_n_raw_bytes(tor_tls_t *tls, size_t *n_read, size_t *n_written) * save the original BIO for tls->ssl in the tor_tls_t structure, but * that would be tempting fate. */ wbio = SSL_get_wbio(tls->ssl); +#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) + /* BIO structure is opaque as of OpenSSL 1.1.0-pre5-dev. Again, not + * supposed to use this form of the version macro, but the OpenSSL developers + * introduced major API changes in the pre-release stage. + */ + if (BIO_method_type(wbio) == BIO_TYPE_BUFFER && + (tmpbio = BIO_next(wbio)) != NULL) + wbio = tmpbio; +#else if (wbio->method == BIO_f_buffer() && (tmpbio = BIO_next(wbio)) != NULL) wbio = tmpbio; - w = BIO_number_written(wbio); +#endif + w = (unsigned long) BIO_number_written(wbio); /* We are ok with letting these unsigned ints go "negative" here: * If we wrapped around, this should still give us the right answer, unless @@ -2667,106 +2340,7 @@ check_no_tls_errors_(const char *fname, int line) int tor_tls_used_v1_handshake(tor_tls_t *tls) { - if (tls->isServer) { -#ifdef V2_HANDSHAKE_SERVER - return ! tls->wasV2Handshake; -#endif - } else { -#ifdef V2_HANDSHAKE_CLIENT - return ! tls->wasV2Handshake; -#endif - } - return 1; -} - -/** Return true iff <b>name</b> is a DN of a kind that could only - * occur in a v3-handshake-indicating certificate */ -static int -dn_indicates_v3_cert(X509_NAME *name) -{ -#ifdef DISABLE_V3_LINKPROTO_CLIENTSIDE - (void)name; - return 0; -#else - X509_NAME_ENTRY *entry; - int n_entries; - ASN1_OBJECT *obj; - ASN1_STRING *str; - unsigned char *s; - int len, r; - - n_entries = X509_NAME_entry_count(name); - if (n_entries != 1) - return 1; /* More than one entry in the DN. */ - entry = X509_NAME_get_entry(name, 0); - - obj = X509_NAME_ENTRY_get_object(entry); - if (OBJ_obj2nid(obj) != OBJ_txt2nid("commonName")) - return 1; /* The entry isn't a commonName. */ - - str = X509_NAME_ENTRY_get_data(entry); - len = ASN1_STRING_to_UTF8(&s, str); - if (len < 0) - return 0; - if (len < 4) { - OPENSSL_free(s); - return 1; - } - r = fast_memneq(s + len - 4, ".net", 4); - OPENSSL_free(s); - return r; -#endif -} - -/** Return true iff the peer certificate we're received on <b>tls</b> - * indicates that this connection should use the v3 (in-protocol) - * authentication handshake. - * - * Only the connection initiator should use this, and only once the initial - * handshake is done; the responder detects a v1 handshake by cipher types, - * and a v3/v2 handshake by Versions cell vs renegotiation. - */ -int -tor_tls_received_v3_certificate(tor_tls_t *tls) -{ - X509 *cert = SSL_get_peer_certificate(tls->ssl); - EVP_PKEY *key = NULL; - X509_NAME *issuer_name, *subject_name; - int is_v3 = 0; - - if (!cert) { - log_warn(LD_BUG, "Called on a connection with no peer certificate"); - goto done; - } - - subject_name = X509_get_subject_name(cert); - issuer_name = X509_get_issuer_name(cert); - - if (X509_name_cmp(subject_name, issuer_name) == 0) { - is_v3 = 1; /* purportedly self signed */ - goto done; - } - - if (dn_indicates_v3_cert(subject_name) || - dn_indicates_v3_cert(issuer_name)) { - is_v3 = 1; /* DN is fancy */ - goto done; - } - - key = X509_get_pubkey(cert); - if (EVP_PKEY_bits(key) != 1024 || - EVP_PKEY_type(key->type) != EVP_PKEY_RSA) { - is_v3 = 1; /* Key is fancy */ - goto done; - } - - done: - if (key) - EVP_PKEY_free(key); - if (cert) - X509_free(cert); - - return is_v3; + return ! tls->wasV2Handshake; } /** Return the number of server handshakes that we've noticed doing on @@ -2785,33 +2359,108 @@ tor_tls_server_got_renegotiate(tor_tls_t *tls) return tls->got_renegotiate; } +#ifndef HAVE_SSL_GET_CLIENT_RANDOM +static size_t +SSL_get_client_random(SSL *s, uint8_t *out, size_t len) +{ + if (len == 0) + return SSL3_RANDOM_SIZE; + tor_assert(len == SSL3_RANDOM_SIZE); + tor_assert(s->s3); + memcpy(out, s->s3->client_random, len); + return len; +} +#endif + +#ifndef HAVE_SSL_GET_SERVER_RANDOM +static size_t +SSL_get_server_random(SSL *s, uint8_t *out, size_t len) +{ + if (len == 0) + return SSL3_RANDOM_SIZE; + tor_assert(len == SSL3_RANDOM_SIZE); + tor_assert(s->s3); + memcpy(out, s->s3->server_random, len); + return len; +} +#endif + +#ifndef HAVE_SSL_SESSION_GET_MASTER_KEY +STATIC size_t +SSL_SESSION_get_master_key(SSL_SESSION *s, uint8_t *out, size_t len) +{ + tor_assert(s); + if (len == 0) + return s->master_key_length; + tor_assert(len == (size_t)s->master_key_length); + tor_assert(out); + memcpy(out, s->master_key, len); + return len; +} +#endif + /** Set the DIGEST256_LEN buffer at <b>secrets_out</b> to the value used in * the v3 handshake to prove that the client knows the TLS secrets for the * connection <b>tls</b>. Return 0 on success, -1 on failure. */ -int -tor_tls_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out) +MOCK_IMPL(int, +tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out)) { #define TLSSECRET_MAGIC "Tor V3 handshake TLS cross-certification" - char buf[128]; + uint8_t buf[128]; size_t len; tor_assert(tls); - tor_assert(tls->ssl); - tor_assert(tls->ssl->s3); - tor_assert(tls->ssl->session); + + SSL *const ssl = tls->ssl; + SSL_SESSION *const session = SSL_get_session(ssl); + + tor_assert(ssl); + tor_assert(session); + + const size_t server_random_len = SSL_get_server_random(ssl, NULL, 0); + const size_t client_random_len = SSL_get_client_random(ssl, NULL, 0); + const size_t master_key_len = SSL_SESSION_get_master_key(session, NULL, 0); + + tor_assert(server_random_len); + tor_assert(client_random_len); + tor_assert(master_key_len); + + len = client_random_len + server_random_len + strlen(TLSSECRET_MAGIC) + 1; + tor_assert(len <= sizeof(buf)); + + { + size_t r = SSL_get_client_random(ssl, buf, client_random_len); + tor_assert(r == client_random_len); + } + + { + size_t r = SSL_get_server_random(ssl, + buf+client_random_len, + server_random_len); + tor_assert(r == server_random_len); + } + + uint8_t *master_key = tor_malloc_zero(master_key_len); + { + size_t r = SSL_SESSION_get_master_key(session, master_key, master_key_len); + tor_assert(r == master_key_len); + } + + uint8_t *nextbuf = buf + client_random_len + server_random_len; + memcpy(nextbuf, TLSSECRET_MAGIC, strlen(TLSSECRET_MAGIC) + 1); + /* The value is an HMAC, using the TLS master key as the HMAC key, of client_random | server_random | TLSSECRET_MAGIC */ - memcpy(buf + 0, tls->ssl->s3->client_random, 32); - memcpy(buf + 32, tls->ssl->s3->server_random, 32); - memcpy(buf + 64, TLSSECRET_MAGIC, strlen(TLSSECRET_MAGIC) + 1); - len = 64 + strlen(TLSSECRET_MAGIC) + 1; crypto_hmac_sha256((char*)secrets_out, - (char*)tls->ssl->session->master_key, - tls->ssl->session->master_key_length, - buf, len); + (char*)master_key, + master_key_len, + (char*)buf, len); memwipe(buf, 0, sizeof(buf)); + memwipe(master_key, 0, master_key_len); + tor_free(master_key); + return 0; } @@ -2819,12 +2468,23 @@ tor_tls_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out) * Set *<b>rbuf_capacity</b> to the amount of storage allocated for the read * buffer and *<b>rbuf_bytes</b> to the amount actually used. * Set *<b>wbuf_capacity</b> to the amount of storage allocated for the write - * buffer and *<b>wbuf_bytes</b> to the amount actually used. */ -void + * buffer and *<b>wbuf_bytes</b> to the amount actually used. + * + * Return 0 on success, -1 on failure.*/ +int tor_tls_get_buffer_sizes(tor_tls_t *tls, size_t *rbuf_capacity, size_t *rbuf_bytes, size_t *wbuf_capacity, size_t *wbuf_bytes) { +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) + (void)tls; + (void)rbuf_capacity; + (void)rbuf_bytes; + (void)wbuf_capacity; + (void)wbuf_bytes; + + return -1; +#else if (tls->ssl->s3->rbuf.buf) *rbuf_capacity = tls->ssl->s3->rbuf.len; else @@ -2835,6 +2495,8 @@ tor_tls_get_buffer_sizes(tor_tls_t *tls, *wbuf_capacity = 0; *rbuf_bytes = tls->ssl->s3->rbuf.left; *wbuf_bytes = tls->ssl->s3->wbuf.left; + return 0; +#endif } #ifdef USE_BUFFEREVENTS @@ -2909,3 +2571,29 @@ tor_tls_init_bufferevent(tor_tls_t *tls, struct bufferevent *bufev_in, } #endif +/** Check whether the ECC group requested is supported by the current OpenSSL + * library instance. Return 1 if the group is supported, and 0 if not. + */ +int +evaluate_ecgroup_for_tls(const char *ecgroup) +{ + EC_KEY *ec_key; + int nid; + int ret; + + if (!ecgroup) + nid = NID_tor_default_ecdhe_group; + else if (!strcasecmp(ecgroup, "P256")) + nid = NID_X9_62_prime256v1; + else if (!strcasecmp(ecgroup, "P224")) + nid = NID_secp224r1; + else + return 0; + + ec_key = EC_KEY_new_by_curve_name(nid); + ret = (ec_key != NULL); + EC_KEY_free(ec_key); + + return ret; +} + |