Back to index

tor  0.2.3.19-rc
Classes | Defines | Typedefs | Functions | Variables
tortls.c File Reference

Wrapper functions to present a consistent interface to TLS, SSL, and X.509 functions from OpenSSL. More...

#include "orconfig.h"
#include <assert.h>
#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 "crypto.h"
#include "tortls.h"
#include "util.h"
#include "torlog.h"
#include "container.h"
#include <string.h>
#include "./ciphers.inc"

Go to the source code of this file.

Classes

struct  tor_cert_t
 Structure that we use for a single certificate. More...
struct  tor_tls_context_t
 Holds a SSL_CTX object and related state used to configure TLS connections. More...
struct  tor_tls_t
 Holds a SSL object and its associated data. More...
struct  cipher_info_t
 Holds a cipher that we want to advertise, and its 2-byte ID. More...

Defines

#define CRYPTO_PRIVATE   /* to import prototypes from crypto.h */
#define TORTLS_PRIVATE
#define V2_HANDSHAKE_SERVER
#define V2_HANDSHAKE_CLIENT
#define LEGAL_NICKNAME_CHARACTERS   "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
#define IDENTITY_CERT_LIFETIME   (365*24*60*60)
 How long do identity certificates live? (sec)
#define ADDR(tls)   (((tls) && (tls)->address) ? tls->address : "peer")
#define DISABLE_SSL3_HANDSHAKE
#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION   0x00040000L
#define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION   0x0010
#define TOR_TLS_MAGIC   0x71571571
#define _TOR_TLS_SYSCALL   (_MIN_TOR_TLS_ERROR_VAL - 2)
#define _TOR_TLS_ZERORETURN   (_MIN_TOR_TLS_ERROR_VAL - 1)
#define CASE(st)   case TOR_TLS_ST_##st: tortls_state = " in "#st ; break
#define CATCH_SYSCALL   1
#define CATCH_ZERO   2
#define SERIAL_NUMBER_SIZE   8
#define SERVER_CIPHER_LIST
 List of ciphers that servers should select from.
#define CIPHER(id, name)   name ":"
#define XCIPHER(id, name)
#define CIPHER(id, name)   { id, name },
#define XCIPHER(id, name)   { id, #name },
#define TLSSECRET_MAGIC   "Tor V3 handshake TLS cross-certification"

Typedefs

typedef struct tor_tls_context_t tor_tls_context_t
 Holds a SSL_CTX object and related state used to configure TLS connections.
typedef struct cipher_info_t cipher_info_t
 Holds a cipher that we want to advertise, and its 2-byte ID.

Functions

static STACK_OF (SSL_CIPHER)
 A stack of SSL_CIPHER objects, some real, some fake.
static INLINE tor_tls_ttor_tls_get_by_ssl (const SSL *ssl)
 Helper: given a SSL* pointer, return the tor_tls_t object using that pointer.
static void tor_tls_context_decref (tor_tls_context_t *ctx)
 Remove a reference to ctx, and free it if it has no more references.
static void tor_tls_context_incref (tor_tls_context_t *ctx)
 Increase the reference count of 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)
 Generate and sign an X509 certificate with the public key rsa, signed by the private key rsa_sign.
static int tor_tls_context_init_one (tor_tls_context_t **ppcontext, crypto_pk_t *identity, unsigned int key_lifetime, int is_client)
 Create a new global TLS context.
static tor_tls_context_ttor_tls_context_new (crypto_pk_t *identity, unsigned int key_lifetime, int is_client)
 Create a new TLS context for use with Tor TLS handshakes.
static int check_cert_lifetime_internal (int severity, const X509 *cert, int past_tolerance, int future_tolerance)
 Helper: check whether cert is expired give or take past_tolerance seconds, or not-yet-valid give or take future_tolerance seconds.
void tor_tls_get_state_description (tor_tls_t *tls, char *buf, size_t sz)
 Write a description of the current state of tls into the sz-byte buffer at buf.
void tor_tls_log_one_error (tor_tls_t *tls, unsigned long err, int severity, int domain, const char *doing)
 Log a single error err as returned by ERR_get_error(), which was received while performing an operation doing on tls.
static void tls_log_errors (tor_tls_t *tls, int severity, int domain, const char *doing)
 Log all pending tls errors at level severity in log domain domain.
static int tor_errno_to_tls_error (int e)
 Convert an errno (or a WSAerrno on windows) into a TOR_TLS_* error code.
const char * tor_tls_err_to_string (int err)
 Given a TOR_TLS_* error code, return a string equivalent.
static int tor_tls_get_error (tor_tls_t *tls, int r, int extra, const char *doing, int severity, int domain)
 Given a TLS object and the result of an SSL_* call, use SSL_get_error to determine whether an error has occurred, and if so which one.
static void tor_tls_init (void)
 Initialize OpenSSL, unless it has already been initialized.
void tor_tls_free_all (void)
 Free all global TLS structures.
static int always_accept_verify_cb (int preverify_ok, X509_STORE_CTX *x509_ctx)
 We need to give OpenSSL a callback to verify certificates.
static X509_NAME * tor_x509_name_new (const char *cname)
 Return a newly allocated X509 name with commonName cname.
void tor_cert_free (tor_cert_t *cert)
 Free all storage held in cert
static tor_cert_ttor_cert_new (X509 *x509_cert)
 Allocate a new tor_cert_t to hold the certificate "x509_cert".
tor_cert_ttor_cert_decode (const uint8_t *certificate, size_t certificate_len)
 Read a DER-encoded X509 cert, of length exactly certificate_len, from a certificate.
void tor_cert_get_der (const tor_cert_t *cert, const uint8_t **encoded_out, size_t *size_out)
 Set *encoded_out and *size_out to cert's encoded DER representation and length, respectively.
const digests_ttor_cert_get_id_digests (const tor_cert_t *cert)
 Return a set of digests for the public key in cert, or NULL if this cert's public key is not one we know how to take the digest of.
const digests_ttor_cert_get_cert_digests (const tor_cert_t *cert)
 Return a set of digests for the public key in cert.
int tor_tls_get_my_certs (int server, const tor_cert_t **link_cert_out, const tor_cert_t **id_cert_out)
 Set *link_cert_out and *id_cert_out to the link certificate and ID certificate that we're currently using for our V3 in-protocol handshake's certificate chain.
crypto_pk_ttor_tls_get_my_client_auth_key (void)
 Return the authentication key that we use to authenticate ourselves as a client in the V3 in-protocol handshake.
crypto_pk_ttor_tls_cert_get_key (tor_cert_t *cert)
 Return a newly allocated copy of the public key that a certificate certifies.
static int pkey_eq (EVP_PKEY *a, EVP_PKEY *b)
 Return true iff a and b represent the same public key.
int tor_tls_cert_matches_key (const tor_tls_t *tls, const tor_cert_t *cert)
 Return true iff the other side of tls has authenticated to us, and the key certified in cert is the same as the key they used to do it.
int tor_tls_cert_is_valid (int severity, const tor_cert_t *cert, const tor_cert_t *signing_cert, int check_rsa_1024)
 Check whether cert is well-formed, currently live, and correctly signed by the public key in signing_cert.
int tor_tls_context_init (int is_public_server, crypto_pk_t *client_identity, crypto_pk_t *server_identity, unsigned int key_lifetime)
 Create new global client and server TLS contexts.
static int tor_tls_client_is_using_v2_ciphers (const SSL *ssl, const char *address)
 Return true iff the cipher list suggested by the client for ssl is a list that indicates that the client knows how to do the v2 TLS connection handshake.
static void tor_tls_debug_state_callback (const SSL *ssl, int type, int val)
 Invoked when a TLS state changes: log the change at severity 'debug'.
static void tor_tls_server_info_callback (const SSL *ssl, int type, int val)
 Invoked when we're accepting a connection on ssl, and the connection changes state.
static void log_unsupported_ciphers (smartlist_t *unsupported)
 Explain which ciphers we're missing.
static void rectify_client_ciphers (STACK_OF(SSL_CIPHER)**ciphers)
 Replace *ciphers with a new list of SSL ciphersuites: specifically, a list designed to mimic a common web browser.
tor_tls_ttor_tls_new (int sock, int isServer)
 Create a new TLS object from a file descriptor, and a flag to determine whether it is functioning as a server.
void tor_tls_set_logged_address (tor_tls_t *tls, const char *address)
 Make future log messages about tls display the address address.
void tor_tls_set_renegotiate_callback (tor_tls_t *tls, void(*cb)(tor_tls_t *, void *arg), void *arg)
 Set cb to be called with argument arg whenever tls next gets a client-side renegotiate in the middle of a read.
void tor_tls_unblock_renegotiation (tor_tls_t *tls)
 If this version of openssl requires it, turn on renegotiation on tls.
void tor_tls_block_renegotiation (tor_tls_t *tls)
 If this version of openssl supports it, turn off renegotiation on tls.
void tor_tls_assert_renegotiation_unblocked (tor_tls_t *tls)
 Assert that the flags that allow legacy renegotiation are still set.
int tor_tls_is_server (tor_tls_t *tls)
 Return whether this tls initiated the connect (client) or received it (server).
void tor_tls_free (tor_tls_t *tls)
 Release resources associated with a TLS object.
int tor_tls_read (tor_tls_t *tls, char *cp, size_t len)
 Underlying function for TLS reading.
int tor_tls_write (tor_tls_t *tls, const char *cp, size_t n)
 Underlying function for TLS writing.
int tor_tls_handshake (tor_tls_t *tls)
 Perform initial handshake on tls.
int tor_tls_finish_handshake (tor_tls_t *tls)
 Perform the final part of the intial TLS handshake on tls.
int tor_tls_renegotiate (tor_tls_t *tls)
 Client only: Renegotiate a TLS session.
int tor_tls_shutdown (tor_tls_t *tls)
 Shut down an open tls connection tls.
int tor_tls_peer_has_cert (tor_tls_t *tls)
 Return true iff this TLS connection is authenticated.
tor_cert_ttor_tls_get_peer_cert (tor_tls_t *tls)
 Return the peer certificate, or NULL if there isn't one.
static void log_cert_lifetime (int severity, const X509 *cert, const char *problem)
 Warn that a certificate lifetime extends through a certain range.
static void try_to_extract_certs_from_tls (int severity, tor_tls_t *tls, X509 **cert_out, X509 **id_cert_out)
 Helper function: try to extract a link certificate and an identity certificate from tls, and store them in *cert_out and *id_cert_out respectively.
int tor_tls_verify (int severity, tor_tls_t *tls, crypto_pk_t **identity_key)
 If the provided tls connection is authenticated and has a certificate chain that is currently valid and signed, then set *identity_key to the identity certificate's key and return 0.
int tor_tls_check_lifetime (int severity, tor_tls_t *tls, int past_tolerance, int future_tolerance)
 Check whether the certificate set on the connection tls is expired give or take past_tolerance seconds, or not-yet-valid give or take future_tolerance seconds.
int tor_tls_get_pending_bytes (tor_tls_t *tls)
 Return the number of bytes available for reading from tls.
size_t tor_tls_get_forced_write_size (tor_tls_t *tls)
 If tls requires that the next write be of a particular size, return that size.
void tor_tls_get_n_raw_bytes (tor_tls_t *tls, size_t *n_read, size_t *n_written)
 Sets n_read and n_written to the number of bytes read and written, respectively, on the raw socket used by tls since the last time this function was called on tls.
void _check_no_tls_errors (const char *fname, int line)
 Implement check_no_tls_errors: If there are any pending OpenSSL errors, log an error message.
int tor_tls_used_v1_handshake (tor_tls_t *tls)
 Return true iff the initial TLS connection at tls did not use a v2 TLS handshake.
static int dn_indicates_v3_cert (X509_NAME *name)
 Return true iff name is a DN of a kind that could only occur in a v3-handshake-indicating certificate.
int tor_tls_received_v3_certificate (tor_tls_t *tls)
 Return true iff the peer certificate we're received on tls indicates that this connection should use the v3 (in-protocol) authentication handshake.
int tor_tls_get_num_server_handshakes (tor_tls_t *tls)
 Return the number of server handshakes that we've noticed doing on tls.
int tor_tls_server_got_renegotiate (tor_tls_t *tls)
 Return true iff the server TLS connection tls got the renegotiation request it was waiting for.
int tor_tls_get_tlssecrets (tor_tls_t *tls, uint8_t *secrets_out)
 Set the DIGEST256_LEN buffer at secrets_out to the value used in the v3 handshake to prove that the client knows the TLS secrets for the connection tls.
void 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)
 Examine the amount of memory used and available for buffers in tls.

Variables

static int use_unsafe_renegotiation_op = 0
 Does the run-time openssl version look like we need SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION?
static int use_unsafe_renegotiation_flag = 0
 Does the run-time openssl version look like we need SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION?
static SSL_CIPHER * CLIENT_CIPHER_DUMMIES = NULL
 An array of fake SSL_CIPHER objects that we use in order to trick OpenSSL in client mode into advertising the ciphers we want.
static int tls_library_is_initialized = 0
 True iff tor_tls_init() has been called.
static const char CLIENT_CIPHER_LIST [] = "!SSLv2"
 List of ciphers that clients should advertise, omitting items that our OpenSSL doesn't know about.
static const cipher_info_t CLIENT_CIPHER_INFO_LIST []
 A list of all the ciphers that clients should advertise, including items that OpenSSL might not know about.
static const int N_CLIENT_CIPHERS
 The length of CLIENT_CIPHER_INFO_LIST and CLIENT_CIPHER_DUMMIES.
static tor_tls_context_tserver_tls_context = NULL
 Global TLS contexts.
static tor_tls_context_tclient_tls_context = NULL

Detailed Description

Wrapper functions to present a consistent interface to TLS, SSL, and X.509 functions from OpenSSL.

Definition in file tortls.c.


Class Documentation

struct tor_cert_t

Structure that we use for a single certificate.

Definition at line 108 of file tortls.c.

Collaboration diagram for tor_cert_t:
Class Members
X509 * cert
digests_t cert_digests
uint8_t * encoded
size_t encoded_len
digests_t pkey_digests
unsigned pkey_digests_set: 1
struct tor_tls_context_t

Holds a SSL_CTX object and related state used to configure TLS connections.

Definition at line 120 of file tortls.c.

Collaboration diagram for tor_tls_context_t:
Class Members
crypto_pk_t * auth_key
SSL_CTX * ctx
crypto_pk_t * link_key
tor_cert_t * my_auth_cert
tor_cert_t * my_id_cert
tor_cert_t * my_link_cert
int refcnt
struct cipher_info_t

Holds a cipher that we want to advertise, and its 2-byte ID.

Definition at line 685 of file tortls.c.

Class Members
unsigned id
const char * name

Define Documentation

Definition at line 237 of file tortls.c.

Definition at line 238 of file tortls.c.

#define ADDR (   tls)    (((tls) && (tls)->address) ? tls->address : "peer")

Definition at line 77 of file tortls.c.

#define CASE (   st)    case TOR_TLS_ST_##st: tortls_state = " in "#st ; break
#define CATCH_SYSCALL   1

Definition at line 390 of file tortls.c.

#define CATCH_ZERO   2

Definition at line 391 of file tortls.c.

#define CIPHER (   id,
  name 
)    name ":"

Definition at line 671 of file tortls.c.

#define CIPHER (   id,
  name 
)    { id, name },

Definition at line 671 of file tortls.c.

#define CRYPTO_PRIVATE   /* to import prototypes from crypto.h */

Definition at line 51 of file tortls.c.

Definition at line 86 of file tortls.c.

#define IDENTITY_CERT_LIFETIME   (365*24*60*60)

How long do identity certificates live? (sec)

Definition at line 75 of file tortls.c.

#define LEGAL_NICKNAME_CHARACTERS   "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

Definition at line 71 of file tortls.c.

#define SERIAL_NUMBER_SIZE   8
Value:
(TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":"           \
   TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":"           \
   SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)

List of ciphers that servers should select from.

Definition at line 661 of file tortls.c.

Definition at line 97 of file tortls.c.

#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION   0x00040000L

Definition at line 94 of file tortls.c.

#define TLSSECRET_MAGIC   "Tor V3 handshake TLS cross-certification"
#define TOR_TLS_MAGIC   0x71571571

Definition at line 130 of file tortls.c.

#define TORTLS_PRIVATE

Definition at line 52 of file tortls.c.

Definition at line 68 of file tortls.c.

Definition at line 67 of file tortls.c.

#define XCIPHER (   id,
  name 
)

Definition at line 672 of file tortls.c.

#define XCIPHER (   id,
  name 
)    { id, #name },

Definition at line 672 of file tortls.c.


Typedef Documentation

typedef struct cipher_info_t cipher_info_t

Holds a cipher that we want to advertise, and its 2-byte ID.

Holds a SSL_CTX object and related state used to configure TLS connections.


Function Documentation

void _check_no_tls_errors ( const char *  fname,
int  line 
)

Implement check_no_tls_errors: If there are any pending OpenSSL errors, log an error message.

Definition at line 2289 of file tortls.c.

{
  if (ERR_peek_error() == 0)
    return;
  log(LOG_WARN, LD_CRYPTO, "Unhandled OpenSSL errors found at %s:%d: ",
      tor_fix_source_file(fname), line);
  tls_log_errors(NULL, LOG_WARN, LD_NET, NULL);
}

Here is the call graph for this function:

static int always_accept_verify_cb ( int  preverify_ok,
X509_STORE_CTX *  x509_ctx 
) [static]

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.

Definition at line 541 of file tortls.c.

{
  (void) preverify_ok;
  (void) x509_ctx;
  return 1;
}

Here is the caller graph for this function:

static int check_cert_lifetime_internal ( int  severity,
const X509 *  cert,
int  past_tolerance,
int  future_tolerance 
) [static]

Helper: check whether cert is expired give or take past_tolerance seconds, or not-yet-valid give or take future_tolerance seconds.

If it is live, return 0. If it is not live, log a message and return -1.

Definition at line 2211 of file tortls.c.

{
  time_t now, t;

  now = time(NULL);

  t = now + future_tolerance;
  if (X509_cmp_time(X509_get_notBefore(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) {
    log_cert_lifetime(severity, cert, "already expired");
    return -1;
  }

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dn_indicates_v3_cert ( X509_NAME *  name) [static]

Return true iff name is a DN of a kind that could only occur in a v3-handshake-indicating certificate.

Definition at line 2318 of file tortls.c.

{
#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;
  r = fast_memneq(s + len - 4, ".net", 4);
  OPENSSL_free(s);
  return r;
#endif
}

Here is the caller graph for this function:

static void log_cert_lifetime ( int  severity,
const X509 *  cert,
const char *  problem 
) [static]

Warn that a certificate lifetime extends through a certain range.

Definition at line 2037 of file tortls.c.

{
  BIO *bio = NULL;
  BUF_MEM *buf;
  char *s1=NULL, *s2=NULL;
  char mytime[33];
  time_t now = time(NULL);
  struct tm tm;

  if (problem)
    log(severity, LD_GENERAL,
        "Certificate %s. Either their clock is set wrong, or your clock "
        "is wrong.",
           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)))) {
    tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime");
    goto end;
  }
  BIO_get_mem_ptr(bio, &buf);
  s1 = tor_strndup(buf->data, buf->length);

  (void)BIO_reset(bio);
  if (!(ASN1_TIME_print(bio, X509_get_notAfter(cert)))) {
    tls_log_errors(NULL, LOG_WARN, LD_NET, "printing certificate lifetime");
    goto end;
  }
  BIO_get_mem_ptr(bio, &buf);
  s2 = tor_strndup(buf->data, buf->length);

  strftime(mytime, 32, "%b %d %H:%M:%S %Y GMT", tor_gmtime_r(&now, &tm));

  log(severity, LD_GENERAL,
      "(certificate lifetime runs from %s through %s. Your time is %s.)",
      s1,s2,mytime);

 end:
  /* Not expected to get invoked */
  tls_log_errors(NULL, LOG_WARN, LD_NET, "getting certificate lifetime");
  if (bio)
    BIO_free(bio);
  tor_free(s1);
  tor_free(s2);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void log_unsupported_ciphers ( smartlist_t unsupported) [static]

Explain which ciphers we're missing.

Definition at line 1423 of file tortls.c.

{
  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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int pkey_eq ( EVP_PKEY *  a,
EVP_PKEY *  b 
) [static]

Return true iff a and b represent the same public key.

Definition at line 911 of file tortls.c.

{
  /* We'd like to do this, but openssl 0.9.7 doesn't have it:
     return EVP_PKEY_cmp(a,b) == 1;
  */
  unsigned char *a_enc=NULL, *b_enc=NULL, *a_ptr, *b_ptr;
  int a_len1, b_len1, a_len2, b_len2, result;
  a_len1 = i2d_PublicKey(a, NULL);
  b_len1 = i2d_PublicKey(b, NULL);
  if (a_len1 != b_len1)
    return 0;
  a_ptr = a_enc = tor_malloc(a_len1);
  b_ptr = b_enc = tor_malloc(b_len1);
  a_len2 = i2d_PublicKey(a, &a_ptr);
  b_len2 = i2d_PublicKey(b, &b_ptr);
  tor_assert(a_len2 == a_len1);
  tor_assert(b_len2 == b_len1);
  result = tor_memeq(a_enc, b_enc, a_len1);
  tor_free(a_enc);
  tor_free(b_enc);
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void rectify_client_ciphers ( STACK_OF(SSL_CIPHER)**  ciphers) [static]

Replace *ciphers 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 does 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.]

Definition at line 1456 of file tortls.c.

{
#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
}

Here is the call graph for this function:

Here is the caller graph for this function:

static STACK_OF ( SSL_CIPHER  ) [static]

A stack of SSL_CIPHER objects, some real, some fake.

See rectify_client_ciphers() for details. Helper: Allocate tor_tls_object_ex_data_index.

Definition at line 178 of file tortls.c.

{
  if (tor_tls_object_ex_data_index == -1) {
    tor_tls_object_ex_data_index =
      SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
    tor_assert(tor_tls_object_ex_data_index != -1);
  }
}

Here is the caller graph for this function:

static void tls_log_errors ( tor_tls_t tls,
int  severity,
int  domain,
const char *  doing 
) [static]

Log all pending tls errors at level severity in log domain domain.

Use doing to describe our current activities.

Definition at line 325 of file tortls.c.

{
  unsigned long err;

  while ((err = ERR_get_error()) != 0) {
    tor_tls_log_one_error(tls, err, severity, domain, doing);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

tor_cert_t* tor_cert_decode ( const uint8_t *  certificate,
size_t  certificate_len 
)

Read a DER-encoded X509 cert, of length exactly certificate_len, from a certificate.

Return a newly allocated tor_cert_t on success and NULL on failure.

Definition at line 771 of file tortls.c.

{
  X509 *x509;
  const unsigned char *cp = (const unsigned char *)certificate;
  tor_cert_t *newcert;
  tor_assert(certificate);

  if (certificate_len > INT_MAX)
    return NULL;

#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(0,9,8)
  /* This ifdef suppresses a type warning.  Take out this case once everybody
   * is using OpenSSL 0.9.8 or later. */
  x509 = d2i_X509(NULL, (unsigned char**)&cp, (int)certificate_len);
#else
  x509 = d2i_X509(NULL, &cp, (int)certificate_len);
#endif
  if (!x509)
    return NULL; /* Couldn't decode */
  if (cp - certificate != (int)certificate_len) {
    X509_free(x509);
    return NULL; /* Didn't use all the bytes */
  }
  newcert = tor_cert_new(x509);
  if (!newcert) {
    return NULL;
  }
  if (newcert->encoded_len != certificate_len ||
      fast_memneq(newcert->encoded, certificate, certificate_len)) {
    /* Cert wasn't in DER */
    tor_cert_free(newcert);
    return NULL;
  }
  return newcert;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void tor_cert_free ( tor_cert_t cert)

Free all storage held in cert

Definition at line 709 of file tortls.c.

{
  if (! cert)
    return;
  if (cert->cert)
    X509_free(cert->cert);
  tor_free(cert->encoded);
  memset(cert, 0x03, sizeof(*cert));
  tor_free(cert);
}

Here is the caller graph for this function:

Return a set of digests for the public key in cert.

Definition at line 833 of file tortls.c.

{
  return &cert->cert_digests;
}

Here is the caller graph for this function:

void tor_cert_get_der ( const tor_cert_t cert,
const uint8_t **  encoded_out,
size_t *  size_out 
)

Set *encoded_out and *size_out to cert's encoded DER representation and length, respectively.

Definition at line 810 of file tortls.c.

{
  tor_assert(cert);
  tor_assert(encoded_out);
  tor_assert(size_out);
  *encoded_out = cert->encoded;
  *size_out = cert->encoded_len;
}

Here is the caller graph for this function:

const digests_t* tor_cert_get_id_digests ( const tor_cert_t cert)

Return a set of digests for the public key in cert, or NULL if this cert's public key is not one we know how to take the digest of.

Definition at line 823 of file tortls.c.

{
  if (cert->pkey_digests_set)
    return &cert->pkey_digests;
  else
    return NULL;
}

Here is the caller graph for this function:

static tor_cert_t* tor_cert_new ( X509 *  x509_cert) [static]

Allocate a new tor_cert_t to hold the certificate "x509_cert".

Steals a reference to x509_cert.

Definition at line 726 of file tortls.c.

{
  tor_cert_t *cert;
  EVP_PKEY *pkey;
  RSA *rsa;
  int length, length2;
  unsigned char *cp;

  if (!x509_cert)
    return NULL;

  length = i2d_X509(x509_cert, NULL);
  cert = tor_malloc_zero(sizeof(tor_cert_t));
  if (length <= 0) {
    tor_free(cert);
    log_err(LD_CRYPTO, "Couldn't get length of encoded x509 certificate");
    X509_free(x509_cert);
    return NULL;
  }
  cert->encoded_len = (size_t) length;
  cp = cert->encoded = tor_malloc(length);
  length2 = i2d_X509(x509_cert, &cp);
  tor_assert(length2 == length);

  cert->cert = x509_cert;

  crypto_digest_all(&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);
    cert->pkey_digests_set = 1;
    crypto_pk_free(pk);
    EVP_PKEY_free(pkey);
  }

  return cert;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int tor_errno_to_tls_error ( int  e) [static]

Convert an errno (or a WSAerrno on windows) into a TOR_TLS_* error code.

Definition at line 337 of file tortls.c.

{
#if defined(_WIN32)
  switch (e) {
    case WSAECONNRESET: // most common
      return TOR_TLS_ERROR_CONNRESET;
    case WSAETIMEDOUT:
      return TOR_TLS_ERROR_TIMEOUT;
    case WSAENETUNREACH:
    case WSAEHOSTUNREACH:
      return TOR_TLS_ERROR_NO_ROUTE;
    case WSAECONNREFUSED:
      return TOR_TLS_ERROR_CONNREFUSED; // least common
    default:
      return TOR_TLS_ERROR_MISC;
  }
#else
  switch (e) {
    case ECONNRESET: // most common
      return TOR_TLS_ERROR_CONNRESET;
    case ETIMEDOUT:
      return TOR_TLS_ERROR_TIMEOUT;
    case EHOSTUNREACH:
    case ENETUNREACH:
      return TOR_TLS_ERROR_NO_ROUTE;
    case ECONNREFUSED:
      return TOR_TLS_ERROR_CONNREFUSED; // least common
    default:
      return TOR_TLS_ERROR_MISC;
  }
#endif
}

Here is the caller graph for this function:

Assert that the flags that allow legacy renegotiation are still set.

Definition at line 1686 of file tortls.c.

{
  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 this version of openssl supports it, turn off renegotiation on tls.

(Our protocol never requires this for security, but it's nice to use belt-and-suspenders here.)

Definition at line 1679 of file tortls.c.

Here is the caller graph for this function:

Return a newly allocated copy of the public key that a certificate certifies.

Return NULL if the cert's key is not RSA.

Definition at line 892 of file tortls.c.

{
  crypto_pk_t *result = NULL;
  EVP_PKEY *pkey = X509_get_pubkey(cert->cert);
  RSA *rsa;
  if (!pkey)
    return NULL;
  rsa = EVP_PKEY_get1_RSA(pkey);
  if (!rsa) {
    EVP_PKEY_free(pkey);
    return NULL;
  }
  result = _crypto_new_pk_from_rsa(rsa);
  EVP_PKEY_free(pkey);
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int tor_tls_cert_is_valid ( int  severity,
const tor_cert_t cert,
const tor_cert_t signing_cert,
int  check_rsa_1024 
)

Check whether cert is well-formed, currently live, and correctly signed by the public key in signing_cert.

If check_rsa_1024, make sure that it has an RSA key with 1024 bits; otherwise, just check that the key is long enough. Return 1 if the cert is good, and 0 if it's bad or we couldn't check it.

Definition at line 966 of file tortls.c.

{
  EVP_PKEY *cert_key;
  EVP_PKEY *signing_key = X509_get_pubkey(signing_cert->cert);
  int r, key_ok = 0;
  if (!signing_key)
    return 0;
  r = X509_verify(cert->cert, signing_key);
  EVP_PKEY_free(signing_key);
  if (r <= 0)
    return 0;

  /* 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;

  cert_key = X509_get_pubkey(cert->cert);
  if (check_rsa_1024 && cert_key) {
    RSA *rsa = EVP_PKEY_get1_RSA(cert_key);
    if (rsa && BN_num_bits(rsa->n) == 1024)
      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)
      min_bits = 128;
#endif
    if (EVP_PKEY_bits(cert_key) >= min_bits)
      key_ok = 1;
  }
  EVP_PKEY_free(cert_key);
  if (!key_ok)
    return 0;

  /* XXXX compare DNs or anything? */

  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int tor_tls_cert_matches_key ( const tor_tls_t tls,
const tor_cert_t cert 
)

Return true iff the other side of tls has authenticated to us, and the key certified in cert is the same as the key they used to do it.

Definition at line 938 of file tortls.c.

{
  X509 *peercert = SSL_get_peer_certificate(tls->ssl);
  EVP_PKEY *link_key = NULL, *cert_key = NULL;
  int result;

  if (!peercert)
    return 0;
  link_key = X509_get_pubkey(peercert);
  cert_key = X509_get_pubkey(cert->cert);

  result = link_key && cert_key && pkey_eq(cert_key, link_key);

  X509_free(peercert);
  if (link_key)
    EVP_PKEY_free(link_key);
  if (cert_key)
    EVP_PKEY_free(cert_key);

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int tor_tls_check_lifetime ( int  severity,
tor_tls_t tls,
int  past_tolerance,
int  future_tolerance 
)

Check whether the certificate set on the connection tls is expired give or take past_tolerance seconds, or not-yet-valid give or take future_tolerance seconds.

Return 0 for valid, -1 for failure.

NOTE: you should call tor_tls_verify before tor_tls_check_lifetime.

Definition at line 2183 of file tortls.c.

{
  X509 *cert;
  int r = -1;

  if (!(cert = SSL_get_peer_certificate(tls->ssl)))
    goto done;

  if (check_cert_lifetime_internal(severity, cert,
                                   past_tolerance, future_tolerance) < 0)
    goto done;

  r = 0;
 done:
  if (cert)
    X509_free(cert);
  /* Not expected to get invoked */
  tls_log_errors(tls, LOG_WARN, LD_NET, "checking certificate lifetime");

  return r;
}

Here is the call graph for this function:

static int tor_tls_client_is_using_v2_ciphers ( const SSL *  ssl,
const char *  address 
) [static]

Return true iff the cipher list suggested by the client for ssl is a list that indicates that the client knows how to do the v2 TLS connection handshake.

Definition at line 1307 of file tortls.c.

{
  int i;
  SSL_SESSION *session;
  /* If we reached this point, we just got a client hello.  See if there is
   * a cipher list. */
  if (!(session = SSL_get_session((SSL *)ssl))) {
    log_info(LD_NET, "No session on TLS?");
    return 0;
  }
  if (!session->ciphers) {
    log_info(LD_NET, "No ciphers on session");
    return 0;
  }
  /* 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(session->ciphers); ++i) {
    SSL_CIPHER *cipher = sk_SSL_CIPHER_value(session->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) &&
        strcmp(ciphername, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) &&
        strcmp(ciphername, "(NONE)")) {
      log_debug(LD_NET, "Got a non-version-1 cipher called '%s'", ciphername);
      // return 1;
      goto dump_list;
    }
  }
  return 0;
 dump_list:
  {
    smartlist_t *elts = smartlist_new();
    char *s;
    for (i = 0; i < sk_SSL_CIPHER_num(session->ciphers); ++i) {
      SSL_CIPHER *cipher = sk_SSL_CIPHER_value(session->ciphers, i);
      const char *ciphername = SSL_CIPHER_get_name(cipher);
      smartlist_add(elts, (char*)ciphername);
    }
    s = smartlist_join_strings(elts, ":", 0, NULL);
    log_debug(LD_NET, "Got a non-version-1 cipher list from %s.  It is: '%s'",
              address, s);
    tor_free(s);
    smartlist_free(elts);
  }
  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void tor_tls_context_decref ( tor_tls_context_t ctx) [static]

Remove a reference to ctx, and free it if it has no more references.

Definition at line 841 of file tortls.c.

{
  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);
    crypto_pk_free(ctx->link_key);
    crypto_pk_free(ctx->auth_key);
    tor_free(ctx);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void tor_tls_context_incref ( tor_tls_context_t ctx) [static]

Increase the reference count of ctx.

Definition at line 1014 of file tortls.c.

{
  ++ctx->refcnt;
}

Here is the caller graph for this function:

int tor_tls_context_init ( int  is_public_server,
crypto_pk_t client_identity,
crypto_pk_t server_identity,
unsigned int  key_lifetime 
)

Create new global client and server TLS contexts.

If server_identity is NULL, this will not generate a server TLS context. If is_public_server is non-zero, this will use the same TLS context for incoming and outgoing connections, and ignore client_identity.

Definition at line 1026 of file tortls.c.

{
  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, 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,
                                     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,
                                   1);
  }

  return MIN(rv1, rv2);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int tor_tls_context_init_one ( tor_tls_context_t **  ppcontext,
crypto_pk_t identity,
unsigned int  key_lifetime,
int  is_client 
) [static]

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.

Definition at line 1085 of file tortls.c.

{
  tor_tls_context_t *new_ctx = tor_tls_context_new(identity,
                                                   key_lifetime,
                                                   is_client);
  tor_tls_context_t *old_ctx = *ppcontext;

  if (new_ctx != NULL) {
    *ppcontext = new_ctx;

    /* Free the old context if one existed. */
    if (old_ctx != NULL) {
      /* This is safe even if there are open connections: we reference-
       * count tor_tls_context_t objects. */
      tor_tls_context_decref(old_ctx);
    }
  }

  return ((new_ctx != NULL) ? 0 : -1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static tor_tls_context_t * tor_tls_context_new ( crypto_pk_t identity,
unsigned int  key_lifetime,
int  is_client 
) [static]

Create a new TLS context for use with Tor TLS handshakes.

identity should be set to the identity key used to sign the certificate.

Definition at line 1114 of file tortls.c.

{
  crypto_pk_t *rsa = NULL, *rsa_auth = NULL;
  EVP_PKEY *pkey = NULL;
  tor_tls_context_t *result = NULL;
  X509 *cert = NULL, *idcert = NULL, *authcert = NULL;
  char *nickname = NULL, *nn2 = NULL;

  tor_tls_init();
  nickname = crypto_random_hostname(8, 20, "www.", ".net");
#ifdef DISABLE_V3_LINKPROTO_SERVERSIDE
  nn2 = crypto_random_hostname(8, 20, "www.", ".net");
#else
  nn2 = crypto_random_hostname(8, 20, "www.", ".com");
#endif

  /* Generate short-term RSA key for use with TLS. */
  if (!(rsa = crypto_pk_new()))
    goto error;
  if (crypto_pk_generate_key(rsa)<0)
    goto error;
  if (!is_client) {
    /* Generate short-term RSA key for use in the in-protocol ("v3")
     * authentication handshake. */
    if (!(rsa_auth = crypto_pk_new()))
      goto error;
    if (crypto_pk_generate_key(rsa_auth)<0)
      goto error;
    /* Create a link 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);
    /* Create an authentication certificate signed by identity key. */
    authcert = tor_tls_create_certificate(rsa_auth, identity, nickname, nn2,
                                          key_lifetime);
    if (!cert || !idcert || !authcert) {
      log(LOG_WARN, LD_CRYPTO, "Error creating certificate");
      goto error;
    }
  }

  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));
    if (!result->my_link_cert || !result->my_id_cert || !result->my_auth_cert)
      goto error;
    result->link_key = crypto_pk_dup_key(rsa);
    result->auth_key = crypto_pk_dup_key(rsa_auth);
  }

#if 0
  /* Tell OpenSSL to only use TLS1.  This may have subtly different results
   * from SSLv23_method() with SSLv2 and SSLv3 disabled, so we need to do some
   * investigation before we consider adjusting it. It should be compatible
   * with existing Tors. */
  if (!(result->ctx = SSL_CTX_new(TLSv1_method())))
    goto error;
#endif

  /* 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);

  /* 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. */
#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

  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);

#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
  SSL_CTX_set_options(result->ctx,
                      SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
#endif
  /* 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);
  }
  /* 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;
#ifdef SSL_MODE_RELEASE_BUFFERS
  SSL_CTX_set_mode(result->ctx, SSL_MODE_RELEASE_BUFFERS);
#endif
  if (! is_client) {
    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) {
      X509_STORE *s = SSL_CTX_get_cert_store(result->ctx);
      tor_assert(s);
      X509_STORE_add_cert(s, idcert);
      X509_free(idcert); /* The context now owns the reference to idcert */
      idcert = NULL;
    }
  }
  SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF);
  if (!is_client) {
    tor_assert(rsa);
    if (!(pkey = _crypto_pk_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;
  }
  {
    crypto_dh_t *dh = crypto_dh_new(DH_TYPE_TLS);
    tor_assert(dh);
    SSL_CTX_set_tmp_dh(result->ctx, _crypto_dh_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);

  if (rsa)
    crypto_pk_free(rsa);
  if (rsa_auth)
    crypto_pk_free(rsa_auth);
  X509_free(authcert);
  tor_free(nickname);
  tor_free(nn2);
  return result;

 error:
  tls_log_errors(NULL, LOG_WARN, LD_NET, "creating TLS context");
  tor_free(nickname);
  tor_free(nn2);
  if (pkey)
    EVP_PKEY_free(pkey);
  if (rsa)
    crypto_pk_free(rsa);
  if (rsa_auth)
    crypto_pk_free(rsa_auth);
  if (result)
    tor_tls_context_decref(result);
  if (cert)
    X509_free(cert);
  if (idcert)
    X509_free(idcert);
  if (authcert)
    X509_free(authcert);
  return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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]

Generate and sign an X509 certificate with the public key rsa, signed by the private key rsa_sign.

The commonName of the certificate will be cname; the commonName of the issuer will be cname_sign. The cert will be valid for cert_lifetime seconds starting from now. Return a certificate on success, NULL on failure.

Definition at line 575 of file tortls.c.

{
  /* OpenSSL generates self-signed certificates with random 64-bit serial
   * numbers, so let's do that too. */
#define SERIAL_NUMBER_SIZE 8

  time_t start_time, end_time;
  BIGNUM *serial_number = NULL;
  unsigned char serial_tmp[SERIAL_NUMBER_SIZE];
  EVP_PKEY *sign_pkey = NULL, *pkey=NULL;
  X509 *x509 = NULL;
  X509_NAME *name = NULL, *name_issuer=NULL;

  tor_tls_init();

  start_time = time(NULL);

  tor_assert(rsa);
  tor_assert(cname);
  tor_assert(rsa_sign);
  tor_assert(cname_sign);
  if (!(sign_pkey = _crypto_pk_get_evp_pkey(rsa_sign,1)))
    goto error;
  if (!(pkey = _crypto_pk_get_evp_pkey(rsa,0)))
    goto error;
  if (!(x509 = X509_new()))
    goto error;
  if (!(X509_set_version(x509, 2)))
    goto error;

  { /* our serial number is 8 random bytes. */
    if (crypto_rand((char *)serial_tmp, sizeof(serial_tmp)) < 0)
      goto error;
    if (!(serial_number = BN_bin2bn(serial_tmp, sizeof(serial_tmp), NULL)))
      goto error;
    if (!(BN_to_ASN1_INTEGER(serial_number, X509_get_serialNumber(x509))))
      goto error;
  }

  if (!(name = tor_x509_name_new(cname)))
    goto error;
  if (!(X509_set_subject_name(x509, name)))
    goto error;
  if (!(name_issuer = tor_x509_name_new(cname_sign)))
    goto error;
  if (!(X509_set_issuer_name(x509, name_issuer)))
    goto error;

  if (!X509_time_adj(X509_get_notBefore(x509),0,&start_time))
    goto error;
  end_time = start_time + cert_lifetime;
  if (!X509_time_adj(X509_get_notAfter(x509),0,&end_time))
    goto error;
  if (!X509_set_pubkey(x509, pkey))
    goto error;
  if (!X509_sign(x509, sign_pkey, EVP_sha1()))
    goto error;

  goto done;
 error:
  if (x509) {
    X509_free(x509);
    x509 = NULL;
  }
 done:
  tls_log_errors(NULL, LOG_WARN, LD_NET, "generating certificate");
  if (sign_pkey)
    EVP_PKEY_free(sign_pkey);
  if (pkey)
    EVP_PKEY_free(pkey);
  if (serial_number)
    BN_free(serial_number);
  if (name)
    X509_NAME_free(name);
  if (name_issuer)
    X509_NAME_free(name_issuer);
  return x509;

#undef SERIAL_NUMBER_SIZE
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void tor_tls_debug_state_callback ( const SSL *  ssl,
int  type,
int  val 
) [static]

Invoked when a TLS state changes: log the change at severity 'debug'.

Definition at line 1356 of file tortls.c.

{
  log_debug(LD_HANDSHAKE, "SSL %p is now in state %s [type=%d,val=%d].",
            ssl, SSL_state_string_long(ssl), type, val);
}

Here is the caller graph for this function:

const char* tor_tls_err_to_string ( int  err)

Given a TOR_TLS_* error code, return a string equivalent.

Definition at line 372 of file tortls.c.

{
  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)";
  }
}

Here is the caller graph for this function:

Perform the final part of the intial TLS handshake on tls.

This should be called for the first handshake only: it determines whether the v1 or the v2 handshake was used, and adjusts things for the renegotiation handshake as appropriate.

tor_tls_handshake() calls this on its own; you only need to call this if bufferevent is doing the handshake for you.

Definition at line 1852 of file tortls.c.

{
  int r = TOR_TLS_DONE;
  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
    if (tor_tls_client_is_using_v2_ciphers(tls->ssl, ADDR(tls))) {
      /* 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
       * was buggy.  Fixing that. */
      if (!tls->wasV2Handshake) {
        log_warn(LD_BUG, "For some reason, wasV2Handshake didn't"
                 " get set. Fixing that.");
      }
      tls->wasV2Handshake = 1;
      log_debug(LD_HANDSHAKE, "Completed V2 TLS handshake with client; waiting"
                " for renegotiation.");
    } 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
    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;
    }
  }
  return r;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void tor_tls_free ( tor_tls_t tls)

Release resources associated with a TLS object.

Does not close the underlying file descriptor.

Definition at line 1711 of file tortls.c.

{
  if (!tls)
    return;
  tor_assert(tls->ssl);
#ifdef SSL_set_tlsext_host_name
  SSL_set_tlsext_host_name(tls->ssl, NULL);
#endif
  SSL_free(tls->ssl);
  tls->ssl = NULL;
  tls->negotiated_callback = NULL;
  if (tls->context)
    tor_tls_context_decref(tls->context);
  tor_free(tls->address);
  tls->magic = 0x99999999;
  tor_free(tls);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void tor_tls_free_all ( void  )

Free all global TLS structures.

Definition at line 516 of file tortls.c.

{
  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);
  }
#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
}

Here is the call graph for this function:

Here is the caller graph for this function:

void 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 
)

Examine the amount of memory used and available for buffers in tls.

Set *rbuf_capacity to the amount of storage allocated for the read buffer and *rbuf_bytes to the amount actually used. Set *wbuf_capacity to the amount of storage allocated for the write buffer and *wbuf_bytes to the amount actually used.

Definition at line 2453 of file tortls.c.

{
  if (tls->ssl->s3->rbuf.buf)
    *rbuf_capacity = tls->ssl->s3->rbuf.len;
  else
    *rbuf_capacity = 0;
  if (tls->ssl->s3->wbuf.buf)
    *wbuf_capacity = tls->ssl->s3->wbuf.len;
  else
    *wbuf_capacity = 0;
  *rbuf_bytes = tls->ssl->s3->rbuf.left;
  *wbuf_bytes = tls->ssl->s3->wbuf.left;
}

Here is the caller graph for this function:

static INLINE tor_tls_t* tor_tls_get_by_ssl ( const SSL *  ssl) [static]

Helper: given a SSL* pointer, return the tor_tls_t object using that pointer.

Definition at line 199 of file tortls.c.

{
  tor_tls_t *result = SSL_get_ex_data(ssl, tor_tls_object_ex_data_index);
  if (result)
    tor_assert(result->magic == TOR_TLS_MAGIC);
  return result;
}

Here is the caller graph for this function:

static int tor_tls_get_error ( tor_tls_t tls,
int  r,
int  extra,
const char *  doing,
int  severity,
int  domain 
) [static]

Given a TLS object and the result of an SSL_* call, use SSL_get_error to determine whether an error has occurred, and if so which one.

Return one of TOR_TLS_{DONE|WANTREAD|WANTWRITE|ERROR}. If extra&CATCH_SYSCALL is true, return _TOR_TLS_SYSCALL instead of reporting syscall errors. If extra&CATCH_ZERO is true, return _TOR_TLS_ZERORETURN instead of reporting zero-return errors.

If an error has occurred, log it at level severity and describe the current action as doing.

Definition at line 404 of file tortls.c.

{
  int err = SSL_get_error(tls->ssl, r);
  int tor_error = TOR_TLS_ERROR_MISC;
  switch (err) {
    case SSL_ERROR_NONE:
      return TOR_TLS_DONE;
    case SSL_ERROR_WANT_READ:
      return TOR_TLS_WANTREAD;
    case SSL_ERROR_WANT_WRITE:
      return TOR_TLS_WANTWRITE;
    case SSL_ERROR_SYSCALL:
      if (extra&CATCH_SYSCALL)
        return _TOR_TLS_SYSCALL;
      if (r == 0) {
        log(severity, LD_NET, "TLS error: unexpected close while %s (%s)",
            doing, SSL_state_string_long(tls->ssl));
        tor_error = TOR_TLS_ERROR_IO;
      } else {
        int e = tor_socket_errno(tls->socket);
        log(severity, LD_NET,
            "TLS error: <syscall error while %s> (errno=%d: %s; state=%s)",
            doing, e, tor_socket_strerror(e),
            SSL_state_string_long(tls->ssl));
        tor_error = tor_errno_to_tls_error(e);
      }
      tls_log_errors(tls, severity, domain, doing);
      return tor_error;
    case SSL_ERROR_ZERO_RETURN:
      if (extra&CATCH_ZERO)
        return _TOR_TLS_ZERORETURN;
      log(severity, LD_NET, "TLS connection closed while %s in state %s",
          doing, SSL_state_string_long(tls->ssl));
      tls_log_errors(tls, severity, domain, doing);
      return TOR_TLS_CLOSE;
    default:
      tls_log_errors(tls, severity, domain, doing);
      return TOR_TLS_ERROR_MISC;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

If tls requires that the next write be of a particular size, return that size.

Otherwise, return 0.

Definition at line 2244 of file tortls.c.

{
  return tls->wantwrite_n;
}

Here is the caller graph for this function:

int tor_tls_get_my_certs ( int  server,
const tor_cert_t **  link_cert_out,
const tor_cert_t **  id_cert_out 
)

Set *link_cert_out and *id_cert_out to the link certificate and ID certificate that we're currently using for our V3 in-protocol handshake's certificate chain.

If server is true, provide the certs that we use in server mode; otherwise, provide the certs that we use in client mode.

Definition at line 861 of file tortls.c.

{
  tor_tls_context_t *ctx = server ? server_tls_context : client_tls_context;
  if (! ctx)
    return -1;
  if (link_cert_out)
    *link_cert_out = server ? ctx->my_link_cert : ctx->my_auth_cert;
  if (id_cert_out)
    *id_cert_out = ctx->my_id_cert;
  return 0;
}

Here is the caller graph for this function:

Return the authentication key that we use to authenticate ourselves as a client in the V3 in-protocol handshake.

Definition at line 880 of file tortls.c.

{
  if (! client_tls_context)
    return NULL;
  return client_tls_context->auth_key;
}

Here is the caller graph for this function:

void tor_tls_get_n_raw_bytes ( tor_tls_t tls,
size_t *  n_read,
size_t *  n_written 
)

Sets n_read and n_written to the number of bytes read and written, respectively, on the raw socket used by tls since the last time this function was called on tls.

Definition at line 2253 of file tortls.c.

{
  BIO *wbio, *tmpbio;
  unsigned long r, w;
  r = 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
   * that this approach will fail if we ever replace tls->ssl's BIOs with
   * buffering bios for reasons of our own.  As an alternative, we could
   * 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 (wbio->method == BIO_f_buffer() && (tmpbio = BIO_next(wbio)) != NULL)
    wbio = tmpbio;
  w = 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
   * we wrapped around by more than ULONG_MAX since the last time we called
   * this function.
   */
  *n_read = (size_t)(r - tls->last_read_count);
  *n_written = (size_t)(w - tls->last_write_count);
  if (*n_read > INT_MAX || *n_written > INT_MAX) {
    log_warn(LD_BUG, "Preposterously large value in tor_tls_get_n_raw_bytes. "
             "r=%lu, last_read=%lu, w=%lu, last_written=%lu",
             r, tls->last_read_count, w, tls->last_write_count);
  }
  tls->last_read_count = r;
  tls->last_write_count = w;
}

Here is the caller graph for this function:

Return the number of server handshakes that we've noticed doing on tls.

Definition at line 2404 of file tortls.c.

{
  return tls->server_handshake_count;
}

Return the peer certificate, or NULL if there isn't one.

Definition at line 2025 of file tortls.c.

{
  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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return the number of bytes available for reading from tls.

Definition at line 2235 of file tortls.c.

{
  tor_assert(tls);
  return SSL_pending(tls->ssl);
}

Here is the caller graph for this function:

void tor_tls_get_state_description ( tor_tls_t tls,
char *  buf,
size_t  sz 
)

Write a description of the current state of tls into the sz-byte buffer at buf.

Definition at line 243 of file tortls.c.

{
  const char *ssl_state;
  const char *tortls_state;

  if (PREDICT_UNLIKELY(!tls || !tls->ssl)) {
    strlcpy(buf, "(No SSL object)", sz);
    return;
  }

  ssl_state = SSL_state_string_long(tls->ssl);
  switch (tls->state) {
#define CASE(st) case TOR_TLS_ST_##st: tortls_state = " in "#st ; break
    CASE(HANDSHAKE);
    CASE(OPEN);
    CASE(GOTCLOSE);
    CASE(SENTCLOSE);
    CASE(CLOSED);
    CASE(RENEGOTIATE);
#undef CASE
  case TOR_TLS_ST_BUFFEREVENT:
    tortls_state = "";
    break;
  default:
    tortls_state = " in unknown TLS state";
    break;
  }

  tor_snprintf(buf, sz, "%s%s", ssl_state, tortls_state);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int tor_tls_get_tlssecrets ( tor_tls_t tls,
uint8_t *  secrets_out 
)

Set the DIGEST256_LEN buffer at secrets_out to the value used in the v3 handshake to prove that the client knows the TLS secrets for the connection tls.

Return 0 on success, -1 on failure.

Definition at line 2422 of file tortls.c.

{
#define TLSSECRET_MAGIC "Tor V3 handshake TLS cross-certification"
  char buf[128];
  size_t len;
  tor_assert(tls);
  tor_assert(tls->ssl);
  tor_assert(tls->ssl->s3);
  tor_assert(tls->ssl->session);
  /*
    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);
  memset(buf, 0, sizeof(buf));
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int tor_tls_handshake ( tor_tls_t tls)

Perform initial handshake on tls.

When finished, returns TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD, or TOR_TLS_WANTWRITE.

Definition at line 1806 of file tortls.c.

{
  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;
  if (tls->isServer) {
    log_debug(LD_HANDSHAKE, "About to call SSL_accept on %p (%s)", tls,
              SSL_state_string_long(tls->ssl));
    r = SSL_accept(tls->ssl);
  } else {
    log_debug(LD_HANDSHAKE, "About to call SSL_connect on %p (%s)", tls,
              SSL_state_string_long(tls->ssl));
    r = SSL_connect(tls->ssl);
  }
  if (oldstate != tls->ssl->state)
    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
   * for clearing its flags when you say accept or connect. */
  tor_tls_unblock_renegotiation(tls);
  r = tor_tls_get_error(tls,r,0, "handshaking", LOG_INFO, LD_HANDSHAKE);
  if (ERR_peek_error() != 0) {
    tls_log_errors(tls, tls->isServer ? LOG_INFO : LOG_WARN, LD_HANDSHAKE,
                   "handshaking");
    return TOR_TLS_ERROR_MISC;
  }
  if (r == TOR_TLS_DONE) {
    tls->state = TOR_TLS_ST_OPEN;
    return tor_tls_finish_handshake(tls);
  }
  return r;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void tor_tls_init ( void  ) [static]

Initialize OpenSSL, unless it has already been initialized.

Definition at line 449 of file tortls.c.

{
  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_notice(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_notice(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_notice(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);
    }

    tor_tls_allocate_tor_tls_object_ex_data_index();

    tls_library_is_initialized = 1;
  }
}

Here is the caller graph for this function:

int tor_tls_is_server ( tor_tls_t tls)

Return whether this tls initiated the connect (client) or received it (server).

Definition at line 1701 of file tortls.c.

{
  tor_assert(tls);
  return tls->isServer;
}

Here is the caller graph for this function:

void tor_tls_log_one_error ( tor_tls_t tls,
unsigned long  err,
int  severity,
int  domain,
const char *  doing 
)

Log a single error err as returned by ERR_get_error(), which was received while performing an operation doing on tls.

Log the message at severity, in log domain domain.

Definition at line 278 of file tortls.c.

{
  const char *state = NULL, *addr;
  const char *msg, *lib, *func;

  state = (tls && tls->ssl)?SSL_state_string_long(tls->ssl):"---";

  addr = tls ? tls->address : NULL;

  /* Some errors are known-benign, meaning they are the fault of the other
   * side of the connection. The caller doesn't know this, so override the
   * priority for those cases. */
  switch (ERR_GET_REASON(err)) {
    case SSL_R_HTTP_REQUEST:
    case SSL_R_HTTPS_PROXY_REQUEST:
    case SSL_R_RECORD_LENGTH_MISMATCH:
    case SSL_R_RECORD_TOO_LARGE:
    case SSL_R_UNKNOWN_PROTOCOL:
    case SSL_R_UNSUPPORTED_PROTOCOL:
      severity = LOG_INFO;
      break;
    default:
      break;
  }

  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 (!lib) lib = "(null)";
  if (!func) func = "(null)";
  if (doing) {
    log(severity, domain, "TLS error while %s%s%s: %s (in %s:%s:%s)",
        doing, addr?" with ":"", addr?addr:"",
        msg, lib, func, state);
  } else {
    log(severity, domain, "TLS error%s%s: %s (in %s:%s:%s)",
        addr?" with ":"", addr?addr:"",
        msg, lib, func, state);
  }
}

Here is the caller graph for this function:

tor_tls_t* tor_tls_new ( int  sock,
int  isServer 
)

Create a new TLS object from a file descriptor, and a flag to determine whether it is functioning as a server.

Definition at line 1544 of file tortls.c.

{
  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;
  result->magic = TOR_TLS_MAGIC;

  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;
  }

#ifdef SSL_set_tlsext_host_name
  /* Browsers use the TLS hostname extension, so we should too. */
  if (!isServer) {
    char *fake_hostname = crypto_random_hostname(4,25, "www.",".com");
    SSL_set_tlsext_host_name(result->ssl, fake_hostname);
    tor_free(fake_hostname);
  }
#endif

  if (!SSL_set_cipher_list(result->ssl,
                     isServer ? SERVER_CIPHER_LIST : CLIENT_CIPHER_LIST)) {
    tls_log_errors(NULL, LOG_WARN, LD_NET, "setting ciphers");
#ifdef SSL_set_tlsext_host_name
    SSL_set_tlsext_host_name(result->ssl, NULL);
#endif
    SSL_free(result->ssl);
    tor_free(result);
    return NULL;
  }
  if (!isServer)
    rectify_client_ciphers(&result->ssl->cipher_list);
  result->socket = sock;
  bio = BIO_new_socket(sock, BIO_NOCLOSE);
  if (! bio) {
    tls_log_errors(NULL, LOG_WARN, LD_NET, "opening BIO");
#ifdef SSL_set_tlsext_host_name
    SSL_set_tlsext_host_name(result->ssl, NULL);
#endif
    SSL_free(result->ssl);
    tor_free(result);
    return NULL;
  }
  {
    int set_worked =
      SSL_set_ex_data(result->ssl, tor_tls_object_ex_data_index, result);
    if (!set_worked) {
      log_warn(LD_BUG,
               "Couldn't set the tls for an SSL*; connection will fail");
    }
  }
  SSL_set_bio(result->ssl, bio, bio);
  tor_tls_context_incref(context);
  result->context = context;
  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);
  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
  {
    SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback);
  }

  /* Not expected to get called. */
  tls_log_errors(NULL, LOG_WARN, LD_NET, "creating tor_tls_t object");
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return true iff this TLS connection is authenticated.

Definition at line 2012 of file tortls.c.

{
  X509 *cert;
  cert = SSL_get_peer_certificate(tls->ssl);
  tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "getting peer certificate");
  if (!cert)
    return 0;
  X509_free(cert);
  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int tor_tls_read ( tor_tls_t tls,
char *  cp,
size_t  len 
)

Underlying function for TLS reading.

Reads up to len characters from tls into cp. On success, returns the number of characters read. On failure, returns TOR_TLS_ERROR, TOR_TLS_CLOSE, TOR_TLS_WANTREAD, or TOR_TLS_WANTWRITE.

Definition at line 1735 of file tortls.c.

{
  int r, err;
  tor_assert(tls);
  tor_assert(tls->ssl);
  tor_assert(tls->state == TOR_TLS_ST_OPEN);
  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));
      if (tls->negotiated_callback)
        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);
  if (err == _TOR_TLS_ZERORETURN || err == TOR_TLS_CLOSE) {
    log_debug(LD_NET,"read returned r=%d; TLS is closed",r);
    tls->state = TOR_TLS_ST_CLOSED;
    return TOR_TLS_CLOSE;
  } else {
    tor_assert(err != TOR_TLS_DONE);
    log_debug(LD_NET,"read returned r=%d, err=%d",r,err);
    return err;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return true iff the peer certificate we're received on tls 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.

Definition at line 2359 of file tortls.c.

{
  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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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.

Definition at line 1923 of file tortls.c.

{
  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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return true iff the server TLS connection tls got the renegotiation request it was waiting for.

Definition at line 2412 of file tortls.c.

{
  return tls->got_renegotiate;
}

Here is the caller graph for this function:

static void tor_tls_server_info_callback ( const SSL *  ssl,
int  type,
int  val 
) [static]

Invoked when we're accepting a connection on ssl, and the connection changes state.

We use this:

  • To alter the state of the handshake partway through, so we do not send or request extra certificates in v2 handshakes.
  • To detect renegotiation

Definition at line 1369 of file tortls.c.

{
  tor_tls_t *tls;
  (void) val;

  tor_tls_debug_state_callback(ssl, type, 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;

  tls = tor_tls_get_by_ssl(ssl);
  if (tls) {
    /* Check whether we're watching for renegotiates.  If so, this is one! */
    if (tls->negotiated_callback)
      tls->got_renegotiate = 1;
    if (tls->server_handshake_count < 127) /*avoid any overflow possibility*/
      ++tls->server_handshake_count;
  } else {
    log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
    return;
  }

  /* Now check the cipher list. */
  if (tor_tls_client_is_using_v2_ciphers(ssl, ADDR(tls))) {
    if (tls->wasV2Handshake)
      return; /* We already turned this stuff off for the first handshake;
               * This is a renegotiation. */

    /* Yes, we're casting away the const from ssl.  This is very naughty of us.
     * Let's hope openssl doesn't notice! */

    /* Set SSL_MODE_NO_AUTO_CHAIN to keep from sending back any extra certs. */
    SSL_set_mode((SSL*) ssl, SSL_MODE_NO_AUTO_CHAIN);
    /* Don't send a hello request. */
    SSL_set_verify((SSL*) ssl, SSL_VERIFY_NONE, NULL);

    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 {
      log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void tor_tls_set_logged_address ( tor_tls_t tls,
const char *  address 
)

Make future log messages about tls display the address address.

Definition at line 1629 of file tortls.c.

Here is the caller graph for this function:

void tor_tls_set_renegotiate_callback ( tor_tls_t tls,
void(*)(tor_tls_t *, void *arg)  cb,
void *  arg 
)

Set cb to be called with argument arg whenever tls next gets a client-side renegotiate in the middle of a read.

Do not invoke this function until after initial handshaking is done!

Definition at line 1641 of file tortls.c.

{
  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
}

Here is the call graph for this function:

Here is the caller graph for this function:

int tor_tls_shutdown ( tor_tls_t tls)

Shut down an open tls connection tls.

When finished, returns TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD, or TOR_TLS_WANTWRITE.

Definition at line 1952 of file tortls.c.

{
  int r, err;
  char buf[128];
  tor_assert(tls);
  tor_assert(tls->ssl);

  while (1) {
    if (tls->state == TOR_TLS_ST_SENTCLOSE) {
      /* If we've already called shutdown once to send a close message,
       * we read until the other side has closed too.
       */
      do {
        r = SSL_read(tls->ssl, buf, 128);
      } while (r>0);
      err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading to shut down",
                              LOG_INFO, LD_NET);
      if (err == _TOR_TLS_ZERORETURN) {
        tls->state = TOR_TLS_ST_GOTCLOSE;
        /* fall through... */
      } else {
        return err;
      }
    }

    r = SSL_shutdown(tls->ssl);
    if (r == 1) {
      /* If shutdown returns 1, the connection is entirely closed. */
      tls->state = TOR_TLS_ST_CLOSED;
      return TOR_TLS_DONE;
    }
    err = tor_tls_get_error(tls, r, CATCH_SYSCALL|CATCH_ZERO, "shutting down",
                            LOG_INFO, LD_NET);
    if (err == _TOR_TLS_SYSCALL) {
      /* The underlying TCP connection closed while we were shutting down. */
      tls->state = TOR_TLS_ST_CLOSED;
      return TOR_TLS_DONE;
    } else if (err == _TOR_TLS_ZERORETURN) {
      /* The TLS connection says that it sent a shutdown record, but
       * isn't done shutting down yet.  Make sure that this hasn't
       * happened before, then go back to the start of the function
       * and try to read.
       */
      if (tls->state == TOR_TLS_ST_GOTCLOSE ||
         tls->state == TOR_TLS_ST_SENTCLOSE) {
        log(LOG_WARN, LD_NET,
            "TLS returned \"half-closed\" value while already half-closed");
        return TOR_TLS_ERROR_MISC;
      }
      tls->state = TOR_TLS_ST_SENTCLOSE;
      /* fall through ... */
    } else {
      return err;
    }
  } /* end loop */
}

Here is the call graph for this function:

If this version of openssl requires it, turn on renegotiation on tls.

Definition at line 1661 of file tortls.c.

{
  /* 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);
  }
}

Here is the caller graph for this function:

Return true iff the initial TLS connection at tls did not use a v2 TLS handshake.

Output is undefined if the handshake isn't finished.

Definition at line 2301 of file tortls.c.

{
  if (tls->isServer) {
#ifdef V2_HANDSHAKE_SERVER
    return ! tls->wasV2Handshake;
#endif
  } else {
#ifdef V2_HANDSHAKE_CLIENT
    return ! tls->wasV2Handshake;
#endif
  }
  return 1;
}

Here is the caller graph for this function:

int tor_tls_verify ( int  severity,
tor_tls_t tls,
crypto_pk_t **  identity_key 
)

If the provided tls connection is authenticated and has a certificate chain that is currently valid and signed, then set *identity_key to the identity certificate's key and return 0.

Else, return -1 and log complaints with log-level severity.

Definition at line 2131 of file tortls.c.

{
  X509 *cert = NULL, *id_cert = NULL;
  EVP_PKEY *id_pkey = NULL;
  RSA *rsa;
  int r = -1;

  *identity_key = NULL;

  try_to_extract_certs_from_tls(severity, tls, &cert, &id_cert);
  if (!cert)
    goto done;
  if (!id_cert) {
    log_fn(severity,LD_PROTOCOL,"No distinct identity certificate found");
    goto done;
  }
  tls_log_errors(tls, severity, LD_HANDSHAKE, "before verifying certificate");

  if (!(id_pkey = X509_get_pubkey(id_cert)) ||
      X509_verify(cert, id_pkey) <= 0) {
    log_fn(severity,LD_PROTOCOL,"X509_verify on cert and pkey returned <= 0");
    tls_log_errors(tls, severity, LD_HANDSHAKE, "verifying certificate");
    goto done;
  }

  rsa = EVP_PKEY_get1_RSA(id_pkey);
  if (!rsa)
    goto done;
  *identity_key = _crypto_new_pk_from_rsa(rsa);

  r = 0;

 done:
  if (cert)
    X509_free(cert);
  if (id_pkey)
    EVP_PKEY_free(id_pkey);

  /* This should never get invoked, but let's make sure in case OpenSSL
   * acts unexpectedly. */
  tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, "finishing tor_tls_verify");

  return r;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int tor_tls_write ( tor_tls_t tls,
const char *  cp,
size_t  n 
)

Underlying function for TLS writing.

Write up to n characters from cp onto tls. On success, returns the number of characters written. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD, or TOR_TLS_WANTWRITE.

Definition at line 1773 of file tortls.c.

{
  int r, err;
  tor_assert(tls);
  tor_assert(tls->ssl);
  tor_assert(tls->state == TOR_TLS_ST_OPEN);
  tor_assert(n < INT_MAX);
  if (n == 0)
    return 0;
  if (tls->wantwrite_n) {
    /* if WANTWRITE last time, we must use the _same_ n as before */
    tor_assert(n >= tls->wantwrite_n);
    log_debug(LD_NET,"resuming pending-write, (%d to flush, reusing %d)",
              (int)n, (int)tls->wantwrite_n);
    n = tls->wantwrite_n;
    tls->wantwrite_n = 0;
  }
  r = SSL_write(tls->ssl, cp, (int)n);
  err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO, LD_NET);
  if (err == TOR_TLS_DONE) {
    return r;
  }
  if (err == TOR_TLS_WANTWRITE || err == TOR_TLS_WANTREAD) {
    tls->wantwrite_n = n;
  }
  return err;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static X509_NAME* tor_x509_name_new ( const char *  cname) [static]

Return a newly allocated X509 name with commonName cname.

Definition at line 551 of file tortls.c.

{
  int nid;
  X509_NAME *name;
  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;
  return name;
 error:
  X509_NAME_free(name);
  return NULL;
}

Here is the caller graph for this function:

static void try_to_extract_certs_from_tls ( int  severity,
tor_tls_t tls,
X509 **  cert_out,
X509 **  id_cert_out 
) [static]

Helper function: try to extract a link certificate and an identity certificate from tls, and store them in *cert_out and *id_cert_out respectively.

Log all messages at level severity.

Note that a reference is added to cert_out, so it needs to be freed. id_cert_out doesn't.

Definition at line 2093 of file tortls.c.

{
  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;
  if (!(chain = SSL_get_peer_cert_chain(tls->ssl)))
    return;
  num_in_chain = sk_X509_num(chain);
  /* 1 means we're receiving (server-side), and it's just the id_cert.
   * 2 means we're connecting (client-side), and it's both the link
   * cert and the id_cert.
   */
  if (num_in_chain < 1) {
    log_fn(severity,LD_PROTOCOL,
           "Unexpected number of certificates in chain (%d)",
           num_in_chain);
    return;
  }
  for (i=0; i<num_in_chain; ++i) {
    id_cert = sk_X509_value(chain, i);
    if (X509_cmp(id_cert, cert) != 0)
      break;
  }
  *id_cert_out = id_cert;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

SSL_CIPHER* CLIENT_CIPHER_DUMMIES = NULL [static]

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.

Definition at line 175 of file tortls.c.

A list of all the ciphers that clients should advertise, including items that OpenSSL might not know about.

Definition at line 688 of file tortls.c.

const char CLIENT_CIPHER_LIST[] = "!SSLv2" [static]

List of ciphers that clients should advertise, omitting items that our OpenSSL doesn't know about.

Definition at line 675 of file tortls.c.

Definition at line 230 of file tortls.c.

const int N_CLIENT_CIPHERS [static]
Initial value:

The length of CLIENT_CIPHER_INFO_LIST and CLIENT_CIPHER_DUMMIES.

Definition at line 697 of file tortls.c.

Global TLS contexts.

We keep them here because nobody else needs to touch them.

Definition at line 229 of file tortls.c.

int tls_library_is_initialized = 0 [static]

True iff tor_tls_init() has been called.

Definition at line 234 of file tortls.c.

Does the run-time openssl version look like we need SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION?

Definition at line 105 of file tortls.c.

int use_unsafe_renegotiation_op = 0 [static]

Does the run-time openssl version look like we need SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION?

Definition at line 102 of file tortls.c.