[or-cvs] [tor/master] Merge remote branch 'origin/maint-0.2.2'

nickm at torproject.org nickm at torproject.org
Thu Feb 3 18:56:55 UTC 2011


commit 912b76a1bf2645e74fbca8ba3f27f1a17d510cf5
Merge: 0fcb677 2fa9ddb
Author: Nick Mathewson <nickm at torproject.org>
Date:   Thu Feb 3 13:56:37 2011 -0500

    Merge remote branch 'origin/maint-0.2.2'

 changes/bug2378     |    8 ++++++++
 src/common/crypto.c |   19 +++++++------------
 src/common/crypto.h |    1 -
 src/common/tortls.c |    1 +
 src/or/onion.c      |    4 ++++
 5 files changed, 20 insertions(+), 13 deletions(-)

diff --combined src/common/crypto.c
index 1108ba2,cfbc002..587a83a
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@@ -326,17 -326,6 +326,6 @@@ _crypto_new_pk_env_rsa(RSA *rsa
    return env;
  }
  
- /** used by tortls.c: wrap the RSA from an evp_pkey in a crypto_pk_env_t.
-  * returns NULL if this isn't an RSA key. */
- crypto_pk_env_t *
- _crypto_new_pk_env_evp_pkey(EVP_PKEY *pkey)
- {
-   RSA *rsa;
-   if (!(rsa = EVP_PKEY_get1_RSA(pkey)))
-     return NULL;
-   return _crypto_new_pk_env_rsa(rsa);
- }
- 
  /** Helper, used by tor-checkkey.c and tor-gencert.c.  Return the RSA from a
   * crypto_pk_env_t. */
  RSA *
@@@ -390,7 -379,7 +379,7 @@@ crypto_new_pk_env(void
    RSA *rsa;
  
    rsa = RSA_new();
-   if (!rsa) return NULL;
+   tor_assert(rsa);
    return _crypto_new_pk_env_rsa(rsa);
  }
  
@@@ -535,6 -524,8 +524,8 @@@ crypto_pk_read_private_key_from_string(
  
    /* Create a read-only memory BIO, backed by the string 's' */
    b = BIO_new_mem_buf((char*)s, (int)len);
+   if (!b)
+     return -1;
  
    if (env->key)
      RSA_free(env->key);
@@@ -595,6 -586,8 +586,8 @@@ crypto_pk_write_key_to_string_impl(cryp
    tor_assert(dest);
  
    b = BIO_new(BIO_s_mem()); /* Create a memory BIO */
+   if (!b)
+     return -1;
  
    /* Now you can treat b as if it were a file.  Just use the
     * PEM_*_bio_* functions instead of the non-bio variants.
@@@ -662,6 -655,8 +655,8 @@@ crypto_pk_read_public_key_from_string(c
    tor_assert(len<INT_MAX);
  
    b = BIO_new(BIO_s_mem()); /* Create a memory BIO */
+   if (!b)
+     return -1;
  
    BIO_write(b, src, (int)len);
  
@@@ -927,7 -922,7 +922,7 @@@ crypto_pk_public_checksig_digest(crypto
      log_warn(LD_BUG, "couldn't compute digest");
      return -1;
    }
 -  buflen = crypto_pk_keysize(env)+1;
 +  buflen = crypto_pk_keysize(env);
    buf = tor_malloc(buflen);
    r = crypto_pk_public_checksig(env,buf,buflen,sig,siglen);
    if (r != DIGEST_LEN) {
@@@ -1112,8 -1107,8 +1107,8 @@@ crypto_pk_private_hybrid_decrypt(crypto
                                       warnOnFailure);
    }
  
 -  buf = tor_malloc(pkeylen+1);
 -  outlen = crypto_pk_private_decrypt(env,buf,pkeylen+1,from,pkeylen,padding,
 +  buf = tor_malloc(pkeylen);
 +  outlen = crypto_pk_private_decrypt(env,buf,pkeylen,from,pkeylen,padding,
                                       warnOnFailure);
    if (outlen<0) {
      log_fn(warnOnFailure?LOG_WARN:LOG_DEBUG, LD_CRYPTO,
@@@ -2689,3 -2684,4 +2684,3 @@@ setup_openssl_threading(void
    return 0;
  }
  #endif
 -
diff --combined src/common/crypto.h
index f114dd6,05185f3..d50ca70
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@@ -243,14 -243,12 +243,13 @@@ void secret_to_key(char *key_out, size_
                     size_t secret_len, const char *s2k_specifier);
  
  #ifdef CRYPTO_PRIVATE
 -/* Prototypes for private functions only used by tortls.c and crypto.c */
 +/* Prototypes for private functions only used by tortls.c, crypto.c, and the
 + * unit tests. */
  struct rsa_st;
  struct evp_pkey_st;
  struct dh_st;
  struct rsa_st *_crypto_pk_env_get_rsa(crypto_pk_env_t *env);
  crypto_pk_env_t *_crypto_new_pk_env_rsa(struct rsa_st *rsa);
- crypto_pk_env_t *_crypto_new_pk_env_evp_pkey(struct evp_pkey_st *pkey);
  struct evp_pkey_st *_crypto_pk_env_get_evp_pkey(crypto_pk_env_t *env,
                                                  int private);
  struct dh_st *_crypto_dh_env_get_dh(crypto_dh_env_t *dh);
diff --combined src/common/tortls.c
index 6d38b55,10f4440..ca9e92c
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@@ -44,14 -44,7 +44,14 @@@
  #error "We require OpenSSL >= 0.9.7"
  #endif
  
 +#ifdef USE_BUFFEREVENTS
 +#include <event2/bufferevent_ssl.h>
 +#include <event2/buffer.h>
 +#include "compat_libevent.h"
 +#endif
 +
  #define CRYPTO_PRIVATE /* to import prototypes from crypto.h */
 +#define TORTLS_PRIVATE
  
  #include "crypto.h"
  #include "tortls.h"
@@@ -116,7 -109,6 +116,7 @@@ struct tor_tls_t 
    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
    } 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 */
@@@ -125,10 -117,8 +125,10 @@@
                                    * 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. */
 +  /** True iff we should call negotiated_callback when we're done reading. */
    unsigned int got_renegotiate:1;
 +  /** 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
@@@ -199,7 -189,7 +199,7 @@@ static X509* tor_tls_create_certificate
                                          const char *cname,
                                          const char *cname_sign,
                                          unsigned int lifetime);
 -static void tor_tls_unblock_renegotiation(tor_tls_t *tls);
 +
  static int tor_tls_context_init_one(tor_tls_context_t **ppcontext,
                                      crypto_pk_env_t *identity,
                                      unsigned int key_lifetime);
@@@ -210,7 -200,6 +210,7 @@@ static tor_tls_context_t *tor_tls_conte
   * to touch them. */
  static tor_tls_context_t *server_tls_context = NULL;
  static tor_tls_context_t *client_tls_context = NULL;
 +
  /** True iff tor_tls_init() has been called. */
  static int tls_library_is_initialized = 0;
  
@@@ -234,46 -223,36 +234,46 @@@ ssl_state_to_string(int ssl_state
    return buf;
  }
  
 +void
 +tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
 +                  int severity, int domain, const char *doing)
 +{
 +  const char *state = NULL, *addr;
 +  const char *msg, *lib, *func;
 +  int st;
 +
 +  st = (tls && tls->ssl) ? tls->ssl->state : -1;
 +  state = (st>=0)?ssl_state_to_string(st):"---";
 +
 +  addr = tls ? tls->address : NULL;
 +
 +  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);
 +  }
 +}
 +
  /** Log all pending tls errors at level <b>severity</b>.  Use
   * <b>doing</b> to describe our current activities.
   */
  static void
  tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing)
  {
 -  const char *state = NULL;
 -  int st;
    unsigned long err;
 -  const char *msg, *lib, *func, *addr;
 -  addr = tls ? tls->address : NULL;
 -  st = (tls && tls->ssl) ? tls->ssl->state : -1;
 +
    while ((err = ERR_get_error()) != 0) {
 -    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 (!state)
 -      state = (st>=0)?ssl_state_to_string(st):"---";
 -    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);
 -    }
 +    tor_tls_log_one_error(tls, err, severity, domain, doing);
    }
  }
  
@@@ -829,6 -808,7 +829,7 @@@ tor_tls_context_new(crypto_pk_env_t *id
      goto error;
    {
      crypto_dh_env_t *dh = crypto_dh_new(DH_TYPE_TLS);
+     tor_assert(dh);
      SSL_CTX_set_tmp_dh(result->ctx, _crypto_dh_env_get_dh(dh));
      crypto_dh_free(dh);
    }
@@@ -933,8 -913,6 +934,8 @@@ tor_tls_server_info_callback(const SSL 
      /* 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!");
    }
@@@ -953,10 -931,6 +954,10 @@@
  
      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!");
      }
@@@ -1143,7 -1117,7 +1144,7 @@@ tor_tls_set_renegotiate_callback(tor_tl
  /** If this version of openssl requires it, turn on renegotiation on
   * <b>tls</b>.
   */
 -static void
 +void
  tor_tls_unblock_renegotiation(tor_tls_t *tls)
  {
    /* Yes, we know what we are doing here.  No, we do not treat a renegotiation
@@@ -1167,19 -1141,6 +1168,19 @@@ tor_tls_block_renegotiation(tor_tls_t *
    tls->ssl->s3->flags &= ~SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
  }
  
 +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));
 +  }
 +}
 +
  /** Return whether this tls initiated the connect (client) or
   * received it (server). */
  int
@@@ -1324,86 -1285,56 +1325,86 @@@ tor_tls_handshake(tor_tls_t *tls
    }
    if (r == TOR_TLS_DONE) {
      tls->state = TOR_TLS_ST_OPEN;
 -    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;
 +    return tor_tls_finish_handshake(tls);
 +  }
 +  return r;
 +}
 +
 +/** Perform the final part of the intial TLS handshake on <b>tls</b>.  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.
 + */
 +int
 +tor_tls_finish_handshake(tor_tls_t *tls)
 +{
 +  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;
 +    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.");
        }
 -#endif
 +      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);
 +    /* 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;
 -      }
 +    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;
  }
  
 +#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.
@@@ -1620,8 -1551,6 +1621,8 @@@ tor_tls_verify(int severity, tor_tls_t 
      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");
@@@ -1771,22 -1700,6 +1772,22 @@@ tor_tls_used_v1_handshake(tor_tls_t *tl
    return 1;
  }
  
 +/** Return the number of server handshakes that we've noticed doing on
 + * <b>tls</b>. */
 +int
 +tor_tls_get_num_server_handshakes(tor_tls_t *tls)
 +{
 +  return tls->server_handshake_count;
 +}
 +
 +/** Return true iff the server TLS connection <b>tls</b> got the renegotiation
 + * request it was waiting for. */
 +int
 +tor_tls_server_got_renegotiate(tor_tls_t *tls)
 +{
 +  return tls->got_renegotiate;
 +}
 +
  /** Examine the amount of memory used and available for buffers in <b>tls</b>.
   * 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.
@@@ -1809,71 -1722,3 +1810,71 @@@ tor_tls_get_buffer_sizes(tor_tls_t *tls
    *wbuf_bytes = tls->ssl->s3->wbuf.left;
  }
  
 +#ifdef USE_BUFFEREVENTS
 +/** Construct and return an TLS-encrypting bufferevent to send data over
 + * <b>socket</b>, which must match the socket of the underlying bufferevent
 + * <b>bufev_in</b>.  The TLS object <b>tls</b> is used for encryption.
 + *
 + * This function will either create a filtering bufferevent that wraps around
 + * <b>bufev_in</b>, or it will free bufev_in and return a new bufferevent that
 + * uses the <b>tls</b> to talk to the network directly.  Do not use
 + * <b>bufev_in</b> after calling this function.
 + *
 + * The connection will start out doing a server handshake if <b>receiving</b>
 + * is strue, and a client handshake otherwise.
 + *
 + * Returns NULL on failure.
 + */
 +struct bufferevent *
 +tor_tls_init_bufferevent(tor_tls_t *tls, struct bufferevent *bufev_in,
 +                         evutil_socket_t socket, int receiving,
 +                         int filter)
 +{
 +  struct bufferevent *out;
 +  const enum bufferevent_ssl_state state = receiving ?
 +    BUFFEREVENT_SSL_ACCEPTING : BUFFEREVENT_SSL_CONNECTING;
 +
 +  if (filter) {
 +    /* Grab an extra reference to the SSL, since BEV_OPT_CLOSE_ON_FREE
 +       means that the SSL will get freed too.
 +
 +       This increment makes our SSL usage not-threadsafe, BTW.  We should
 +       see if we're allowed to use CRYPTO_add from outside openssl. */
 +    tls->ssl->references += 1;
 +    out = bufferevent_openssl_filter_new(tor_libevent_get_base(),
 +                                         bufev_in,
 +                                         tls->ssl,
 +                                         state,
 +                                         BEV_OPT_DEFER_CALLBACKS|
 +                                         BEV_OPT_CLOSE_ON_FREE);
 +  } else {
 +    if (bufev_in) {
 +      evutil_socket_t s = bufferevent_getfd(bufev_in);
 +      tor_assert(s == -1 || s == socket);
 +      tor_assert(evbuffer_get_length(bufferevent_get_input(bufev_in)) == 0);
 +      tor_assert(evbuffer_get_length(bufferevent_get_output(bufev_in)) == 0);
 +      tor_assert(BIO_number_read(SSL_get_rbio(tls->ssl)) == 0);
 +      tor_assert(BIO_number_written(SSL_get_rbio(tls->ssl)) == 0);
 +      bufferevent_free(bufev_in);
 +    }
 +
 +    /* Current versions (as of 2.0.x) of Libevent need to defer
 +     * bufferevent_openssl callbacks, or else our callback functions will
 +     * get called reentrantly, which is bad for us.
 +     */
 +    out = bufferevent_openssl_socket_new(tor_libevent_get_base(),
 +                                         socket,
 +                                         tls->ssl,
 +                                         state,
 +                                         BEV_OPT_DEFER_CALLBACKS);
 +  }
 +  tls->state = TOR_TLS_ST_BUFFEREVENT;
 +
 +  /* Unblock _after_ creating the bufferevent, since accept/connect tend to
 +   * clear flags. */
 +  tor_tls_unblock_renegotiation(tls);
 +
 +  return out;
 +}
 +#endif
 +



More information about the tor-commits mailing list