[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

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



commit a7790d48af73760a2ae10fcff70b319914316b90
Merge: 1393985 ef6fa07
Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
Date:   Sat Jan 15 14:15:19 2011 -0500

    Merge remote branch 'origin/maint-0.2.1' into maint-0.2.2

 changes/bug2384      |    6 ++++++
 src/common/crypto.c  |   12 +++++++++---
 src/or/rendclient.c  |    2 ++
 src/or/rendservice.c |    2 ++
 4 files changed, 19 insertions(+), 3 deletions(-)

diff --combined src/common/crypto.c
index 1d12a9d,29137a8..e847d8c
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@@ -27,7 -27,6 +27,7 @@@
  #include <openssl/rsa.h>
  #include <openssl/pem.h>
  #include <openssl/evp.h>
 +#include <openssl/engine.h>
  #include <openssl/rand.h>
  #include <openssl/opensslv.h>
  #include <openssl/bn.h>
@@@ -50,9 -49,9 +50,9 @@@
  
  #define CRYPTO_PRIVATE
  #include "crypto.h"
 -#include "log.h"
 +#include "../common/torlog.h"
  #include "aes.h"
 -#include "util.h"
 +#include "../common/util.h"
  #include "container.h"
  #include "compat.h"
  
@@@ -62,33 -61,6 +62,33 @@@
  
  #include <openssl/engine.h>
  
 +#ifdef ANDROID
 +/* Android's OpenSSL seems to have removed all of its Engine support. */
 +#define DISABLE_ENGINES
 +#endif
 +
 +#if OPENSSL_VERSION_NUMBER < 0x00908000l
 +/* On OpenSSL versions before 0.9.8, there is no working SHA256
 + * implementation, so we use Tom St Denis's nice speedy one, slightly adapted
 + * to our needs */
 +#define SHA256_CTX sha256_state
 +#define SHA256_Init sha256_init
 +#define SHA256_Update sha256_process
 +#define LTC_ARGCHK(x) tor_assert(x)
 +#include "sha256.c"
 +#define SHA256_Final(a,b) sha256_done(b,a)
 +
 +static unsigned char *
 +SHA256(const unsigned char *m, size_t len, unsigned char *d)
 +{
 +  SHA256_CTX ctx;
 +  SHA256_Init(&ctx);
 +  SHA256_Update(&ctx, m, len);
 +  SHA256_Final(d, &ctx);
 +  return d;
 +}
 +#endif
 +
  /** Macro: is k a valid RSA public or private key? */
  #define PUBLIC_KEY_OK(k) ((k) && (k)->key && (k)->key->n)
  /** Macro: is k a valid RSA private key? */
@@@ -122,7 -94,7 +122,7 @@@ struct crypto_dh_env_t 
  };
  
  static int setup_openssl_threading(void);
 -static int tor_check_dh_key(BIGNUM *bn);
 +static int tor_check_dh_key(int severity, BIGNUM *bn);
  
  /** Return the number of bytes added by padding method <b>padding</b>.
   */
@@@ -179,7 -151,6 +179,7 @@@ crypto_log_errors(int severity, const c
    }
  }
  
 +#ifndef DISABLE_ENGINES
  /** Log any OpenSSL engines we're using at NOTICE. */
  static void
  log_engine(const char *fn, ENGINE *e)
@@@ -194,82 -165,37 +194,82 @@@
      log(LOG_INFO, LD_CRYPTO, "Using default implementation for %s", fn);
    }
  }
 +#endif
 +
 +#ifndef DISABLE_ENGINES
 +/** Try to load an engine in a shared library via fully qualified path.
 + */
 +static ENGINE *
 +try_load_engine(const char *path, const char *engine)
 +{
 +  ENGINE *e = ENGINE_by_id("dynamic");
 +  if (e) {
 +    if (!ENGINE_ctrl_cmd_string(e, "ID", engine, 0) ||
 +        !ENGINE_ctrl_cmd_string(e, "DIR_LOAD", "2", 0) ||
 +        !ENGINE_ctrl_cmd_string(e, "DIR_ADD", path, 0) ||
 +        !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) {
 +      ENGINE_free(e);
 +      e = NULL;
 +    }
 +  }
 +  return e;
 +}
 +#endif
  
  /** Initialize the crypto library.  Return 0 on success, -1 on failure.
   */
  int
 -crypto_global_init(int useAccel)
 +crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
  {
    if (!_crypto_global_initialized) {
      ERR_load_crypto_strings();
      OpenSSL_add_all_algorithms();
      _crypto_global_initialized = 1;
      setup_openssl_threading();
 -    /* XXX the below is a bug, since we can't know if we're supposed
 -     * to be using hardware acceleration or not. we should arrange
 -     * for this function to be called before init_keys. But make it
 -     * not complain loudly, at least until we make acceleration work. */
 -    if (useAccel < 0) {
 -      log_info(LD_CRYPTO, "Initializing OpenSSL via tor_tls_init().");
 -    }
      if (useAccel > 0) {
 +#ifdef DISABLE_ENGINES
 +      (void)accelName;
 +      (void)accelDir;
 +      log_warn(LD_CRYPTO, "No OpenSSL hardware acceleration support enabled.");
 +#else
 +      ENGINE *e = NULL;
 +
        log_info(LD_CRYPTO, "Initializing OpenSSL engine support.");
        ENGINE_load_builtin_engines();
 -      if (!ENGINE_register_all_complete())
 -        return -1;
 -
 -      /* XXXX make sure this isn't leaking. */
 +      ENGINE_register_all_complete();
 +
 +      if (accelName) {
 +        if (accelDir) {
 +          log_info(LD_CRYPTO, "Trying to load dynamic OpenSSL engine \"%s\""
 +                   " via path \"%s\".", accelName, accelDir);
 +          e = try_load_engine(accelName, accelDir);
 +        } else {
 +          log_info(LD_CRYPTO, "Initializing dynamic OpenSSL engine \"%s\""
 +                   " acceleration support.", accelName);
 +          e = ENGINE_by_id(accelName);
 +        }
 +        if (!e) {
 +          log_warn(LD_CRYPTO, "Unable to load dynamic OpenSSL engine \"%s\".",
 +                   accelName);
 +        } else {
 +          log_info(LD_CRYPTO, "Loaded dynamic OpenSSL engine \"%s\".",
 +                   accelName);
 +        }
 +      }
 +      if (e) {
 +        log_info(LD_CRYPTO, "Loaded OpenSSL hardware acceleration engine,"
 +                 " setting default ciphers.");
 +        ENGINE_set_default(e, ENGINE_METHOD_ALL);
 +      }
        log_engine("RSA", ENGINE_get_default_RSA());
        log_engine("DH", ENGINE_get_default_DH());
        log_engine("RAND", ENGINE_get_default_RAND());
        log_engine("SHA1", ENGINE_get_digest_engine(NID_sha1));
        log_engine("3DES", ENGINE_get_cipher_engine(NID_des_ede3_ecb));
        log_engine("AES", ENGINE_get_cipher_engine(NID_aes_128_ecb));
 +#endif
 +    } else {
 +      log_info(LD_CRYPTO, "NOT using OpenSSL engine support.");
      }
      return crypto_seed_rng(1);
    }
@@@ -291,11 -217,7 +291,11 @@@ crypto_global_cleanup(void
    EVP_cleanup();
    ERR_remove_state(0);
    ERR_free_strings();
 +
 +#ifndef DISABLE_ENGINES
    ENGINE_cleanup();
 +#endif
 +
    CONF_modules_unload(1);
    CRYPTO_cleanup_all_ex_data();
  #ifdef TOR_IS_MULTITHREADED
@@@ -337,8 -259,7 +337,8 @@@ _crypto_new_pk_env_evp_pkey(EVP_PKEY *p
    return _crypto_new_pk_env_rsa(rsa);
  }
  
 -/** Helper, used by tor-checkkey.c.  Return the RSA from a crypto_pk_env_t. */
 +/** Helper, used by tor-checkkey.c and tor-gencert.c.  Return the RSA from a
 + * crypto_pk_env_t. */
  RSA *
  _crypto_pk_env_get_rsa(crypto_pk_env_t *env)
  {
@@@ -400,12 -321,10 +400,12 @@@ crypto_new_pk_env(void
  void
  crypto_free_pk_env(crypto_pk_env_t *env)
  {
 -  tor_assert(env);
 +  if (!env)
 +    return;
  
    if (--env->refs > 0)
      return;
 +  tor_assert(env->refs == 0);
  
    if (env->key)
      RSA_free(env->key);
@@@ -428,7 -347,10 +428,7 @@@ crypto_create_init_cipher(const char *k
      return NULL;
    }
  
 -  if (crypto_cipher_set_key(crypto, key)) {
 -    crypto_log_errors(LOG_WARN, "setting symmetric key");
 -    goto error;
 -  }
 +  crypto_cipher_set_key(crypto, key);
  
    if (encrypt_mode)
      r = crypto_cipher_encrypt_init_cipher(crypto);
@@@ -462,8 -384,7 +462,8 @@@ crypto_new_cipher_env(void
  void
  crypto_free_cipher_env(crypto_cipher_env_t *env)
  {
 -  tor_assert(env);
 +  if (!env)
 +    return;
  
    tor_assert(env->cipher);
    aes_free_cipher(env->cipher);
@@@ -473,11 -394,11 +473,11 @@@
  
  /* public key crypto */
  
 -/** Generate a new public/private keypair in <b>env</b>.  Return 0 on
 - * success, -1 on failure.
 +/** Generate a <b>bits</b>-bit new public/private keypair in <b>env</b>.
 + * Return 0 on success, -1 on failure.
   */
  int
 -crypto_pk_generate_key(crypto_pk_env_t *env)
 +crypto_pk_generate_key_with_bits(crypto_pk_env_t *env, int bits)
  {
    tor_assert(env);
  
@@@ -485,7 -406,7 +485,7 @@@
      RSA_free(env->key);
  #if OPENSSL_VERSION_NUMBER < 0x00908000l
    /* In OpenSSL 0.9.7, RSA_generate_key is all we have. */
 -  env->key = RSA_generate_key(PK_BYTES*8,65537, NULL, NULL);
 +  env->key = RSA_generate_key(bits, 65537, NULL, NULL);
  #else
    /* In OpenSSL 0.9.8, RSA_generate_key is deprecated. */
    {
@@@ -498,7 -419,7 +498,7 @@@
      r = RSA_new();
      if (!r)
        goto done;
 -    if (RSA_generate_key_ex(r, PK_BYTES*8, e, NULL) == -1)
 +    if (RSA_generate_key_ex(r, bits, e, NULL) == -1)
        goto done;
  
      env->key = r;
@@@ -569,6 -490,7 +569,7 @@@ crypto_pk_read_private_key_from_filenam
  
    /* Try to parse it. */
    r = crypto_pk_read_private_key_from_string(env, contents, -1);
+   memset(contents, 0, strlen(contents));
    tor_free(contents);
    if (r)
      return -1; /* read_private_key_from_string already warned, so we don't.*/
@@@ -706,6 -628,7 +707,7 @@@ crypto_pk_write_private_key_to_filename
    s[len]='\0';
    r = write_str_to_file(fname, s, 0);
    BIO_free(bio);
+   memset(s, 0, strlen(s));
    tor_free(s);
    return r;
  }
@@@ -782,25 -705,14 +784,25 @@@ crypto_pk_env_t 
  crypto_pk_copy_full(crypto_pk_env_t *env)
  {
    RSA *new_key;
 +  int privatekey = 0;
    tor_assert(env);
    tor_assert(env->key);
  
    if (PRIVATE_KEY_OK(env)) {
      new_key = RSAPrivateKey_dup(env->key);
 +    privatekey = 1;
    } else {
      new_key = RSAPublicKey_dup(env->key);
    }
 +  if (!new_key) {
 +    log_err(LD_CRYPTO, "Unable to duplicate a %s key: openssl failed.",
 +            privatekey?"private":"public");
 +    crypto_log_errors(LOG_ERR,
 +                      privatekey ? "Duplicating a private key" :
 +                      "Duplicating a public key");
 +    tor_fragile_assert();
 +    return NULL;
 +  }
  
    return _crypto_new_pk_env_rsa(new_key);
  }
@@@ -1301,14 -1213,19 +1303,14 @@@ crypto_cipher_generate_key(crypto_ciphe
  
  /** Set the symmetric key for the cipher in <b>env</b> to the first
   * CIPHER_KEY_LEN bytes of <b>key</b>. Does not initialize the cipher.
 - * Return 0 on success, -1 on failure.
   */
 -int
 +void
  crypto_cipher_set_key(crypto_cipher_env_t *env, const char *key)
  {
    tor_assert(env);
    tor_assert(key);
  
 -  if (!env->key)
 -    return -1;
 -
    memcpy(env->key, key, CIPHER_KEY_LEN);
 -  return 0;
  }
  
  /** Generate an initialization vector for our AES-CTR cipher; store it
@@@ -1485,69 -1402,9 +1487,69 @@@ crypto_digest(char *digest, const char 
    return (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL);
  }
  
 +int
 +crypto_digest256(char *digest, const char *m, size_t len,
 +                 digest_algorithm_t algorithm)
 +{
 +  tor_assert(m);
 +  tor_assert(digest);
 +  tor_assert(algorithm == DIGEST_SHA256);
 +  return (SHA256((const unsigned char*)m,len,(unsigned char*)digest) == NULL);
 +}
 +
 +/** Set the digests_t in <b>ds_out</b> to contain every digest on the
 + * <b>len</b> bytes in <b>m</b> that we know how to compute.  Return 0 on
 + * success, -1 on failure. */
 +int
 +crypto_digest_all(digests_t *ds_out, const char *m, size_t len)
 +{
 +  digest_algorithm_t i;
 +  tor_assert(ds_out);
 +  memset(ds_out, 0, sizeof(*ds_out));
 +  if (crypto_digest(ds_out->d[DIGEST_SHA1], m, len) < 0)
 +    return -1;
 +  for (i = DIGEST_SHA256; i < N_DIGEST_ALGORITHMS; ++i) {
 +    if (crypto_digest256(ds_out->d[i], m, len, i) < 0)
 +      return -1;
 +  }
 +  return 0;
 +}
 +
 +/** Return the name of an algorithm, as used in directory documents. */
 +const char *
 +crypto_digest_algorithm_get_name(digest_algorithm_t alg)
 +{
 +  switch (alg) {
 +    case DIGEST_SHA1:
 +      return "sha1";
 +    case DIGEST_SHA256:
 +      return "sha256";
 +    default:
 +      tor_fragile_assert();
 +      return "??unknown_digest??";
 +  }
 +}
 +
 +/** Given the name of a digest algorithm, return its integer value, or -1 if
 + * the name is not recognized. */
 +int
 +crypto_digest_algorithm_parse_name(const char *name)
 +{
 +  if (!strcmp(name, "sha1"))
 +    return DIGEST_SHA1;
 +  else if (!strcmp(name, "sha256"))
 +    return DIGEST_SHA256;
 +  else
 +    return -1;
 +}
 +
  /** Intermediate information about the digest of a stream of data. */
  struct crypto_digest_env_t {
 -  SHA_CTX d;
 +  union {
 +    SHA_CTX sha1;
 +    SHA256_CTX sha2;
 +  } d;
 +  digest_algorithm_t algorithm : 8;
  };
  
  /** Allocate and return a new digest object.
@@@ -1557,19 -1414,7 +1559,19 @@@ crypto_new_digest_env(void
  {
    crypto_digest_env_t *r;
    r = tor_malloc(sizeof(crypto_digest_env_t));
 -  SHA1_Init(&r->d);
 +  SHA1_Init(&r->d.sha1);
 +  r->algorithm = DIGEST_SHA1;
 +  return r;
 +}
 +
 +crypto_digest_env_t *
 +crypto_new_digest256_env(digest_algorithm_t algorithm)
 +{
 +  crypto_digest_env_t *r;
 +  tor_assert(algorithm == DIGEST_SHA256);
 +  r = tor_malloc(sizeof(crypto_digest_env_t));
 +  SHA256_Init(&r->d.sha2);
 +  r->algorithm = algorithm;
    return r;
  }
  
@@@ -1578,8 -1423,6 +1580,8 @@@
  void
  crypto_free_digest_env(crypto_digest_env_t *digest)
  {
 +  if (!digest)
 +    return;
    memset(digest, 0, sizeof(crypto_digest_env_t));
    tor_free(digest);
  }
@@@ -1592,51 -1435,30 +1594,51 @@@ crypto_digest_add_bytes(crypto_digest_e
  {
    tor_assert(digest);
    tor_assert(data);
 -  /* Using the SHA1_*() calls directly means we don't support doing
 -   * SHA1 in hardware. But so far the delay of getting the question
 +  /* Using the SHA*_*() calls directly means we don't support doing
 +   * SHA in hardware. But so far the delay of getting the question
     * to the hardware, and hearing the answer, is likely higher than
     * just doing it ourselves. Hashes are fast.
     */
 -  SHA1_Update(&digest->d, (void*)data, len);
 +  switch (digest->algorithm) {
 +    case DIGEST_SHA1:
 +      SHA1_Update(&digest->d.sha1, (void*)data, len);
 +      break;
 +    case DIGEST_SHA256:
 +      SHA256_Update(&digest->d.sha2, (void*)data, len);
 +      break;
 +    default:
 +      tor_fragile_assert();
 +      break;
 +  }
  }
  
  /** Compute the hash of the data that has been passed to the digest
   * object; write the first out_len bytes of the result to <b>out</b>.
 - * <b>out_len</b> must be \<= DIGEST_LEN.
 + * <b>out_len</b> must be \<= DIGEST256_LEN.
   */
  void
  crypto_digest_get_digest(crypto_digest_env_t *digest,
                           char *out, size_t out_len)
  {
 -  unsigned char r[DIGEST_LEN];
 -  SHA_CTX tmpctx;
 +  unsigned char r[DIGEST256_LEN];
 +  crypto_digest_env_t tmpenv;
    tor_assert(digest);
    tor_assert(out);
 -  tor_assert(out_len <= DIGEST_LEN);
 -  /* memcpy into a temporary ctx, since SHA1_Final clears the context */
 -  memcpy(&tmpctx, &digest->d, sizeof(SHA_CTX));
 -  SHA1_Final(r, &tmpctx);
 +  /* memcpy into a temporary ctx, since SHA*_Final clears the context */
 +  memcpy(&tmpenv, digest, sizeof(crypto_digest_env_t));
 +  switch (digest->algorithm) {
 +    case DIGEST_SHA1:
 +      tor_assert(out_len <= DIGEST_LEN);
 +      SHA1_Final(r, &tmpenv.d.sha1);
 +      break;
 +    case DIGEST_SHA256:
 +      tor_assert(out_len <= DIGEST256_LEN);
 +      SHA256_Final(r, &tmpenv.d.sha2);
 +      break;
 +    default:
 +      tor_fragile_assert();
 +      break;
 +  }
    memcpy(out, r, out_len);
    memset(r, 0, sizeof(r));
  }
@@@ -1772,7 -1594,7 +1774,7 @@@ crypto_dh_generate_public(crypto_dh_env
      crypto_log_errors(LOG_WARN, "generating DH key");
      return -1;
    }
 -  if (tor_check_dh_key(dh->dh->pub_key)<0) {
 +  if (tor_check_dh_key(LOG_WARN, dh->dh->pub_key)<0) {
      log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid.  I guess once-in-"
               "the-universe chances really do happen.  Trying again.");
      /* Free and clear the keys, so OpenSSL will actually try again. */
@@@ -1819,7 -1641,7 +1821,7 @@@ crypto_dh_get_public(crypto_dh_env_t *d
   * See http://www.cl.cam.ac.uk/ftp/users/rja14/psandqs.ps.gz for some tips.
   */
  static int
 -tor_check_dh_key(BIGNUM *bn)
 +tor_check_dh_key(int severity, BIGNUM *bn)
  {
    BIGNUM *x;
    char *s;
@@@ -1830,13 -1652,13 +1832,13 @@@
      init_dh_param();
    BN_set_word(x, 1);
    if (BN_cmp(bn,x)<=0) {
 -    log_warn(LD_CRYPTO, "DH key must be at least 2.");
 +    log_fn(severity, LD_CRYPTO, "DH key must be at least 2.");
      goto err;
    }
    BN_copy(x,dh_param_p);
    BN_sub_word(x, 1);
    if (BN_cmp(bn,x)>=0) {
 -    log_warn(LD_CRYPTO, "DH key must be at most p-2.");
 +    log_fn(severity, LD_CRYPTO, "DH key must be at most p-2.");
      goto err;
    }
    BN_free(x);
@@@ -1844,7 -1666,7 +1846,7 @@@
   err:
    BN_free(x);
    s = BN_bn2hex(bn);
 -  log_warn(LD_CRYPTO, "Rejecting insecure DH key [%s]", s);
 +  log_fn(severity, LD_CRYPTO, "Rejecting insecure DH key [%s]", s);
    OPENSSL_free(s);
    return -1;
  }
@@@ -1862,13 -1684,13 +1864,13 @@@
   * where || is concatenation.)
   */
  ssize_t
 -crypto_dh_compute_secret(crypto_dh_env_t *dh,
 +crypto_dh_compute_secret(int severity, crypto_dh_env_t *dh,
                           const char *pubkey, size_t pubkey_len,
                           char *secret_out, size_t secret_bytes_out)
  {
    char *secret_tmp = NULL;
    BIGNUM *pubkey_bn = NULL;
-   size_t secret_len=0;
+   size_t secret_len=0, secret_tmp_len=0;
    int result=0;
    tor_assert(dh);
    tor_assert(secret_bytes_out/DIGEST_LEN <= 255);
@@@ -1877,12 -1699,13 +1879,13 @@@
    if (!(pubkey_bn = BN_bin2bn((const unsigned char*)pubkey,
                                (int)pubkey_len, NULL)))
      goto error;
 -  if (tor_check_dh_key(pubkey_bn)<0) {
 +  if (tor_check_dh_key(severity, pubkey_bn)<0) {
      /* Check for invalid public keys. */
 -    log_warn(LD_CRYPTO,"Rejected invalid g^x");
 +    log_fn(severity, LD_CRYPTO,"Rejected invalid g^x");
      goto error;
    }
-   secret_tmp = tor_malloc(crypto_dh_get_bytes(dh));
+   secret_tmp_len = crypto_dh_get_bytes(dh);
+   secret_tmp = tor_malloc(secret_tmp_len);
    result = DH_compute_key((unsigned char*)secret_tmp, pubkey_bn, dh->dh);
    if (result < 0) {
      log_warn(LD_CRYPTO,"DH_compute_key() failed.");
@@@ -1901,7 -1724,10 +1904,10 @@@
    crypto_log_errors(LOG_WARN, "completing DH handshake");
    if (pubkey_bn)
      BN_free(pubkey_bn);
-   tor_free(secret_tmp);
+   if (secret_tmp) {
+     memset(secret_tmp, 0, secret_tmp_len);
+     tor_free(secret_tmp);
+   }
    if (result < 0)
      return result;
    else
@@@ -1951,8 -1777,7 +1957,8 @@@ crypto_expand_key_material(const char *
  void
  crypto_dh_free(crypto_dh_env_t *dh)
  {
 -  tor_assert(dh);
 +  if (!dh)
 +    return;
    tor_assert(dh->dh);
    DH_free(dh->dh);
    tor_free(dh);
@@@ -1977,14 -1802,6 +1983,14 @@@
      OPENSSL_VERSION_NUMBER <= 0x00907fffl) ||   \
     (OPENSSL_VERSION_NUMBER >= 0x0090803fl))
  
 +static void
 +seed_weak_rng(void)
 +{
 +  unsigned seed;
 +  crypto_rand((void*)&seed, sizeof(seed));
 +  tor_init_weak_random(seed);
 +}
 +
  /** Seed OpenSSL's random number generator with bytes from the operating
   * system.  <b>startup</b> should be true iff we have just started Tor and
   * have not yet allocated a bunch of fds.  Return 0 on success, -1 on failure.
@@@ -1992,15 -1809,14 +1998,15 @@@
  int
  crypto_seed_rng(int startup)
  {
 -  char buf[ADD_ENTROPY];
    int rand_poll_status = 0;
  
    /* local variables */
  #ifdef MS_WINDOWS
 +  unsigned char buf[ADD_ENTROPY];
    static int provider_set = 0;
    static HCRYPTPROV provider;
  #else
 +  char buf[ADD_ENTROPY];
    static const char *filenames[] = {
      "/dev/srandom", "/dev/urandom", "/dev/random", NULL
    };
@@@ -2036,7 -1852,6 +2042,7 @@@
    }
    RAND_seed(buf, sizeof(buf));
    memset(buf, 0, sizeof(buf));
 +  seed_weak_rng();
    return 0;
  #else
    for (i = 0; filenames[i]; ++i) {
@@@ -2053,7 -1868,6 +2059,7 @@@
      }
      RAND_seed(buf, (int)sizeof(buf));
      memset(buf, 0, sizeof(buf));
 +    seed_weak_rng();
      return 0;
    }
  
@@@ -2121,26 -1935,6 +2127,26 @@@ crypto_rand_uint64(uint64_t max
    }
  }
  
 +/** Return a pseudorandom double d, chosen uniformly from the range
 + * 0.0 <= d < 1.0.
 + */
 +double
 +crypto_rand_double(void)
 +{
 +  /* We just use an unsigned int here; we don't really care about getting
 +   * more than 32 bits of resolution */
 +  unsigned int uint;
 +  crypto_rand((char*)&uint, sizeof(uint));
 +#if SIZEOF_INT == 4
 +#define UINT_MAX_AS_DOUBLE 4294967296.0
 +#elif SIZEOF_INT == 8
 +#define UINT_MAX_AS_DOUBLE 1.8446744073709552e+19
 +#else
 +#error SIZEOF_INT is neither 4 nor 8
 +#endif
 +  return ((double)uint) / UINT_MAX_AS_DOUBLE;
 +}
 +
  /** Generate and return a new random hostname starting with <b>prefix</b>,
   * ending with <b>suffix</b>, and containing no less than
   * <b>min_rand_len</b> and no more than <b>max_rand_len</b> random base32
@@@ -2401,54 -2195,15 +2407,54 @@@ digest_from_base64(char *digest, const 
  #endif
  }
  
 +/** Base-64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the
 + * trailing = and newline characters, and store the nul-terminated result in
 + * the first BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>.  */
 +int
 +digest256_to_base64(char *d64, const char *digest)
 +{
 +  char buf[256];
 +  base64_encode(buf, sizeof(buf), digest, DIGEST256_LEN);
 +  buf[BASE64_DIGEST256_LEN] = '\0';
 +  memcpy(d64, buf, BASE64_DIGEST256_LEN+1);
 +  return 0;
 +}
 +
 +/** Given a base-64 encoded, nul-terminated digest in <b>d64</b> (without
 + * trailing newline or = characters), decode it and store the result in the
 + * first DIGEST256_LEN bytes at <b>digest</b>. */
 +int
 +digest256_from_base64(char *digest, const char *d64)
 +{
 +#ifdef USE_OPENSSL_BASE64
 +  char buf_in[BASE64_DIGEST256_LEN+3];
 +  char buf[256];
 +  if (strlen(d64) != BASE64_DIGEST256_LEN)
 +    return -1;
 +  memcpy(buf_in, d64, BASE64_DIGEST256_LEN);
 +  memcpy(buf_in+BASE64_DIGEST256_LEN, "=\n\0", 3);
 +  if (base64_decode(buf, sizeof(buf), buf_in, strlen(buf_in)) != DIGEST256_LEN)
 +    return -1;
 +  memcpy(digest, buf, DIGEST256_LEN);
 +  return 0;
 +#else
 +  if (base64_decode(digest, DIGEST256_LEN, d64, strlen(d64)) == DIGEST256_LEN)
 +    return 0;
 +  else
 +    return -1;
 +#endif
 +}
 +
  /** Implements base32 encoding as in rfc3548.  Limitation: Requires
   * that srclen*8 is a multiple of 5.
   */
  void
  base32_encode(char *dest, size_t destlen, const char *src, size_t srclen)
  {
 -  unsigned int i, bit, v, u;
 -  size_t nbits = srclen * 8;
 +  unsigned int i, v, u;
 +  size_t nbits = srclen * 8, bit;
  
 +  tor_assert(srclen < SIZE_T_CEILING/8);
    tor_assert((nbits%5) == 0); /* We need an even multiple of 5 bits. */
    tor_assert((nbits/5)+1 <= destlen); /* We need enough space. */
    tor_assert(destlen < SIZE_T_CEILING);
@@@ -2472,12 -2227,11 +2478,12 @@@ base32_decode(char *dest, size_t destle
  {
    /* XXXX we might want to rewrite this along the lines of base64_decode, if
     * it ever shows up in the profile. */
 -  unsigned int i, j, bit;
 -  size_t nbits;
 +  unsigned int i;
 +  size_t nbits, j, bit;
    char *tmp;
    nbits = srclen * 5;
  
 +  tor_assert(srclen < SIZE_T_CEILING / 5);
    tor_assert((nbits%8) == 0); /* We need an even multiple of 8 bits. */
    tor_assert((nbits/8) <= destlen); /* We need enough space. */
    tor_assert(destlen < SIZE_T_CEILING);
diff --combined src/or/rendclient.c
index b8526b6,9587546..1306fe0
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@@ -8,19 -8,6 +8,19 @@@
   **/
  
  #include "or.h"
 +#include "circuitbuild.h"
 +#include "circuitlist.h"
 +#include "circuituse.h"
 +#include "config.h"
 +#include "connection.h"
 +#include "connection_edge.h"
 +#include "directory.h"
 +#include "main.h"
 +#include "relay.h"
 +#include "rendclient.h"
 +#include "rendcommon.h"
 +#include "rephist.h"
 +#include "routerlist.h"
  
  /** Called when we've established a circuit to an introduction point:
   * send the introduction request. */
@@@ -76,7 -63,7 +76,7 @@@ rend_client_send_introduction(origin_ci
    rend_cache_entry_t *entry;
    crypt_path_t *cpath;
    off_t dh_offset;
 -  crypto_pk_env_t *intro_key; /* either Bob's public key or an intro key. */
 +  crypto_pk_env_t *intro_key = NULL;
  
    tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
    tor_assert(rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY);
@@@ -89,26 -76,48 +89,26 @@@
                                &entry) < 1) {
      log_warn(LD_REND,
               "query %s didn't have valid rend desc in cache. Failing.",
 -             escaped_safe_str(introcirc->rend_data->onion_address));
 +             escaped_safe_str_client(introcirc->rend_data->onion_address));
      goto err;
    }
  
 -  /* first 20 bytes of payload are the hash of Bob's pk */
 -  if (entry->parsed->version == 0) { /* un-versioned descriptor */
 -    intro_key = entry->parsed->pk;
 -  } else { /* versioned descriptor */
 -    intro_key = NULL;
 -    SMARTLIST_FOREACH(entry->parsed->intro_nodes, rend_intro_point_t *,
 -                      intro, {
 -      if (!memcmp(introcirc->build_state->chosen_exit->identity_digest,
 -                  intro->extend_info->identity_digest, DIGEST_LEN)) {
 -        intro_key = intro->intro_key;
 -        break;
 -      }
 -    });
 -    if (!intro_key) {
 -      /** XXX This case probably means that the intro point vanished while
 -       * we were building a circuit to it. In the future, we should find
 -       * out how that happened and whether we should kill the circuits to
 -       * removed intro points immediately. See task 1073. */
 -      int num_intro_points = smartlist_len(entry->parsed->intro_nodes);
 -      if (rend_cache_lookup_entry(introcirc->rend_data->onion_address,
 -          0, &entry) > 0) {
 -        log_info(LD_REND, "We have both a v0 and a v2 rend desc for this "
 -                 "service. The v2 desc doesn't contain the introduction "
 -                 "point (and key) to send an INTRODUCE1/2 cell to this "
 -                 "introduction point. Assuming the introduction point "
 -                 "is for v0 rend clients and using the service key "
 -                 "from the v0 desc instead. (This is probably a bug, "
 -                 "because we shouldn't even have both a v0 and a v2 "
 -                 "descriptor for the same service.)");
 -        /* See flyspray task 1024. */
 -        intro_key = entry->parsed->pk;
 -      } else {
 -        log_info(LD_REND, "Internal error: could not find intro key; we "
 -                 "only have a v2 rend desc with %d intro points.",
 -                 num_intro_points);
 -        goto err;
 -      }
 +  /* first 20 bytes of payload are the hash of the intro key */
 +  intro_key = NULL;
 +  SMARTLIST_FOREACH(entry->parsed->intro_nodes, rend_intro_point_t *,
 +                    intro, {
 +    if (!memcmp(introcirc->build_state->chosen_exit->identity_digest,
 +                intro->extend_info->identity_digest, DIGEST_LEN)) {
 +      intro_key = intro->intro_key;
 +      break;
      }
 +  });
 +  if (!intro_key) {
 +    log_info(LD_REND, "Our introduction point knowledge changed in "
 +             "mid-connect! Could not find intro key; we only have a "
 +             "v2 rend desc with %d intro points. Giving up.",
 +             smartlist_len(entry->parsed->intro_nodes));
 +    goto err;
    }
    if (crypto_pk_get_digest(intro_key, payload)<0) {
      log_warn(LD_BUG, "Internal error: couldn't hash public key.");
@@@ -210,7 -219,7 +210,7 @@@
    introcirc->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
  
    return 0;
 -err:
 + err:
    circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL);
    circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_REASON_INTERNAL);
    return -1;
@@@ -283,7 -292,7 +283,7 @@@ rend_client_introduction_acked(origin_c
        extend_info = rend_client_get_random_intro(circ->rend_data);
        if (!extend_info) {
          log_warn(LD_REND, "No introduction points left for %s. Closing.",
 -                 escaped_safe_str(circ->rend_data->onion_address));
 +                 escaped_safe_str_client(circ->rend_data->onion_address));
          circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
          return -1;
        }
@@@ -291,7 -300,7 +291,7 @@@
          log_info(LD_REND,
                   "Got nack for %s from %s. Re-extending circ %d, "
                   "this time to %s.",
 -                 escaped_safe_str(circ->rend_data->onion_address),
 +                 escaped_safe_str_client(circ->rend_data->onion_address),
                   circ->build_state->chosen_exit->nickname,
                   circ->_base.n_circ_id, extend_info->nickname);
          result = circuit_extend_to_new_exit(circ, extend_info);
@@@ -299,7 -308,7 +299,7 @@@
          log_info(LD_REND,
                   "Got nack for %s from %s. Building a new introduction "
                   "circuit, this time to %s.",
 -                 escaped_safe_str(circ->rend_data->onion_address),
 +                 escaped_safe_str_client(circ->rend_data->onion_address),
                   circ->build_state->chosen_exit->nickname,
                   extend_info->nickname);
          circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
@@@ -462,21 -471,45 +462,21 @@@ directory_get_from_hs_dir(const char *d
             rend_query->onion_address, desc_id_base32,
             rend_query->auth_type,
             (rend_query->auth_type == REND_NO_AUTH ? "[none]" :
 -           escaped_safe_str(descriptor_cookie_base64)),
 +           escaped_safe_str_client(descriptor_cookie_base64)),
             hs_dir->nickname, hs_dir->dir_port);
    return 1;
  }
  
 -/** If we are not currently fetching a rendezvous service descriptor
 - * for the service ID <b>query</b>, start a directory connection to fetch a
 - * new one.
 - */
 -void
 -rend_client_refetch_renddesc(const char *query)
 -{
 -  if (!get_options()->FetchHidServDescriptors)
 -    return;
 -  log_info(LD_REND, "Fetching rendezvous descriptor for service %s",
 -           escaped_safe_str(query));
 -  if (connection_get_by_type_state_rendquery(CONN_TYPE_DIR, 0, query, 0)) {
 -    log_info(LD_REND,"Would fetch a new renddesc here (for %s), but one is "
 -             "already in progress.", escaped_safe_str(query));
 -  } else {
 -    /* not one already; initiate a dir rend desc lookup */
 -    directory_get_from_dirserver(DIR_PURPOSE_FETCH_RENDDESC,
 -                                 ROUTER_PURPOSE_GENERAL, query,
 -                                 PDS_RETRY_IF_NO_SERVERS);
 -  }
 -}
 -
 -/** Start a connection to a hidden service directory to fetch a v2
 - * rendezvous service descriptor for the base32-encoded service ID
 - * <b>query</b>.
 - */
 +/** Unless we already have a descriptor for <b>rend_query</b> with at least
 + * one (possibly) working introduction point in it, start a connection to a
 + * hidden service directory to fetch a v2 rendezvous service descriptor. */
  void
  rend_client_refetch_v2_renddesc(const rend_data_t *rend_query)
  {
    char descriptor_id[DIGEST_LEN];
    int replicas_left_to_try[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS];
 -  int i, tries_left, r;
 +  int i, tries_left;
    rend_cache_entry_t *e = NULL;
 -  time_t now = time(NULL);
    tor_assert(rend_query);
    /* Are we configured to fetch descriptors? */
    if (!get_options()->FetchHidServDescriptors) {
@@@ -485,13 -518,15 +485,13 @@@
      return;
    }
    /* Before fetching, check if we already have the descriptor here. */
 -  r = rend_cache_lookup_entry(rend_query->onion_address, -1, &e);
 -  if (r > 0 && now - e->received < NUM_SECONDS_BEFORE_HS_REFETCH) {
 +  if (rend_cache_lookup_entry(rend_query->onion_address, -1, &e) > 0) {
      log_info(LD_REND, "We would fetch a v2 rendezvous descriptor, but we "
 -                      "already have a fresh copy of that descriptor here. "
 -                      "Not fetching.");
 +                      "already have that descriptor here. Not fetching.");
      return;
    }
    log_debug(LD_REND, "Fetching v2 rendezvous descriptor for service %s",
 -            safe_str(rend_query->onion_address));
 +            safe_str_client(rend_query->onion_address));
    /* Randomly iterate over the replicas until a descriptor can be fetched
     * from one of the consecutive nodes, or no options are left. */
    tries_left = REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS;
@@@ -517,8 -552,8 +517,8 @@@
    log_info(LD_REND, "Could not pick one of the responsible hidden "
                      "service directories to fetch descriptors, because "
                      "we already tried them all unsuccessfully.");
 -  /* Close pending connections (unless a v0 request is still going on). */
 -  rend_client_desc_trynow(rend_query->onion_address, 2);
 +  /* Close pending connections. */
 +  rend_client_desc_trynow(rend_query->onion_address);
    return;
  }
  
@@@ -539,13 -574,18 +539,13 @@@ rend_client_remove_intro_point(extend_i
    r = rend_cache_lookup_entry(rend_query->onion_address, -1, &ent);
    if (r<0) {
      log_warn(LD_BUG, "Malformed service ID %s.",
 -             escaped_safe_str(rend_query->onion_address));
 +             escaped_safe_str_client(rend_query->onion_address));
      return -1;
    }
    if (r==0) {
      log_info(LD_REND, "Unknown service %s. Re-fetching descriptor.",
 -             escaped_safe_str(rend_query->onion_address));
 -    /* Fetch both, v0 and v2 rend descriptors in parallel. Use whichever
 -     * arrives first. Exception: When using client authorization, only
 -     * fetch v2 descriptors.*/
 +             escaped_safe_str_client(rend_query->onion_address));
      rend_client_refetch_v2_renddesc(rend_query);
 -    if (rend_query->auth_type == REND_NO_AUTH)
 -      rend_client_refetch_renddesc(rend_query->onion_address);
      return 0;
    }
  
@@@ -562,13 -602,18 +562,13 @@@
    if (smartlist_len(ent->parsed->intro_nodes) == 0) {
      log_info(LD_REND,
               "No more intro points remain for %s. Re-fetching descriptor.",
 -             escaped_safe_str(rend_query->onion_address));
 -    /* Fetch both, v0 and v2 rend descriptors in parallel. Use whichever
 -     * arrives first. Exception: When using client authorization, only
 -     * fetch v2 descriptors.*/
 +             escaped_safe_str_client(rend_query->onion_address));
      rend_client_refetch_v2_renddesc(rend_query);
 -    if (rend_query->auth_type == REND_NO_AUTH)
 -      rend_client_refetch_renddesc(rend_query->onion_address);
  
      /* move all pending streams back to renddesc_wait */
      while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP,
                                     AP_CONN_STATE_CIRCUIT_WAIT,
 -                                   rend_query->onion_address, -1))) {
 +                                   rend_query->onion_address))) {
        conn->state = AP_CONN_STATE_RENDDESC_WAIT;
      }
  
@@@ -576,7 -621,7 +576,7 @@@
    }
    log_info(LD_REND,"%d options left for %s.",
             smartlist_len(ent->parsed->intro_nodes),
 -           escaped_safe_str(rend_query->onion_address));
 +           escaped_safe_str_client(rend_query->onion_address));
    return 1;
  }
  
@@@ -638,8 -683,7 +638,8 @@@ rend_client_receive_rendezvous(origin_c
    tor_assert(circ->build_state->pending_final_cpath);
    hop = circ->build_state->pending_final_cpath;
    tor_assert(hop->dh_handshake_state);
 -  if (crypto_dh_compute_secret(hop->dh_handshake_state, (char*)request,
 +  if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN,
 +                               hop->dh_handshake_state, (char*)request,
                                 DH_KEY_LEN,
                                 keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
      log_warn(LD_GENERAL, "Couldn't complete DH handshake.");
@@@ -673,24 -717,32 +673,26 @@@
     * attach only the connections that are waiting on this circuit, rather
     * than trying to attach them all. See comments bug 743. */
    connection_ap_attach_pending();
+   memset(keys, 0, sizeof(keys));
    return 0;
   err:
+   memset(keys, 0, sizeof(keys));
    circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
    return -1;
  }
  
 -/** Find all the apconns in state AP_CONN_STATE_RENDDESC_WAIT that
 - * are waiting on query. If there's a working cache entry here
 - * with at least one intro point, move them to the next state. If
 - * <b>rend_version</b> is non-negative, fail connections that have
 - * requested <b>query</b> unless there are still descriptor fetch
 - * requests in progress for other descriptor versions than
 - * <b>rend_version</b>.
 - */
 +/** Find all the apconns in state AP_CONN_STATE_RENDDESC_WAIT that are
 + * waiting on <b>query</b>. If there's a working cache entry here with at
 + * least one intro point, move them to the next state. */
  void
 -rend_client_desc_trynow(const char *query, int rend_version)
 +rend_client_desc_trynow(const char *query)
  {
    edge_connection_t *conn;
    rend_cache_entry_t *entry;
    time_t now = time(NULL);
  
    smartlist_t *conns = get_connection_array();
 -  SMARTLIST_FOREACH(conns, connection_t *, _conn,
 -  {
 +  SMARTLIST_FOREACH_BEGIN(conns, connection_t *, _conn) {
      if (_conn->type != CONN_TYPE_AP ||
          _conn->state != AP_CONN_STATE_RENDDESC_WAIT ||
          _conn->marked_for_close)
@@@ -722,12 -774,17 +724,12 @@@
            connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
        }
      } else { /* 404, or fetch didn't get that far */
 -      /* Unless there are requests for another descriptor version pending,
 -       * close the connection. */
 -      if (rend_version >= 0 &&
 -          !connection_get_by_type_state_rendquery(CONN_TYPE_DIR, 0, query,
 -                                                  rend_version == 0 ? 2 : 0)) {
 -        log_notice(LD_REND,"Closing stream for '%s.onion': hidden service is "
 -                   "unavailable (try again later).", safe_str(query));
 -        connection_mark_unattached_ap(conn, END_STREAM_REASON_RESOLVEFAILED);
 -      }
 +      log_notice(LD_REND,"Closing stream for '%s.onion': hidden service is "
 +                 "unavailable (try again later).",
 +                 safe_str_client(query));
 +      connection_mark_unattached_ap(conn, END_STREAM_REASON_RESOLVEFAILED);
      }
 -  });
 +  } SMARTLIST_FOREACH_END(_conn);
  }
  
  /** Return a newly allocated extend_info_t* for a randomly chosen introduction
@@@ -745,7 -802,7 +747,7 @@@ rend_client_get_random_intro(const rend
    if (rend_cache_lookup_entry(rend_query->onion_address, -1, &entry) < 1) {
      log_warn(LD_REND,
               "Query '%s' didn't have valid rend desc in cache. Failing.",
 -             safe_str(rend_query->onion_address));
 +             safe_str_client(rend_query->onion_address));
      return NULL;
    }
  
@@@ -757,10 -814,7 +759,10 @@@
    intro = smartlist_get(entry->parsed->intro_nodes, i);
    /* Do we need to look up the router or is the extend info complete? */
    if (!intro->extend_info->onion_key) {
 -    router = router_get_by_nickname(intro->extend_info->nickname, 0);
 +    if (tor_digest_is_zero(intro->extend_info->identity_digest))
 +      router = router_get_by_hexdigest(intro->extend_info->nickname);
 +    else
 +      router = router_get_by_digest(intro->extend_info->identity_digest);
      if (!router) {
        log_info(LD_REND, "Unknown router with nickname '%s'; trying another.",
                 intro->extend_info->nickname);
@@@ -898,7 -952,8 +900,7 @@@ rend_parse_service_authorization(or_opt
   err:
    res = -1;
   done:
 -  if (auth)
 -    rend_service_authorization_free(auth);
 +  rend_service_authorization_free(auth);
    SMARTLIST_FOREACH(sl, char *, c, tor_free(c););
    smartlist_free(sl);
    if (!validate_only && res == 0) {
diff --combined src/or/rendservice.c
index 1d64cf4,a650eda..f1480e0
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@@ -8,23 -8,10 +8,23 @@@
   **/
  
  #include "or.h"
 +#include "circuitbuild.h"
 +#include "circuitlist.h"
 +#include "circuituse.h"
 +#include "config.h"
 +#include "directory.h"
 +#include "networkstatus.h"
 +#include "rendclient.h"
 +#include "rendcommon.h"
 +#include "rendservice.h"
 +#include "router.h"
 +#include "relay.h"
 +#include "rephist.h"
 +#include "routerlist.h"
 +#include "routerparse.h"
  
  static origin_circuit_t *find_intro_circuit(rend_intro_point_t *intro,
 -                                            const char *pk_digest,
 -                                            int desc_version);
 +                                            const char *pk_digest);
  
  /** Represents the mapping from a virtual port of a rendezvous service to
   * a real port on some IP.
@@@ -55,6 -42,8 +55,6 @@@ typedef struct rend_service_t 
    /* Fields specified in config file */
    char *directory; /**< where in the filesystem it stores it */
    smartlist_t *ports; /**< List of rend_service_port_config_t */
 -  int descriptor_version; /**< Rendezvous descriptor version that will be
 -                           * published. */
    rend_auth_type_t auth_type; /**< Client authorization type or 0 if no client
                                 * authorization is performed. */
    smartlist_t *clients; /**< List of rend_authorized_client_t's of
@@@ -69,7 -58,7 +69,7 @@@
                               * or are trying to establish. */
    time_t intro_period_started; /**< Start of the current period to build
                                  * introduction points. */
 -  int n_intro_circuits_launched; /**< count of intro circuits we have
 +  int n_intro_circuits_launched; /**< Count of intro circuits we have
                                    * established in this period. */
    rend_service_descriptor_t *desc; /**< Current hidden service descriptor. */
    time_t desc_is_dirty; /**< Time at which changes to the hidden service
@@@ -101,8 -90,7 +101,8 @@@ num_rend_services(void
  static void
  rend_authorized_client_free(rend_authorized_client_t *client)
  {
 -  if (!client) return;
 +  if (!client)
 +    return;
    if (client->client_key)
      crypto_free_pk_env(client->client_key);
    tor_free(client->client_name);
@@@ -121,9 -109,7 +121,9 @@@ rend_authorized_client_strmap_item_free
  static void
  rend_service_free(rend_service_t *service)
  {
 -  if (!service) return;
 +  if (!service)
 +    return;
 +
    tor_free(service->directory);
    SMARTLIST_FOREACH(service->ports, void*, p, tor_free(p));
    smartlist_free(service->ports);
@@@ -134,14 -120,15 +134,14 @@@
        rend_intro_point_free(intro););
      smartlist_free(service->intro_nodes);
    }
 -  if (service->desc)
 -    rend_service_descriptor_free(service->desc);
 +
 +  rend_service_descriptor_free(service->desc);
    if (service->clients) {
      SMARTLIST_FOREACH(service->clients, rend_authorized_client_t *, c,
        rend_authorized_client_free(c););
      smartlist_free(service->clients);
    }
 -  if (service->accepted_intros)
 -    digestmap_free(service->accepted_intros, _tor_free);
 +  digestmap_free(service->accepted_intros, _tor_free);
    tor_free(service);
  }
  
@@@ -150,9 -137,9 +150,9 @@@
  void
  rend_service_free_all(void)
  {
 -  if (!rend_service_list) {
 +  if (!rend_service_list)
      return;
 -  }
 +
    SMARTLIST_FOREACH(rend_service_list, rend_service_t*, ptr,
                      rend_service_free(ptr));
    smartlist_free(rend_service_list);
@@@ -169,6 -156,36 +169,6 @@@ rend_add_service(rend_service_t *servic
  
    service->intro_nodes = smartlist_create();
  
 -  /* If the service is configured to publish unversioned (v0) and versioned
 -   * descriptors (v2 or higher), split it up into two separate services
 -   * (unless it is configured to perform client authorization). */
 -  if (service->descriptor_version == -1) {
 -    if (service->auth_type == REND_NO_AUTH) {
 -      rend_service_t *v0_service = tor_malloc_zero(sizeof(rend_service_t));
 -      v0_service->directory = tor_strdup(service->directory);
 -      v0_service->ports = smartlist_create();
 -      SMARTLIST_FOREACH(service->ports, rend_service_port_config_t *, p, {
 -        rend_service_port_config_t *copy =
 -          tor_malloc_zero(sizeof(rend_service_port_config_t));
 -        memcpy(copy, p, sizeof(rend_service_port_config_t));
 -        smartlist_add(v0_service->ports, copy);
 -      });
 -      v0_service->intro_period_started = service->intro_period_started;
 -      v0_service->descriptor_version = 0; /* Unversioned descriptor. */
 -      v0_service->auth_type = REND_NO_AUTH;
 -      rend_add_service(v0_service);
 -    }
 -
 -    service->descriptor_version = 2; /* Versioned descriptor. */
 -  }
 -
 -  if (service->auth_type != REND_NO_AUTH && !service->descriptor_version) {
 -    log_warn(LD_CONFIG, "Hidden service with client authorization and "
 -                        "version 0 descriptors configured; ignoring.");
 -    rend_service_free(service);
 -    return;
 -  }
 -
    if (service->auth_type != REND_NO_AUTH &&
        smartlist_len(service->clients) == 0) {
      log_warn(LD_CONFIG, "Hidden service with client authorization but no "
@@@ -280,7 -297,7 +280,7 @@@ rend_config_services(or_options_t *opti
  
    for (line = options->RendConfigLines; line; line = line->next) {
      if (!strcasecmp(line->key, "HiddenServiceDir")) {
 -      if (service) {
 +      if (service) { /* register the one we just finished parsing */
          if (validate_only)
            rend_service_free(service);
          else
@@@ -290,6 -307,7 +290,6 @@@
        service->directory = tor_strdup(line->value);
        service->ports = smartlist_create();
        service->intro_period_started = time(NULL);
 -      service->descriptor_version = -1; /**< All descriptor versions. */
        continue;
      }
      if (!service) {
@@@ -415,13 -433,35 +415,13 @@@
          return -1;
        }
      } else {
 -      smartlist_t *versions;
 -      char *version_str;
 -      int i, version, ver_ok=1, versions_bitmask = 0;
        tor_assert(!strcasecmp(line->key, "HiddenServiceVersion"));
 -      versions = smartlist_create();
 -      smartlist_split_string(versions, line->value, ",",
 -                             SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
 -      for (i = 0; i < smartlist_len(versions); i++) {
 -        version_str = smartlist_get(versions, i);
 -        if (strlen(version_str) != 1 || strspn(version_str, "02") != 1) {
 -          log_warn(LD_CONFIG,
 -                   "HiddenServiceVersion can only be 0 and/or 2.");
 -          SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp));
 -          smartlist_free(versions);
 -          rend_service_free(service);
 -          return -1;
 -        }
 -        version = (int)tor_parse_long(version_str, 10, 0, INT_MAX, &ver_ok,
 -                                      NULL);
 -        if (!ver_ok)
 -          continue;
 -        versions_bitmask |= 1 << version;
 +      if (strcmp(line->value, "2")) {
 +        log_warn(LD_CONFIG,
 +                 "The only supported HiddenServiceVersion is 2.");
 +        rend_service_free(service);
 +        return -1;
        }
 -      /* If exactly one version is set, change descriptor_version to that
 -       * value; otherwise leave it at -1. */
 -      if (versions_bitmask == 1 << 0) service->descriptor_version = 0;
 -      if (versions_bitmask == 1 << 2) service->descriptor_version = 2;
 -      SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp));
 -      smartlist_free(versions);
      }
    }
    if (service) {
@@@ -443,7 -483,8 +443,7 @@@
       * probably ok? */
      SMARTLIST_FOREACH(rend_service_list, rend_service_t *, new, {
        SMARTLIST_FOREACH(old_service_list, rend_service_t *, old, {
 -        if (!strcmp(old->directory, new->directory) &&
 -            old->descriptor_version == new->descriptor_version) {
 +        if (!strcmp(old->directory, new->directory)) {
            smartlist_add_all(new->intro_nodes, old->intro_nodes);
            smartlist_clear(old->intro_nodes);
            smartlist_add(surviving_services, old);
@@@ -466,16 -507,18 +466,16 @@@
          tor_assert(oc->rend_data);
          SMARTLIST_FOREACH(surviving_services, rend_service_t *, ptr, {
            if (!memcmp(ptr->pk_digest, oc->rend_data->rend_pk_digest,
 -                      DIGEST_LEN) &&
 -              ptr->descriptor_version == oc->rend_data->rend_desc_version) {
 +                      DIGEST_LEN)) {
              keep_it = 1;
              break;
            }
          });
          if (keep_it)
            continue;
 -        log_info(LD_REND, "Closing intro point %s for service %s version %d.",
 -                 safe_str(oc->build_state->chosen_exit->nickname),
 -                 oc->rend_data->onion_address,
 -                 oc->rend_data->rend_desc_version);
 +        log_info(LD_REND, "Closing intro point %s for service %s.",
 +                 safe_str_client(oc->build_state->chosen_exit->nickname),
 +                 oc->rend_data->onion_address);
          circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
          /* XXXX Is there another reason we should use here? */
        }
@@@ -498,13 -541,14 +498,13 @@@ rend_service_update_descriptor(rend_ser
    rend_service_descriptor_t *d;
    origin_circuit_t *circ;
    int i;
 -  if (service->desc) {
 -    rend_service_descriptor_free(service->desc);
 -    service->desc = NULL;
 -  }
 +
 +  rend_service_descriptor_free(service->desc);
 +  service->desc = NULL;
 +
    d = service->desc = tor_malloc_zero(sizeof(rend_service_descriptor_t));
    d->pk = crypto_pk_dup_key(service->private_key);
    d->timestamp = time(NULL);
 -  d->version = service->descriptor_version;
    d->intro_nodes = smartlist_create();
    /* Support intro protocols 2 and 3. */
    d->protocols = (1 << 2) + (1 << 3);
@@@ -512,7 -556,7 +512,7 @@@
    for (i = 0; i < smartlist_len(service->intro_nodes); ++i) {
      rend_intro_point_t *intro_svc = smartlist_get(service->intro_nodes, i);
      rend_intro_point_t *intro_desc;
 -    circ = find_intro_circuit(intro_svc, service->pk_digest, d->version);
 +    circ = find_intro_circuit(intro_svc, service->pk_digest);
      if (!circ || circ->_base.purpose != CIRCUIT_PURPOSE_S_INTRO)
        continue;
  
@@@ -753,15 -797,17 +753,15 @@@ rend_service_load_keys(void
    return r;
  }
  
 -/** Return the service whose public key has a digest of <b>digest</b> and
 - * which publishes the given descriptor <b>version</b>.  Return NULL if no
 - * such service exists.
 +/** Return the service whose public key has a digest of <b>digest</b>, or
 + * NULL if no such service exists.
   */
  static rend_service_t *
 -rend_service_get_by_pk_digest_and_version(const char* digest,
 -                                          uint8_t version)
 +rend_service_get_by_pk_digest(const char* digest)
  {
    SMARTLIST_FOREACH(rend_service_list, rend_service_t*, s,
 -                    if (!memcmp(s->pk_digest,digest,DIGEST_LEN) &&
 -                        s->descriptor_version == version) return s);
 +                    if (!memcmp(s->pk_digest,digest,DIGEST_LEN))
 +                        return s);
    return NULL;
  }
  
@@@ -898,16 -944,21 +898,16 @@@ rend_service_introduce(origin_circuit_
    }
  
    /* look up service depending on circuit. */
 -  service = rend_service_get_by_pk_digest_and_version(
 -              circuit->rend_data->rend_pk_digest,
 -              circuit->rend_data->rend_desc_version);
 +  service = rend_service_get_by_pk_digest(
 +                circuit->rend_data->rend_pk_digest);
    if (!service) {
      log_warn(LD_REND, "Got an INTRODUCE2 cell for an unrecognized service %s.",
               escaped(serviceid));
      return -1;
    }
  
 -  /* if descriptor version is 2, use intro key instead of service key. */
 -  if (circuit->rend_data->rend_desc_version == 0) {
 -    intro_key = service->private_key;
 -  } else {
 -    intro_key = circuit->intro_key;
 -  }
 +  /* use intro key instead of service key. */
 +  intro_key = circuit->intro_key;
  
    /* first DIGEST_LEN bytes of request is intro or service pk digest */
    crypto_pk_get_digest(intro_key, intro_key_digest);
@@@ -938,7 -989,7 +938,7 @@@
    len = r;
    if (*buf == 3) {
      /* Version 3 INTRODUCE2 cell. */
 -    time_t ts = 0, now = time(NULL);
 +    time_t ts = 0;
      v3_shift = 1;
      auth_type = buf[1];
      switch (auth_type) {
@@@ -1032,7 -1083,7 +1032,7 @@@
      router = router_get_by_nickname(rp_nickname, 0);
      if (!router) {
        log_info(LD_REND, "Couldn't find router %s named in introduce2 cell.",
 -               escaped_safe_str(rp_nickname));
 +               escaped_safe_str_client(rp_nickname));
        /* XXXX Add a no-such-router reason? */
        reason = END_CIRC_REASON_TORPROTOCOL;
        goto err;
@@@ -1107,8 -1158,7 +1107,8 @@@
      reason = END_CIRC_REASON_INTERNAL;
      goto err;
    }
 -  if (crypto_dh_compute_secret(dh, ptr+REND_COOKIE_LEN, DH_KEY_LEN, keys,
 +  if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh, ptr+REND_COOKIE_LEN,
 +                               DH_KEY_LEN, keys,
                                 DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) {
      log_warn(LD_BUG, "Internal error: couldn't complete DH handshake");
      reason = END_CIRC_REASON_INTERNAL;
@@@ -1118,7 -1168,7 +1118,7 @@@
    circ_needs_uptime = rend_service_requires_uptime(service);
  
    /* help predict this next time */
 -  rep_hist_note_used_internal(time(NULL), circ_needs_uptime, 1);
 +  rep_hist_note_used_internal(now, circ_needs_uptime, 1);
  
    /* Launch a circuit to alice's chosen rendezvous point.
     */
@@@ -1134,16 -1184,14 +1134,16 @@@
    if (!launched) { /* give up */
      log_warn(LD_REND, "Giving up launching first hop of circuit to rendezvous "
               "point %s for service %s.",
 -             escaped_safe_str(extend_info->nickname), serviceid);
 +             escaped_safe_str_client(extend_info->nickname),
 +             serviceid);
      reason = END_CIRC_REASON_CONNECTFAILED;
      goto err;
    }
    log_info(LD_REND,
             "Accepted intro; launching circuit to %s "
             "(cookie %s) for service %s.",
 -           escaped_safe_str(extend_info->nickname), hexcookie, serviceid);
 +           escaped_safe_str_client(extend_info->nickname),
 +           hexcookie, serviceid);
    tor_assert(launched->build_state);
    /* Fill in the circuit's state. */
    launched->rend_data = tor_malloc_zero(sizeof(rend_data_t));
@@@ -1153,10 -1201,11 +1153,10 @@@
    memcpy(launched->rend_data->rend_cookie, r_cookie, REND_COOKIE_LEN);
    strlcpy(launched->rend_data->onion_address, service->service_id,
            sizeof(launched->rend_data->onion_address));
    launched->build_state->pending_final_cpath = cpath =
      tor_malloc_zero(sizeof(crypt_path_t));
    cpath->magic = CRYPT_PATH_MAGIC;
 -  launched->build_state->expiry_time = time(NULL) + MAX_REND_TIMEOUT;
 +  launched->build_state->expiry_time = now + MAX_REND_TIMEOUT;
  
    cpath->dh_handshake_state = dh;
    dh = NULL;
@@@ -1165,8 -1214,10 +1165,10 @@@
    memcpy(cpath->handshake_digest, keys, DIGEST_LEN);
    if (extend_info) extend_info_free(extend_info);
  
+   memset(keys, 0, sizeof(keys));
    return 0;
   err:
+   memset(keys, 0, sizeof(keys));
    if (dh) crypto_dh_free(dh);
    if (launched)
      circuit_mark_for_close(TO_CIRCUIT(launched), reason);
@@@ -1238,7 -1289,7 +1240,7 @@@ rend_service_launch_establish_intro(ren
  
    log_info(LD_REND,
             "Launching circuit to introduction point %s for service %s",
 -           escaped_safe_str(intro->extend_info->nickname),
 +           escaped_safe_str_client(intro->extend_info->nickname),
             service->service_id);
  
    rep_hist_note_used_internal(time(NULL), 1, 0);
@@@ -1251,7 -1302,7 +1253,7 @@@
    if (!launched) {
      log_info(LD_REND,
               "Can't launch circuit to establish introduction at %s.",
 -             escaped_safe_str(intro->extend_info->nickname));
 +             escaped_safe_str_client(intro->extend_info->nickname));
      return -1;
    }
  
@@@ -1274,16 -1325,18 +1276,16 @@@
    strlcpy(launched->rend_data->onion_address, service->service_id,
            sizeof(launched->rend_data->onion_address));
    memcpy(launched->rend_data->rend_pk_digest, service->pk_digest, DIGEST_LEN);
 -  launched->rend_data->rend_desc_version = service->descriptor_version;
 -  if (service->descriptor_version == 2)
 -    launched->intro_key = crypto_pk_dup_key(intro->intro_key);
 +  launched->intro_key = crypto_pk_dup_key(intro->intro_key);
    if (launched->_base.state == CIRCUIT_STATE_OPEN)
      rend_service_intro_has_opened(launched);
    return 0;
  }
  
  /** Return the number of introduction points that are or have been
 - * established for the given service address and rendezvous version. */
 + * established for the given service address in <b>query</b>. */
  static int
 -count_established_intro_points(const char *query, int rend_version)
 +count_established_intro_points(const char *query)
  {
    int num_ipos = 0;
    circuit_t *circ;
@@@ -1294,6 -1347,7 +1296,6 @@@
           circ->purpose == CIRCUIT_PURPOSE_S_INTRO)) {
        origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
        if (oc->rend_data &&
 -          oc->rend_data->rend_desc_version == rend_version &&
            !rend_cmp_service_ids(query, oc->rend_data->onion_address))
          num_ipos++;
      }
@@@ -1323,8 -1377,9 +1325,8 @@@ rend_service_intro_has_opened(origin_ci
    base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
                  circuit->rend_data->rend_pk_digest, REND_SERVICE_ID_LEN);
  
 -  service = rend_service_get_by_pk_digest_and_version(
 -              circuit->rend_data->rend_pk_digest,
 -              circuit->rend_data->rend_desc_version);
 +  service = rend_service_get_by_pk_digest(
 +                circuit->rend_data->rend_pk_digest);
    if (!service) {
      log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %d.",
               serviceid, circuit->_base.n_circ_id);
@@@ -1334,7 -1389,8 +1336,7 @@@
  
    /* If we already have enough introduction circuits for this service,
     * redefine this one as a general circuit. */
 -  if (count_established_intro_points(serviceid,
 -          circuit->rend_data->rend_desc_version) > NUM_INTRO_POINTS) {
 +  if (count_established_intro_points(serviceid) > NUM_INTRO_POINTS) {
      log_info(LD_CIRC|LD_REND, "We have just finished an introduction "
               "circuit, but we already have enough. Redefining purpose to "
               "general.");
@@@ -1347,8 -1403,13 +1349,8 @@@
             "Established circuit %d as introduction point for service %s",
             circuit->_base.n_circ_id, serviceid);
  
 -  /* If the introduction point will not be used in an unversioned
 -   * descriptor, use the intro key instead of the service key in
 -   * ESTABLISH_INTRO. */
 -  if (service->descriptor_version == 0)
 -    intro_key = service->private_key;
 -  else
 -    intro_key = circuit->intro_key;
 +  /* Use the intro key instead of the service key in ESTABLISH_INTRO. */
 +  intro_key = circuit->intro_key;
    /* Build the payload for a RELAY_ESTABLISH_INTRO cell. */
    r = crypto_pk_asn1_encode(intro_key, buf+2,
                              RELAY_PAYLOAD_SIZE-2);
@@@ -1409,8 -1470,9 +1411,8 @@@ rend_service_intro_established(origin_c
      goto err;
    }
    tor_assert(circuit->rend_data);
 -  service = rend_service_get_by_pk_digest_and_version(
 -              circuit->rend_data->rend_pk_digest,
 -              circuit->rend_data->rend_desc_version);
 +  service = rend_service_get_by_pk_digest(
 +                circuit->rend_data->rend_pk_digest);
    if (!service) {
      log_warn(LD_REND, "Unknown service on introduction circuit %d.",
               circuit->_base.n_circ_id);
@@@ -1460,8 -1522,9 +1462,8 @@@ rend_service_rendezvous_has_opened(orig
             "cookie %s for service %s",
             circuit->_base.n_circ_id, hexcookie, serviceid);
  
 -  service = rend_service_get_by_pk_digest_and_version(
 -              circuit->rend_data->rend_pk_digest,
 -              circuit->rend_data->rend_desc_version);
 +  service = rend_service_get_by_pk_digest(
 +                circuit->rend_data->rend_pk_digest);
    if (!service) {
      log_warn(LD_GENERAL, "Internal error: unrecognized service ID on "
               "introduction circuit.");
@@@ -1517,12 -1580,13 +1519,12 @@@
   */
  
  /** Return the (possibly non-open) introduction circuit ending at
 - * <b>intro</b> for the service whose public key is <b>pk_digest</b> and
 - * which publishes descriptor of version <b>desc_version</b>.  Return
 - * NULL if no such service is found.
 + * <b>intro</b> for the service whose public key is <b>pk_digest</b>.
 + * (<b>desc_version</b> is ignored). Return NULL if no such service is
 + * found.
   */
  static origin_circuit_t *
 -find_intro_circuit(rend_intro_point_t *intro, const char *pk_digest,
 -                   int desc_version)
 +find_intro_circuit(rend_intro_point_t *intro, const char *pk_digest)
  {
    origin_circuit_t *circ = NULL;
  
@@@ -1531,7 -1595,8 +1533,7 @@@
                                                    CIRCUIT_PURPOSE_S_INTRO))) {
      if (!memcmp(circ->build_state->chosen_exit->identity_digest,
                  intro->extend_info->identity_digest, DIGEST_LEN) &&
 -        circ->rend_data &&
 -        circ->rend_data->rend_desc_version == desc_version) {
 +        circ->rend_data) {
        return circ;
      }
    }
@@@ -1541,7 -1606,8 +1543,7 @@@
                                          CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) {
      if (!memcmp(circ->build_state->chosen_exit->identity_digest,
                  intro->extend_info->identity_digest, DIGEST_LEN) &&
 -        circ->rend_data &&
 -        circ->rend_data->rend_desc_version == desc_version) {
 +        circ->rend_data) {
        return circ;
      }
    }
@@@ -1574,7 -1640,6 +1576,7 @@@ directory_post_to_hs_dir(rend_service_d
      }
      for (j = 0; j < smartlist_len(responsible_dirs); j++) {
        char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
 +      char *hs_dir_ip;
        hs_dir = smartlist_get(responsible_dirs, j);
        if (smartlist_digest_isin(renddesc->successful_uploads,
                                  hs_dir->identity_digest))
@@@ -1596,18 -1661,15 +1598,18 @@@
                                                strlen(desc->desc_str), 0);
        base32_encode(desc_id_base32, sizeof(desc_id_base32),
                      desc->desc_id, DIGEST_LEN);
 +      hs_dir_ip = tor_dup_ip(hs_dir->addr);
        log_info(LD_REND, "Sending publish request for v2 descriptor for "
                          "service '%s' with descriptor ID '%s' with validity "
                          "of %d seconds to hidden service directory '%s' on "
 -                        "port %d.",
 -               safe_str(service_id),
 -               safe_str(desc_id_base32),
 +                        "%s:%d.",
 +               safe_str_client(service_id),
 +               safe_str_client(desc_id_base32),
                 seconds_valid,
                 hs_dir->nickname,
 -               hs_dir->dir_port);
 +               hs_dir_ip,
 +               hs_dir->or_port);
 +      tor_free(hs_dir_ip);
        /* Remember successful upload to this router for next time. */
        if (!smartlist_digest_isin(successful_uploads, hs_dir->identity_digest))
          smartlist_add(successful_uploads, hs_dir->identity_digest);
@@@ -1637,8 -1699,9 +1639,8 @@@
    smartlist_free(successful_uploads);
  }
  
 -/** Encode and sign up-to-date v0 and/or v2 service descriptors for
 - * <b>service</b>, and upload it/them to all the dirservers/to the
 - * responsible hidden service directories.
 +/** Encode and sign an up-to-date service descriptor for <b>service</b>,
 + * and upload it/them to the responsible hidden service directories.
   */
  static void
  upload_service_descriptor(rend_service_t *service)
@@@ -1650,8 -1713,35 +1652,8 @@@
  
    rendpostperiod = get_options()->RendPostPeriod;
  
 -  /* Upload unversioned (v0) descriptor? */
 -  if (service->descriptor_version == 0 &&
 -      get_options()->PublishHidServDescriptors) {
 -    char *desc;
 -    size_t desc_len;
 -    /* Encode the descriptor. */
 -    if (rend_encode_service_descriptor(service->desc,
 -                                       service->private_key,
 -                                       &desc, &desc_len)<0) {
 -      log_warn(LD_BUG, "Internal error: couldn't encode service descriptor; "
 -               "not uploading.");
 -      return;
 -    }
 -
 -    /* Post it to the dirservers */
 -    rend_get_service_id(service->desc->pk, serviceid);
 -    log_info(LD_REND, "Sending publish request for hidden service %s",
 -             serviceid);
 -    directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_RENDDESC,
 -                                 ROUTER_PURPOSE_GENERAL,
 -                                 HIDSERV_AUTHORITY, desc, desc_len, 0);
 -    tor_free(desc);
 -    service->next_upload_time = now + rendpostperiod;
 -    uploaded = 1;
 -  }
 -
 -  /* Upload v2 descriptor? */
 -  if (service->descriptor_version == 2 &&
 -      get_options()->PublishHidServDescriptors) {
 +  /* Upload descriptor? */
 +  if (get_options()->PublishHidServDescriptors) {
      networkstatus_t *c = networkstatus_get_latest_consensus();
      if (c && smartlist_len(c->routerstatus_list) > 0) {
        int seconds_valid, i, j, num_descs;
@@@ -1790,7 -1880,8 +1792,7 @@@ rend_services_introduce(void
      for (j=0; j < smartlist_len(service->intro_nodes); ++j) {
        intro = smartlist_get(service->intro_nodes, j);
        router = router_get_by_digest(intro->extend_info->identity_digest);
 -      if (!router || !find_intro_circuit(intro, service->pk_digest,
 -                                         service->descriptor_version)) {
 +      if (!router || !find_intro_circuit(intro, service->pk_digest)) {
          log_info(LD_REND,"Giving up on %s as intro point for %s.",
                   intro->extend_info->nickname, service->service_id);
          if (service->desc) {
@@@ -1842,7 -1933,7 +1844,7 @@@
        router_crn_flags_t flags = CRN_NEED_UPTIME;
        if (get_options()->_AllowInvalid & ALLOW_INVALID_INTRODUCTION)
          flags |= CRN_ALLOW_INVALID;
 -      router = router_choose_random_node(NULL, intro_routers,
 +      router = router_choose_random_node(intro_routers,
                                           options->ExcludeNodes, flags);
        if (!router) {
          log_warn(LD_REND,
@@@ -1854,8 -1945,10 +1856,8 @@@
        smartlist_add(intro_routers, router);
        intro = tor_malloc_zero(sizeof(rend_intro_point_t));
        intro->extend_info = extend_info_from_router(router);
 -      if (service->descriptor_version == 2) {
 -        intro->intro_key = crypto_new_pk_env();
 -        tor_assert(!crypto_pk_generate_key(intro->intro_key));
 -      }
 +      intro->intro_key = crypto_new_pk_env();
 +      tor_assert(!crypto_pk_generate_key(intro->intro_key));
        smartlist_add(service->intro_nodes, intro);
        log_info(LD_REND, "Picked router %s as an intro point for %s.",
                 router->nickname, service->service_id);
@@@ -1948,7 -2041,8 +1950,7 @@@ rend_consider_descriptor_republication(
  
    for (i=0; i < smartlist_len(rend_service_list); ++i) {
      service = smartlist_get(rend_service_list, i);
 -    if (service->descriptor_version && service->desc &&
 -        !service->desc->all_uploads_performed) {
 +    if (service->desc && !service->desc->all_uploads_performed) {
        /* If we failed in uploading a descriptor last time, try again *without*
         * updating the descriptor's contents. */
        upload_service_descriptor(service);
@@@ -1974,9 -2068,10 +1976,9 @@@ rend_service_dump_stats(int severity
          service->directory);
      for (j=0; j < smartlist_len(service->intro_nodes); ++j) {
        intro = smartlist_get(service->intro_nodes, j);
 -      safe_name = safe_str(intro->extend_info->nickname);
 +      safe_name = safe_str_client(intro->extend_info->nickname);
  
 -      circ = find_intro_circuit(intro, service->pk_digest,
 -                                service->descriptor_version);
 +      circ = find_intro_circuit(intro, service->pk_digest);
        if (!circ) {
          log(severity, LD_GENERAL, "  Intro point %d at %s: no circuit",
              j, safe_name);
@@@ -2007,8 -2102,9 +2009,8 @@@ rend_service_set_connection_addr_port(e
    log_debug(LD_REND,"beginning to hunt for addr/port");
    base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
                  circ->rend_data->rend_pk_digest, REND_SERVICE_ID_LEN);
 -  service = rend_service_get_by_pk_digest_and_version(
 -                circ->rend_data->rend_pk_digest,
 -                circ->rend_data->rend_desc_version);
 +  service = rend_service_get_by_pk_digest(
 +                circ->rend_data->rend_pk_digest);
    if (!service) {
      log_warn(LD_REND, "Couldn't find any service associated with pk %s on "
               "rendezvous circuit %d; closing.",