Commit 90fcfade authored by Roger Dingledine's avatar Roger Dingledine
Browse files

revert r12841 and r12842, and commit karsten's "patch 13"


svn:r12900
parent e710710e
Loading
Loading
Loading
Loading
+11 −15
Original line number Diff line number Diff line
@@ -3598,6 +3598,13 @@ typedef struct rend_encoded_v2_service_descriptor_t {
  char *desc_str; /**< Descriptor string. */
} rend_encoded_v2_service_descriptor_t;

/** Introduction point information. */
typedef struct rend_intro_point_t {
  extend_info_t *extend_info; /**< Extend info of this introduction point. */
  crypto_pk_env_t *intro_key; /**< Introduction key that replaces the service
                               * key, if this descriptor is V2. */
} rend_intro_point_t;

/** Information used to connect to a hidden service. */
typedef struct rend_service_descriptor_t {
  crypto_pk_env_t *pk; /**< This service's public key. */
@@ -3605,21 +3612,9 @@ typedef struct rend_service_descriptor_t {
  time_t timestamp; /**< Time when the descriptor was generated. */
  uint16_t protocols; /**< Bitmask: which rendezvous protocols are supported?
                       * (We allow bits '0', '1', and '2' to be set.) */
  int n_intro_points; /**< Number of introduction points. */
  /** Array of n_intro_points elements for this service's introduction points'
   * nicknames.  Elements are removed from this array if introduction attempts
   * fail. */
  char **intro_points;
  /** Array of n_intro_points elements for this service's introduction points'
   * extend_infos, or NULL if this descriptor is V0.  Elements are removed
   * from this array if introduction attempts fail.  If this array is present,
   * its elements correspond to the elements of intro_points. */
  extend_info_t **intro_point_extend_info;
  strmap_t *intro_keys; /**< map from intro node hexdigest to key; only
                         * used for versioned hidden service descriptors. */

  /* XXXX020 Refactor n_intro_points, intro_points, intro_point_extend_info,
   * and intro_keys into a list of intro points. */
  /** List of the service's introduction points.  Elements are removed if
   * introduction attempts fail. */
  smartlist_t *intro_nodes;
} rend_service_descriptor_t;

int rend_cmp_service_ids(const char *one, const char *two);
@@ -3637,6 +3632,7 @@ rend_service_descriptor_t *rend_parse_service_descriptor(const char *str,
int rend_get_service_id(crypto_pk_env_t *pk, char *out);
void rend_encoded_v2_service_descriptor_free(
                               rend_encoded_v2_service_descriptor_t *desc);
void rend_intro_point_free(rend_intro_point_t *intro);

/** A cached rendezvous descriptor. */
typedef struct rend_cache_entry_t {
+34 −48
Original line number Diff line number Diff line
@@ -82,12 +82,15 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
  if (entry->parsed->version == 0) { /* unversioned descriptor */
    intro_key = entry->parsed->pk;
  } else { /* versioned descriptor */
    char hex_digest[HEX_DIGEST_LEN+2];
    hex_digest[0] = '$';
    base16_encode(hex_digest+1, HEX_DIGEST_LEN+1,
                  introcirc->build_state->chosen_exit->identity_digest,
                  DIGEST_LEN);
    intro_key = strmap_get(entry->parsed->intro_keys, hex_digest);
    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_warn(LD_BUG, "Internal error: could not find intro key.");
      goto err;
@@ -342,35 +345,17 @@ rend_client_remove_intro_point(extend_info_t *failed_intro, const char *query)
    return 0;
  }

  if (ent->parsed->intro_point_extend_info) {
    for (i=0; i < ent->parsed->n_intro_points; ++i) {
  for (i = 0; i < smartlist_len(ent->parsed->intro_nodes); i++) {
    rend_intro_point_t *intro = smartlist_get(ent->parsed->intro_nodes, i);
    if (!memcmp(failed_intro->identity_digest,
                  ent->parsed->intro_point_extend_info[i]->identity_digest,
                  DIGEST_LEN)) {
        tor_assert(!strcmp(ent->parsed->intro_points[i],
                           ent->parsed->intro_point_extend_info[i]->nickname));
        tor_free(ent->parsed->intro_points[i]);
        extend_info_free(ent->parsed->intro_point_extend_info[i]);
        --ent->parsed->n_intro_points;
        ent->parsed->intro_points[i] =
          ent->parsed->intro_points[ent->parsed->n_intro_points];
        ent->parsed->intro_point_extend_info[i] =
          ent->parsed->intro_point_extend_info[ent->parsed->n_intro_points];
        break;
      }
    }
  } else {
    for (i=0; i < ent->parsed->n_intro_points; ++i) {
      if (!strcasecmp(ent->parsed->intro_points[i], failed_intro->nickname)) {
        tor_free(ent->parsed->intro_points[i]);
        ent->parsed->intro_points[i] =
          ent->parsed->intro_points[--ent->parsed->n_intro_points];
                intro->extend_info->identity_digest, DIGEST_LEN)) {
      rend_intro_point_free(intro);
      smartlist_del(ent->parsed->intro_nodes, i);
      break;
    }
  }
  }

  if (!ent->parsed->n_intro_points) {
  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(query));
@@ -388,7 +373,7 @@ rend_client_remove_intro_point(extend_info_t *failed_intro, const char *query)
    return 0;
  }
  log_info(LD_REND,"%d options left for %s.",
           ent->parsed->n_intro_points, escaped_safe_str(query));
           smartlist_len(ent->parsed->intro_nodes), escaped_safe_str(query));
  return 1;
}

@@ -503,7 +488,7 @@ rend_client_desc_here(const char *query)
      continue;
    assert_connection_ok(TO_CONN(conn), now);
    if (rend_cache_lookup_entry(conn->rend_query, -1, &entry) == 1 &&
        entry->parsed->n_intro_points > 0) {
        smartlist_len(entry->parsed->intro_nodes) > 0) {
      /* either this fetch worked, or it failed but there was a
       * valid entry from before which we should reuse */
      log_info(LD_REND,"Rend desc is usable. Launching circuits.");
@@ -537,6 +522,8 @@ rend_client_get_random_intro(const char *query)
{
  int i;
  rend_cache_entry_t *entry;
  rend_intro_point_t *intro;
  routerinfo_t *router;

  if (rend_cache_lookup_entry(query, -1, &entry) < 1) {
    log_warn(LD_REND,
@@ -546,26 +533,25 @@ rend_client_get_random_intro(const char *query)
  }

 again:
  if (!entry->parsed->n_intro_points)
  if (smartlist_len(entry->parsed->intro_nodes) == 0)
    return NULL;

  i = crypto_rand_int(entry->parsed->n_intro_points);

  if (entry->parsed->intro_point_extend_info) {
    return extend_info_dup(entry->parsed->intro_point_extend_info[i]);
  } else {
    /* add the intro point nicknames */
    char *choice = entry->parsed->intro_points[i];
    routerinfo_t *router = router_get_by_nickname(choice, 0);
  i = crypto_rand_int(smartlist_len(entry->parsed->intro_nodes));
  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 (!router) {
      log_info(LD_REND, "Unknown router with nickname '%s'; trying another.",
               choice);
      tor_free(choice);
      entry->parsed->intro_points[i] =
        entry->parsed->intro_points[--entry->parsed->n_intro_points];
               intro->extend_info->nickname);
      rend_intro_point_free(intro);
      smartlist_del(entry->parsed->intro_nodes, i);
      goto again;
    }
    return extend_info_from_router(router);
    extend_info_free(intro->extend_info);
    intro = tor_malloc_zero(sizeof(rend_intro_point_t));
    intro->extend_info = extend_info_from_router(router);
  }
  return extend_info_dup(intro->extend_info);
}
+51 −57
Original line number Diff line number Diff line
@@ -20,41 +20,17 @@ rend_cmp_service_ids(const char *one, const char *two)
  return strcasecmp(one,two);
}

/** Helper: Release the storage held by the intro key in <b>_ent</b>.
 */
/*XXXX020 there's also one of these in rendservice.c */
/* Right. But the only alternative to that (which I know) would be to
 * write it to or.h. Should I do that? -KL */
static void
intro_key_free(void *_ent)
{
  crypto_pk_env_t *ent = _ent;
  crypto_free_pk_env(ent);
}

/** Free the storage held by the service descriptor <b>desc</b>.
 */
void
rend_service_descriptor_free(rend_service_descriptor_t *desc)
{
  int i;
  if (desc->pk)
    crypto_free_pk_env(desc->pk);
  if (desc->intro_points) {
    for (i=0; i < desc->n_intro_points; ++i) {
      tor_free(desc->intro_points[i]);
    }
    tor_free(desc->intro_points);
  }
  if (desc->intro_point_extend_info) {
    for (i=0; i < desc->n_intro_points; ++i) {
      if (desc->intro_point_extend_info[i])
        extend_info_free(desc->intro_point_extend_info[i]);
    }
    tor_free(desc->intro_point_extend_info);
  }
  if (desc->intro_keys) {
    strmap_free(desc->intro_keys, intro_key_free);
  if (desc->intro_nodes) {
    SMARTLIST_FOREACH(desc->intro_nodes, rend_intro_point_t *, intro,
      rend_intro_point_free(intro););
    smartlist_free(desc->intro_nodes);
  }
  tor_free(desc);
}
@@ -191,9 +167,9 @@ rend_encode_v2_intro_points(char **ipos_base64,
  int r = -1;
  /* Assemble unencrypted list of introduction points. */
  *ipos_base64 = NULL;
  unenc_len = desc->n_intro_points * 1000; /* too long, but ok. */
  unenc_len = smartlist_len(desc->intro_nodes) * 1000; /* too long, but ok. */
  unenc = tor_malloc_zero(unenc_len);
  for (i = 0; i < desc->n_intro_points; i++) {
  for (i = 0; i < smartlist_len(desc->intro_nodes); i++) {
    char id_base32[REND_INTRO_POINT_ID_LEN_BASE32 + 1];
    char *onion_key = NULL;
    size_t onion_key_len;
@@ -202,9 +178,9 @@ rend_encode_v2_intro_points(char **ipos_base64,
    char *address = NULL;
    size_t service_key_len;
    int res;
    char hex_digest[HEX_DIGEST_LEN+2]; /* includes $ and NUL. */
    rend_intro_point_t *intro = smartlist_get(desc->intro_nodes, i);
    /* Obtain extend info with introduction point details. */
    extend_info_t *info = desc->intro_point_extend_info[i];
    extend_info_t *info = intro->extend_info;
    /* Encode introduction point ID. */
    base32_encode(id_base32, sizeof(id_base32),
                  info->identity_digest, DIGEST_LEN);
@@ -215,11 +191,7 @@ rend_encode_v2_intro_points(char **ipos_base64,
      goto done;
    }
    /* Encode intro key. */
    hex_digest[0] = '$';
    base16_encode(hex_digest+1, HEX_DIGEST_LEN+1,
                  info->identity_digest,
                  DIGEST_LEN);
    intro_key = strmap_get(desc->intro_keys, hex_digest);
    intro_key = intro->intro_key;
    if (!intro_key ||
      crypto_pk_write_public_key_to_string(intro_key, &service_key,
                                           &service_key_len) < 0) {
@@ -324,6 +296,17 @@ rend_encoded_v2_service_descriptor_free(
  tor_free(desc);
}

/** Free the storage held by an introduction point info. */
void
rend_intro_point_free(rend_intro_point_t *intro)
{
  if (intro->extend_info)
    extend_info_free(intro->extend_info);
  if (intro->intro_key)
    crypto_free_pk_env(intro->intro_key);
  tor_free(intro);
}

/** Encode a set of rend_encoded_v2_service_descriptor_t's for <b>desc</b>
 * at time <b>now</b> using <b>descriptor_cookie</b> (may be <b>NULL</b> if
 * introduction points shall not be encrypted) and <b>period</b> (e.g. 0
@@ -353,7 +336,7 @@ rend_encode_v2_descriptors(smartlist_t *descs_out,
  seconds_valid = period * REND_TIME_PERIOD_V2_DESC_VALIDITY +
                  get_seconds_valid(now, service_id);
  /* Assemble, possibly encrypt, and encode introduction points. */
  if (desc->n_intro_points > 0 &&
  if (smartlist_len(desc->intro_nodes) > 0 &&
      rend_encode_v2_intro_points(&ipos_base64, desc, descriptor_cookie) < 0) {
    log_warn(LD_REND, "Encoding of introduction points did not succeed.");
    return -1;
@@ -408,7 +391,8 @@ rend_encode_v2_descriptors(smartlist_t *descs_out,
    else
      protocol_versions_string[0]= '\0';
    /* Assemble complete descriptor. */
    desc_len = 2000 + desc->n_intro_points * 1000; /* far too long, but ok. */
    desc_len = 2000 + smartlist_len(desc->intro_nodes) * 1000; /* far too long,
                                                                  but okay.*/
    enc->desc_str = desc_str = tor_malloc_zero(desc_len);
    result = tor_snprintf(desc_str, desc_len,
             "rendezvous-service-descriptor %s\n"
@@ -503,18 +487,24 @@ rend_encode_service_descriptor(rend_service_descriptor_t *desc,
  char *end;
  int i;
  size_t asn1len;
  size_t buflen = PK_BYTES*2*(desc->n_intro_points+2);/*Too long, but ok*/
  size_t buflen =
         PK_BYTES*2*(smartlist_len(desc->intro_nodes)+2);/*Too long, but ok*/
  cp = *str_out = tor_malloc(buflen);
  end = cp + PK_BYTES*2*(desc->n_intro_points+1);
  end = cp + PK_BYTES*2*(smartlist_len(desc->intro_nodes)+1);
  asn1len = crypto_pk_asn1_encode(desc->pk, cp+2, end-(cp+2));
  set_uint16(cp, htons((uint16_t)asn1len));
  cp += 2+asn1len;
  set_uint32(cp, htonl((uint32_t)desc->timestamp));
  cp += 4;
  set_uint16(cp, htons((uint16_t)desc->n_intro_points));
  set_uint16(cp, htons((uint16_t)smartlist_len(desc->intro_nodes)));
  cp += 2;
  for (i=0; i < desc->n_intro_points; ++i) {
    char *ipoint = (char*)desc->intro_points[i];
  for (i=0; i < smartlist_len(desc->intro_nodes); ++i) {
    rend_intro_point_t *intro = smartlist_get(desc->intro_nodes, i);
    char ipoint[HEX_DIGEST_LEN+2];
    ipoint[0] = '$';
    base16_encode(ipoint+1, HEX_DIGEST_LEN+1,
                  intro->extend_info->identity_digest,
                  DIGEST_LEN);
    strlcpy(cp, ipoint, buflen-(cp-*str_out));
    cp += strlen(ipoint)+1;
  }
@@ -537,9 +527,10 @@ rend_service_descriptor_t *
rend_parse_service_descriptor(const char *str, size_t len)
{
  rend_service_descriptor_t *result = NULL;
  int i;
  int i, n_intro_points;
  size_t keylen, asn1len;
  const char *end, *cp, *eos;
  rend_intro_point_t *intro;

  result = tor_malloc_zero(sizeof(rend_service_descriptor_t));
  cp = str;
@@ -558,20 +549,23 @@ rend_parse_service_descriptor(const char *str, size_t len)
  cp += 4;
  result->protocols = 1<<2; /* always use intro format 2 */
  if (end-cp < 2) goto truncated;
  result->n_intro_points = ntohs(get_uint16(cp));
  n_intro_points = ntohs(get_uint16(cp));
  cp += 2;

  if (result->n_intro_points != 0) {
    result->intro_points =
      tor_malloc_zero(sizeof(char*)*result->n_intro_points);
    for (i=0;i<result->n_intro_points;++i) {
  result->intro_nodes = smartlist_create();
  for (i=0;i<n_intro_points;++i) {
    if (end-cp < 2) goto truncated;
    eos = (const char *)memchr(cp,'\0',end-cp);
    if (!eos) goto truncated;
      result->intro_points[i] = tor_strdup(cp);
    /* Write nickname to extend info, but postpone the lookup whether
     * we know that router. It's not part of the parsing process. */
    intro = tor_malloc_zero(sizeof(rend_intro_point_t));
    intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
    strlcpy(intro->extend_info->nickname, cp,
            sizeof(intro->extend_info->nickname));
    smartlist_add(result->intro_nodes, intro);
    cp = eos+1;
  }
  }
  keylen = crypto_pk_keysize(result->pk);
  tor_assert(end-cp >= 0);
  if ((size_t)(end-cp) < keylen) goto truncated;
@@ -1091,7 +1085,7 @@ rend_cache_store_v2_desc_as_client(const char *desc,
      return -1;
    }
  } else {
    parsed->n_intro_points = 0;
    parsed->intro_nodes = smartlist_create();
  }
  /* We don't need the encoded/encrypted introduction points any longer. */
  tor_free(intro_content);
+62 −106

File changed.

Preview size limit exceeded, changes collapsed.

+17 −41
Original line number Diff line number Diff line
@@ -862,8 +862,8 @@ check_signature_token(const char *digest,
    tor_free(signed_digest);
    return -1;
  }
  log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
            hex_str(signed_digest,4));
//  log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
//            hex_str(signed_digest,4));
  if (memcmp(digest, signed_digest, DIGEST_LEN)) {
    log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
    tor_free(signed_digest);
@@ -3384,14 +3384,15 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed,
{
  char *ipos_decrypted = NULL;
  const char **current_ipo;
  smartlist_t *intropoints;
  smartlist_t *tokens;
  int i;
  directory_token_t *tok;
  rend_intro_point_t *intro;
  extend_info_t *info;
  struct in_addr ip;
  int result;
  tor_assert(parsed);
  /** Function may only be invoked once. */
  tor_assert(!parsed->intro_nodes);
  tor_assert(intro_points_encrypted);
  tor_assert(intro_points_encrypted_size > 0);
  /* Decrypt introduction points, if required. */
@@ -3413,15 +3414,9 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed,
    intro_points_encrypted_size = unenclen;
  }
  /* Consider one intro point after the other. */
  current_ipo = &intro_points_encrypted;
  intropoints = smartlist_create();
  current_ipo = (const char **)&intro_points_encrypted;
  tokens = smartlist_create();
  if (parsed->intro_keys) {
    log_warn(LD_BUG, "Parsing list of introduction points for the same "
             "hidden service, twice.");
  } else {
    parsed->intro_keys = strmap_new();
  }
  parsed->intro_nodes = smartlist_create();
  while (!strcmpstart(*current_ipo, "introduction-point ")) {
    /* Determine end of string. */
    const char *eos = strstr(*current_ipo, "\nintroduction-point ");
@@ -3444,8 +3439,9 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed,
      log_warn(LD_REND, "Impossibly short introduction point.");
      goto err;
    }
    /* Allocate new extend info. */
    info = tor_malloc_zero(sizeof(extend_info_t));
    /* Allocate new intro point and extend info. */
    intro = tor_malloc_zero(sizeof(rend_intro_point_t));
    info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
    /* Parse identifier. */
    tok = find_first_by_keyword(tokens, R_IPO_IDENTIFIER);
    tor_assert(tok);
@@ -3453,7 +3449,7 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed,
                      tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) {
      log_warn(LD_REND, "Identity digest contains illegal characters: %s",
               tok->args[0]);
      tor_free(info);
      rend_intro_point_free(intro);
      goto err;
    }
    /* Write identifier to nickname. */
@@ -3464,7 +3460,7 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed,
    tok = find_first_by_keyword(tokens, R_IPO_IP_ADDRESS);
    if (tor_inet_aton(tok->args[0], &ip) == 0) {
      log_warn(LD_REND, "Could not parse IP address.");
      tor_free(info);
      rend_intro_point_free(intro);
      goto err;
    }
    info->addr = ntohl(ip.s_addr);
@@ -3477,7 +3473,7 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed,
    if (!info->port) {
      log_warn(LD_REND, "Introduction point onion port is out of range: %d",
               info->port);
      tor_free(info);
      rend_intro_point_free(intro);
      goto err;
    }
    /* Parse onion key. */
@@ -3486,30 +3482,12 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed,
    tok->key = NULL; /* Prevent free */
    /* Parse service key. */
    tok = find_first_by_keyword(tokens, R_IPO_SERVICE_KEY);
    strmap_set(parsed->intro_keys, info->nickname, tok->key);
    intro->intro_key = tok->key;
    tok->key = NULL; /* Prevent free */
    /* Add extend info to list of introduction points. */
    smartlist_add(intropoints, info);
    /* XXX if intropoints has items on it, but we goto err the next
     * time through the loop, we don't free the items in the 'err'
     * section below. -RD */
  }
  /* Write extend infos to descriptor. */
  /* XXXX020 what if intro_points (&tc) are already set? */
  /* This function is not intended to be invoced multiple times for
   * the same descriptor. Should this be asserted? -KL */
  /* Yes. -NM */
  parsed->n_intro_points = smartlist_len(intropoints);
  parsed->intro_point_extend_info =
    tor_malloc_zero(sizeof(extend_info_t *) * parsed->n_intro_points);
  parsed->intro_points =
    tor_malloc_zero(sizeof(char *) * parsed->n_intro_points);
  i = 0;
  SMARTLIST_FOREACH(intropoints, extend_info_t *, ipo, {
      parsed->intro_points[i] = tor_strdup(ipo->nickname);
      parsed->intro_point_extend_info[i++] = ipo;
  });
  result = parsed->n_intro_points;
    smartlist_add(parsed->intro_nodes, intro);
  }
  result = smartlist_len(parsed->intro_nodes);
  goto done;

 err:
@@ -3520,8 +3498,6 @@ rend_decrypt_introduction_points(rend_service_descriptor_t *parsed,
  SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
  smartlist_free(tokens);

  smartlist_free(intropoints);

  return result;
}
Loading