commit 81deddb08c6b8bf644f663dcdc31720e365f68dc
Merge: 9f3f537 9ad4776
Author: Nick Mathewson <ni...@torproject.org>
Date:   Thu Nov 8 16:48:04 2012 -0500

    Merge remote-tracking branch 'origin/maint-0.2.3'
    
    Conflicts:
        src/common/crypto.c
        src/or/rendservice.c

 changes/bug7352          |   12 +++++++
 src/common/aes.c         |    4 +-
 src/common/compat.c      |    2 +-
 src/common/crypto.c      |   81 +++++++++++++++++++++++++++++++++++-----------
 src/common/crypto.h      |    3 ++
 src/common/mempool.c     |    3 +-
 src/common/tortls.c      |    4 +-
 src/common/util.c        |    2 +-
 src/or/buffers.c         |    6 ++--
 src/or/circuitlist.c     |    8 ++--
 src/or/connection.c      |    2 +-
 src/or/connection_edge.c |    4 +-
 src/or/connection_or.c   |    8 ++--
 src/or/networkstatus.c   |    2 +-
 src/or/onion.c           |   24 +++++++-------
 src/or/rendclient.c      |    4 +-
 src/or/rendservice.c     |   14 ++++----
 src/or/routerparse.c     |    2 +-
 src/tools/tor-gencert.c  |    6 ++--
 19 files changed, 125 insertions(+), 66 deletions(-)

diff --cc src/or/circuitlist.c
index 32a478d,93ba69d..abb8395
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@@ -680,9 -655,9 +680,9 @@@ circuit_free(circuit_t *circ
  
    /* Clear cell queue _after_ removing it from the map.  Otherwise our
     * "active" checks will be violated. */
 -  cell_queue_clear(&circ->n_conn_cells);
 +  cell_queue_clear(&circ->n_chan_cells);
  
-   memset(mem, 0xAA, memlen); /* poison memory */
+   memwipe(mem, 0xAA, memlen); /* poison memory */
    tor_free(mem);
  }
  
diff --cc src/or/rendservice.c
index fe0333e,d235f08..b13992a
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@@ -1383,570 -1402,16 +1383,570 @@@ rend_service_introduce(origin_circuit_
    if (circuit_init_cpath_crypto(cpath,keys+DIGEST_LEN,1)<0)
      goto err;
    memcpy(cpath->handshake_digest, keys, DIGEST_LEN);
 -  if (extend_info) extend_info_free(extend_info);
  
 -  memwipe(keys, 0, sizeof(keys));
 -  return 0;
 +  goto done;
 +
 + log_error:
 +  if (!err_msg) {
 +    if (stage_descr) {
 +      tor_asprintf(&err_msg,
 +                   "unknown %s error for INTRODUCE2", stage_descr);
 +    } else {
 +      err_msg = tor_strdup("unknown error for INTRODUCE2");
 +    }
 +  }
 +
 +  log_warn(LD_REND, "%s on circ %d", err_msg, circuit->base_.n_circ_id);
   err:
 -  memwipe(keys, 0, sizeof(keys));
 +  status = -1;
    if (dh) crypto_dh_free(dh);
 -  if (launched)
 +  if (launched) {
      circuit_mark_for_close(TO_CIRCUIT(launched), reason);
 -  if (extend_info) extend_info_free(extend_info);
 +  }
 +  tor_free(err_msg);
 +
 + done:
-   memset(keys, 0, sizeof(keys));
-   memset(buf, 0, sizeof(buf));
-   memset(serviceid, 0, sizeof(serviceid));
-   memset(hexcookie, 0, sizeof(hexcookie));
-   memset(intro_key_digest, 0, sizeof(intro_key_digest));
-   memset(auth_data, 0, sizeof(auth_data));
-   memset(diffie_hellman_hash, 0, sizeof(diffie_hellman_hash));
++  memwipe(keys, 0, sizeof(keys));
++  memwipe(buf, 0, sizeof(buf));
++  memwipe(serviceid, 0, sizeof(serviceid));
++  memwipe(hexcookie, 0, sizeof(hexcookie));
++  memwipe(intro_key_digest, 0, sizeof(intro_key_digest));
++  memwipe(auth_data, 0, sizeof(auth_data));
++  memwipe(diffie_hellman_hash, 0, sizeof(diffie_hellman_hash));
 +
 +  /* Free the parsed cell */
 +  if (parsed_req) {
 +    rend_service_free_intro(parsed_req);
 +    parsed_req = NULL;
 +  }
 +
 +  /* Free rp if we must */
 +  if (need_rp_free) extend_info_free(rp);
 +
 +  return status;
 +}
 +
 +/** Given a parsed and decrypted INTRODUCE2, find the rendezvous point or
 + * return NULL and an error string if we can't.
 + */
 +
 +static extend_info_t *
 +find_rp_for_intro(const rend_intro_cell_t *intro,
 +                  uint8_t *need_free_out, char **err_msg_out)
 +{
 +  extend_info_t *rp = NULL;
 +  char *err_msg = NULL;
 +  const char *rp_nickname = NULL;
 +  const node_t *node = NULL;
 +  uint8_t need_free = 0;
 +
 +  if (!intro || !need_free_out) {
 +    if (err_msg_out)
 +      err_msg = tor_strdup("Bad parameters to find_rp_for_intro()");
 +
 +    goto err;
 +  }
 +
 +  if (intro->version == 0 || intro->version == 1) {
 +    if (intro->version == 1) rp_nickname = (const char *)(intro->u.v1.rp);
 +    else rp_nickname = (const char *)(intro->u.v0.rp);
 +
 +    node = node_get_by_nickname(rp_nickname, 0);
 +    if (!node) {
 +      if (err_msg_out) {
 +        tor_asprintf(&err_msg,
 +                     "Couldn't find router %s named in INTRODUCE2 cell",
 +                     escaped_safe_str_client(rp_nickname));
 +      }
 +
 +      goto err;
 +    }
 +
 +    rp = extend_info_from_node(node, 0);
 +    if (!rp) {
 +      if (err_msg_out) {
 +        tor_asprintf(&err_msg,
 +                     "Could build extend_info_t for router %s named "
 +                     "in INTRODUCE2 cell",
 +                     escaped_safe_str_client(rp_nickname));
 +      }
 +
 +      goto err;
 +    } else {
 +      need_free = 1;
 +    }
 +  } else if (intro->version == 2) {
 +    rp = intro->u.v2.extend_info;
 +  } else if (intro->version == 3) {
 +    rp = intro->u.v3.extend_info;
 +  } else {
 +    if (err_msg_out) {
 +      tor_asprintf(&err_msg,
 +                   "Unknown version %d in INTRODUCE2 cell",
 +                   (int)(intro->version));
 +    }
 +
 +    goto err;
 +  }
 +
 +  goto done;
 +
 + err:
 +  if (err_msg_out) *err_msg_out = err_msg;
 +  else tor_free(err_msg);
 +
 + done:
 +  if (rp && need_free_out) *need_free_out = need_free;
 +
 +  return rp;
 +}
 +
 +/** Remove unnecessary parts from a rend_intro_cell_t - the ciphertext if
 + * already decrypted, the plaintext too if already parsed
 + */
 +
 +void
 +rend_service_compact_intro(rend_intro_cell_t *request)
 +{
 +  if (!request) return;
 +
 +  if ((request->plaintext && request->plaintext_len > 0) ||
 +       request->parsed) {
 +    tor_free(request->ciphertext);
 +    request->ciphertext_len = 0;
 +  }
 +
 +  if (request->parsed) {
 +    tor_free(request->plaintext);
 +    request->plaintext_len = 0;
 +  }
 +}
 +
 +/** Free a parsed INTRODUCE1 or INTRODUCE2 cell that was allocated by
 + * rend_service_parse_intro().
 + */
 +void
 +rend_service_free_intro(rend_intro_cell_t *request)
 +{
 +  if (!request) {
 +    log_info(LD_BUG, "rend_service_free_intro() called with NULL request!");
 +    return;
 +  }
 +
 +  /* Free ciphertext */
 +  tor_free(request->ciphertext);
 +  request->ciphertext_len = 0;
 +
 +  /* Have plaintext? */
 +  if (request->plaintext) {
 +    /* Zero it out just to be safe */
 +    memset(request->plaintext, 0, request->plaintext_len);
 +    tor_free(request->plaintext);
 +    request->plaintext_len = 0;
 +  }
 +
 +  /* Have parsed plaintext? */
 +  if (request->parsed) {
 +    switch (request->version) {
 +      case 0:
 +      case 1:
 +        /*
 +         * Nothing more to do; these formats have no further pointers
 +         * in them.
 +         */
 +        break;
 +      case 2:
 +        extend_info_free(request->u.v2.extend_info);
 +        request->u.v2.extend_info = NULL;
 +        break;
 +      case 3:
 +        if (request->u.v3.auth_data) {
 +          memset(request->u.v3.auth_data, 0, request->u.v3.auth_len);
 +          tor_free(request->u.v3.auth_data);
 +        }
 +
 +        extend_info_free(request->u.v3.extend_info);
 +        request->u.v3.extend_info = NULL;
 +        break;
 +      default:
 +        log_info(LD_BUG,
 +                 "rend_service_free_intro() saw unknown protocol "
 +                 "version %d.",
 +                 request->version);
 +    }
 +  }
 +
 +  /* Zero it out to make sure sensitive stuff doesn't hang around in memory */
 +  memset(request, 0, sizeof(*request));
 +
 +  tor_free(request);
 +}
 +
 +/** Parse an INTRODUCE1 or INTRODUCE2 cell into a newly allocated
 + * rend_intro_cell_t structure.  Free it with rend_service_free_intro()
 + * when finished.  The type parameter should be 1 or 2 to indicate whether
 + * this is INTRODUCE1 or INTRODUCE2.  This parses only the non-encrypted
 + * parts; after this, call rend_service_decrypt_intro() with a key, then
 + * rend_service_parse_intro_plaintext() to finish parsing.  The optional
 + * err_msg_out parameter is set to a string suitable for log output
 + * if parsing fails.  This function does some validation, but only
 + * that which depends solely on the contents of the cell and the
 + * key; it can be unit-tested.  Further validation is done in
 + * rend_service_validate_intro().
 + */
 +
 +rend_intro_cell_t *
 +rend_service_begin_parse_intro(const uint8_t *request,
 +                               size_t request_len,
 +                               uint8_t type,
 +                               char **err_msg_out)
 +{
 +  rend_intro_cell_t *rv = NULL;
 +  char *err_msg = NULL;
 +
 +  if (!request || request_len <= 0) goto err;
 +  if (!(type == 1 || type == 2)) goto err;
 +
 +  /* First, check that the cell is long enough to be a sensible INTRODUCE */
 +
 +  /* min key length plus digest length plus nickname length */
 +  if (request_len <
 +        (DIGEST_LEN + REND_COOKIE_LEN + (MAX_NICKNAME_LEN + 1) +
 +         DH_KEY_LEN + 42)) {
 +    if (err_msg_out) {
 +      tor_asprintf(&err_msg,
 +                   "got a truncated INTRODUCE%d cell",
 +                   (int)type);
 +    }
 +    goto err;
 +  }
 +
 +  /* Allocate a new parsed cell structure */
 +  rv = tor_malloc_zero(sizeof(*rv));
 +
 +  /* Set the type */
 +  rv->type = type;
 +
 +  /* Copy in the ID */
 +  memcpy(rv->pk, request, DIGEST_LEN);
 +
 +  /* Copy in the ciphertext */
 +  rv->ciphertext = tor_malloc(request_len - DIGEST_LEN);
 +  memcpy(rv->ciphertext, request + DIGEST_LEN, request_len - DIGEST_LEN);
 +  rv->ciphertext_len = request_len - DIGEST_LEN;
 +
 +  goto done;
 +
 + err:
 +  if (rv) rend_service_free_intro(rv);
 +  rv = NULL;
 +  if (err_msg_out && !err_msg) {
 +    tor_asprintf(&err_msg,
 +                 "unknown INTRODUCE%d error",
 +                 (int)type);
 +  }
 +
 + done:
 +  if (err_msg_out) *err_msg_out = err_msg;
 +  else tor_free(err_msg);
 +
 +  return rv;
 +}
 +
 +/** Parse the version-specific parts of a v0 or v1 INTRODUCE1 or INTRODUCE2
 + * cell
 + */
 +
 +static ssize_t
 +rend_service_parse_intro_for_v0_or_v1(
 +    rend_intro_cell_t *intro,
 +    const uint8_t *buf,
 +    size_t plaintext_len,
 +    char **err_msg_out)
 +{
 +  const char *rp_nickname, *endptr;
 +  size_t nickname_field_len, ver_specific_len;
 +
 +  if (intro->version == 1) {
 +    ver_specific_len = MAX_HEX_NICKNAME_LEN + 2;
 +    rp_nickname = ((const char *)buf) + 1;
 +    nickname_field_len = MAX_HEX_NICKNAME_LEN + 1;
 +  } else if (intro->version == 0) {
 +    ver_specific_len = MAX_NICKNAME_LEN + 1;
 +    rp_nickname = (const char *)buf;
 +    nickname_field_len = MAX_NICKNAME_LEN + 1;
 +  } else {
 +    if (err_msg_out)
 +      tor_asprintf(err_msg_out,
 +                   "rend_service_parse_intro_for_v0_or_v1() called with "
 +                   "bad version %d on INTRODUCE%d cell (this is a bug)",
 +                   intro->version,
 +                   (int)(intro->type));
 +    goto err;
 +  }
 +
 +  if (plaintext_len < ver_specific_len) {
 +    if (err_msg_out)
 +      tor_asprintf(err_msg_out,
 +                   "short plaintext of encrypted part in v1 INTRODUCE%d "
 +                   "cell (%lu bytes, needed %lu)",
 +                   (int)(intro->type),
 +                   (unsigned long)plaintext_len,
 +                   (unsigned long)ver_specific_len);
 +    goto err;
 +  }
 +
 +  endptr = memchr(rp_nickname, 0, nickname_field_len);
 +  if (!endptr || endptr == rp_nickname) {
 +    if (err_msg_out) {
 +      tor_asprintf(err_msg_out,
 +                   "couldn't find a nul-padded nickname in "
 +                   "INTRODUCE%d cell",
 +                   (int)(intro->type));
 +    }
 +    goto err;
 +  }
 +
 +  if ((intro->version == 0 &&
 +       !is_legal_nickname(rp_nickname)) ||
 +      (intro->version == 1 &&
 +       !is_legal_nickname_or_hexdigest(rp_nickname))) {
 +    if (err_msg_out) {
 +      tor_asprintf(err_msg_out,
 +                   "bad nickname in INTRODUCE%d cell",
 +                   (int)(intro->type));
 +    }
 +    goto err;
 +  }
 +
 +  if (intro->version == 1) {
 +    memcpy(intro->u.v1.rp, rp_nickname, endptr - rp_nickname + 1);
 +  } else {
 +    memcpy(intro->u.v0.rp, rp_nickname, endptr - rp_nickname + 1);
 +  }
 +
 +  return ver_specific_len;
 +
 + err:
 +  return -1;
 +}
 +
 +/** Parse the version-specific parts of a v2 INTRODUCE1 or INTRODUCE2 cell
 + */
 +
 +static ssize_t
 +rend_service_parse_intro_for_v2(
 +    rend_intro_cell_t *intro,
 +    const uint8_t *buf,
 +    size_t plaintext_len,
 +    char **err_msg_out)
 +{
 +  unsigned int klen;
 +  extend_info_t *extend_info = NULL;
 +  ssize_t ver_specific_len;
 +
 +  /*
 +   * We accept version 3 too so that the v3 parser can call this with
 +   * and adjusted buffer for the latter part of a v3 cell, which is
 +   * identical to a v2 cell.
 +   */
 +  if (!(intro->version == 2 ||
 +        intro->version == 3)) {
 +    if (err_msg_out)
 +      tor_asprintf(err_msg_out,
 +                   "rend_service_parse_intro_for_v2() called with "
 +                   "bad version %d on INTRODUCE%d cell (this is a bug)",
 +                   intro->version,
 +                   (int)(intro->type));
 +    goto err;
 +  }
 +
 +  /* 7 == version, IP and port, DIGEST_LEN == id, 2 == key length */
 +  if (plaintext_len < 7 + DIGEST_LEN + 2) {
 +    if (err_msg_out) {
 +      tor_asprintf(err_msg_out,
 +                   "truncated plaintext of encrypted parted of "
 +                   "version %d INTRODUCE%d cell",
 +                   intro->version,
 +                   (int)(intro->type));
 +    }
 +
 +    goto err;
 +  }
 +
 +  extend_info = tor_malloc_zero(sizeof(extend_info_t));
 +  tor_addr_from_ipv4n(&extend_info->addr, get_uint32(buf + 1));
 +  extend_info->port = ntohs(get_uint16(buf + 5));
 +  memcpy(extend_info->identity_digest, buf + 7, DIGEST_LEN);
 +  extend_info->nickname[0] = '$';
 +  base16_encode(extend_info->nickname + 1, sizeof(extend_info->nickname) - 1,
 +                extend_info->identity_digest, DIGEST_LEN);
 +  klen = ntohs(get_uint16(buf + 7 + DIGEST_LEN));
 +
 +  /* 7 == version, IP and port, DIGEST_LEN == id, 2 == key length */
 +  if (plaintext_len < 7 + DIGEST_LEN + 2 + klen) {
 +    if (err_msg_out) {
 +      tor_asprintf(err_msg_out,
 +                   "truncated plaintext of encrypted parted of "
 +                   "version %d INTRODUCE%d cell",
 +                   intro->version,
 +                   (int)(intro->type));
 +    }
 +
 +    goto err;
 +  }
 +
 +  extend_info->onion_key =
 +    crypto_pk_asn1_decode((const char *)(buf + 7 + DIGEST_LEN + 2), klen);
 +  if (!extend_info->onion_key) {
 +    if (err_msg_out) {
 +      tor_asprintf(err_msg_out,
 +                   "error decoding onion key in version %d "
 +                   "INTRODUCE%d cell",
 +                   intro->version,
 +                   (intro->type));
 +    }
 +
 +    goto err;
 +  }
 +
 +  ver_specific_len = 7+DIGEST_LEN+2+klen;
 +
 +  if (intro->version == 2) intro->u.v2.extend_info = extend_info;
 +  else intro->u.v3.extend_info = extend_info;
 +
 +  return ver_specific_len;
 +
 + err:
 +  extend_info_free(extend_info);
 +
 +  return -1;
 +}
 +
 +/** Parse the version-specific parts of a v3 INTRODUCE1 or INTRODUCE2 cell
 + */
 +
 +static ssize_t
 +rend_service_parse_intro_for_v3(
 +    rend_intro_cell_t *intro,
 +    const uint8_t *buf,
 +    size_t plaintext_len,
 +    char **err_msg_out)
 +{
 +  ssize_t adjust, v2_ver_specific_len, ts_offset;
 +
 +  /* This should only be called on v3 cells */
 +  if (intro->version != 3) {
 +    if (err_msg_out)
 +      tor_asprintf(err_msg_out,
 +                   "rend_service_parse_intro_for_v3() called with "
 +                   "bad version %d on INTRODUCE%d cell (this is a bug)",
 +                   intro->version,
 +                   (int)(intro->type));
 +    goto err;
 +  }
 +
 +  /*
 +   * Check that we have at least enough to get auth_len:
 +   *
 +   * 1 octet for version, 1 for auth_type, 2 for auth_len
 +   */
 +  if (plaintext_len < 4) {
 +    if (err_msg_out) {
 +      tor_asprintf(err_msg_out,
 +                   "truncated plaintext of encrypted parted of "
 +                   "version %d INTRODUCE%d cell",
 +                   intro->version,
 +                   (int)(intro->type));
 +    }
 +
 +    goto err;
 +  }
 +
 +  /*
 +   * The rend_client_send_introduction() function over in rendclient.c is
 +   * broken (i.e., fails to match the spec) in such a way that we can't
 +   * change it without breaking the protocol.  Specifically, it doesn't
 +   * emit auth_len when auth-type is REND_NO_AUTH, so everything is off
 +   * by two bytes after that.  Calculate ts_offset and do everything from
 +   * the timestamp on relative to that to handle this dain bramage.
 +   */
 +
 +  intro->u.v3.auth_type = buf[1];
 +  if (intro->u.v3.auth_type != REND_NO_AUTH) {
 +    intro->u.v3.auth_len = ntohs(get_uint16(buf + 2));
 +    ts_offset = 4 + intro->u.v3.auth_len;
 +  } else {
 +    intro->u.v3.auth_len = 0;
 +    ts_offset = 2;
 +  }
 +
 +  /* Check that auth len makes sense for this auth type */
 +  if (intro->u.v3.auth_type == REND_BASIC_AUTH ||
 +      intro->u.v3.auth_type == REND_STEALTH_AUTH) {
 +      if (intro->u.v3.auth_len != REND_DESC_COOKIE_LEN) {
 +        if (err_msg_out) {
 +          tor_asprintf(err_msg_out,
 +                       "wrong auth data size %d for INTRODUCE%d cell, "
 +                       "should be %d",
 +                       (int)(intro->u.v3.auth_len),
 +                       (int)(intro->type),
 +                       REND_DESC_COOKIE_LEN);
 +        }
 +
 +        goto err;
 +      }
 +  }
 +
 +  /* Check that we actually have everything up to the timestamp */
 +  if (plaintext_len < (size_t)(ts_offset)) {
 +    if (err_msg_out) {
 +      tor_asprintf(err_msg_out,
 +                   "truncated plaintext of encrypted parted of "
 +                   "version %d INTRODUCE%d cell",
 +                   intro->version,
 +                   (int)(intro->type));
 +    }
 +
 +    goto err;
 +  }
 +
 +  if (intro->u.v3.auth_type != REND_NO_AUTH &&
 +      intro->u.v3.auth_len > 0) {
 +    /* Okay, we can go ahead and copy auth_data */
 +    intro->u.v3.auth_data = tor_malloc(intro->u.v3.auth_len);
 +    /*
 +     * We know we had an auth_len field in this case, so 4 is
 +     * always right.
 +     */
 +    memcpy(intro->u.v3.auth_data, buf + 4, intro->u.v3.auth_len);
 +  }
 +
 +  /*
 +   * Apparently we don't use the timestamp any more, but might as well copy
 +   * over just in case we ever care about it.
 +   */
 +  intro->u.v3.timestamp = ntohl(get_uint32(buf + ts_offset));
 +
 +  /*
 +   * From here on, the format is as in v2, so we call the v2 parser with
 +   * adjusted buffer and length.  We are 4 + ts_offset octets in, but the
 +   * v2 parser expects to skip over a version byte at the start, so we
 +   * adjust by 3 + ts_offset.
 +   */
 +  adjust = 3 + ts_offset;
 +
 +  v2_ver_specific_len =
 +    rend_service_parse_intro_for_v2(intro,
 +                                    buf + adjust, plaintext_len - adjust,
 +                                    err_msg_out);
 +
 +  /* Success in v2 parser */
 +  if (v2_ver_specific_len >= 0) return v2_ver_specific_len + adjust;
 +  /* Failure in v2 parser; it will have provided an err_msg */
 +  else return v2_ver_specific_len;
 +
 + err:
    return -1;
  }
  



_______________________________________________
tor-commits mailing list
tor-commits@lists.torproject.org
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits

Reply via email to