Commit a65cea38 authored by Nick Mathewson's avatar Nick Mathewson 🐘
Browse files

r13936@catbus: nickm | 2007-07-27 12:23:26 -0400

 Code to implement detached signature documents.


svn:r10944
parent 35561a54
Loading
Loading
Loading
Loading
+119 −18
Changes for src/or/dirvote.c: 119 added lines, 18 removed lines.
Original line number Diff line number Diff line
@@ -754,32 +754,21 @@ networkstatus_check_consensus_signature(networkstatus_vote_t *consensus)
}

/** DOCDOC */
int
networkstatus_add_consensus_signatures(networkstatus_vote_t *target,
                                       networkstatus_vote_t *src,
static int
networkstatus_add_signatures_impl(networkstatus_vote_t *target,
                                  smartlist_t *src_voter_list,
                                  char **new_signatures_out)
{
  smartlist_t *added_signatures, *sigs;
  int r;
  tor_assert(target);
  tor_assert(src);
  tor_assert(!target->is_vote);
  tor_assert(! src->is_vote);
  tor_assert(new_signatures_out);

  *new_signatures_out = NULL;

  /* Are they the same consensus? */
  if (memcmp(target->networkstatus_digest, src->networkstatus_digest,
             DIGEST_LEN))
    return -1;
  if (target == src)
    return 0;

  added_signatures = smartlist_create();

  /* For each voter in src... */
  SMARTLIST_FOREACH(src->voters, networkstatus_voter_info_t *, src_voter,
  SMARTLIST_FOREACH(src_voter_list, networkstatus_voter_info_t *, src_voter,
    {
      networkstatus_voter_info_t *target_voter =
        networkstatus_get_voter_by_id(target, src_voter->identity_digest);
@@ -793,12 +782,14 @@ networkstatus_add_consensus_signatures(networkstatus_vote_t *target,
      if (target_voter->good_signature)
        continue;

      /* If this signature is no good, then skip. */
      /* Try checking the signature if we haven't already. */
      if (!src_voter->good_signature && !src_voter->bad_signature) {
        cert = authority_cert_get_by_digests(src_voter->identity_digest,
                                             src_voter->signing_key_digest);
        if (cert) {
          networkstatus_check_voter_signature(target, src_voter, cert);
        }
      }
      /* If this signature is good, then replace and add. */
      if (src_voter->good_signature || !target_voter->signature) {
        tor_free(target_voter->signature);
@@ -824,10 +815,10 @@ networkstatus_add_consensus_signatures(networkstatus_vote_t *target,
      base16_encode(sk, sizeof(sk), v->signing_key_digest, DIGEST_LEN);
      base16_encode(ik, sizeof(ik), v->identity_digest, DIGEST_LEN);
      tor_snprintf(buf, sizeof(buf), "directory-signature %s %s\n"
                   "-----BEGIN SIGNATURE-----", ik, sk);
                   "-----BEGIN SIGNATURE-----\n", ik, sk);
      smartlist_add(sigs, tor_strdup(buf));
      base64_encode(buf, sizeof(buf), v->signature, v->signature_len);
      strlcat(buf, "-----END SIGNATURE-----", sizeof(buf));
      strlcat(buf, "-----END SIGNATURE-----\n", sizeof(buf));
      smartlist_add(sigs, tor_strdup(buf));
    });

@@ -839,6 +830,116 @@ networkstatus_add_consensus_signatures(networkstatus_vote_t *target,
  return r;
}

/** DOCDOC */
int
networkstatus_add_consensus_signatures(networkstatus_vote_t *target,
                                       networkstatus_vote_t *src,
                                       char **new_signatures_out)
{
  tor_assert(src);
  tor_assert(! src->is_vote);

  *new_signatures_out = NULL;

  /* Are they the same consensus? */
  if (memcmp(target->networkstatus_digest, src->networkstatus_digest,
             DIGEST_LEN))
    return -1;
  if (target == src)
    return 0;

  return networkstatus_add_signatures_impl(target, src->voters,
                                           new_signatures_out);
}

/** DOCDOC */
int
networkstatus_add_detached_signatures(networkstatus_vote_t *target,
                                      ns_detached_signatures_t *sigs,
                                      char **new_signatures_out)
{
  tor_assert(sigs);

  *new_signatures_out = NULL;

  /* Are they the same consensus? */
  if (memcmp(target->networkstatus_digest, sigs->networkstatus_digest,
             DIGEST_LEN))
    return -1;

  return networkstatus_add_signatures_impl(target, sigs->signatures,
                                           new_signatures_out);
}

/** DOCDOC */
char *
networkstatus_get_detached_signatures(networkstatus_vote_t *consensus)
{
  smartlist_t *elements;
  char buf[4096];
  char *result = NULL;
  tor_assert(consensus);
  tor_assert(! consensus->is_vote);

  elements = smartlist_create();

  {
    char va_buf[ISO_TIME_LEN+1], fu_buf[ISO_TIME_LEN+1],
      vu_buf[ISO_TIME_LEN+1];
    char d[HEX_DIGEST_LEN+1];

    base16_encode(d, sizeof(d), consensus->networkstatus_digest, DIGEST_LEN);
    format_iso_time(va_buf, consensus->valid_after);
    format_iso_time(fu_buf, consensus->fresh_until);
    format_iso_time(vu_buf, consensus->valid_until);

    tor_snprintf(buf, sizeof(buf),
                 "consensus-digest %s\n"
                 "valid-after %s\n"
                 "fresh-until %s\n"
                 "valid-until %s\n", d, va_buf, fu_buf, vu_buf);
    smartlist_add(elements, tor_strdup(buf));
  }

  SMARTLIST_FOREACH(consensus->voters, networkstatus_voter_info_t *, v,
    {
      char sk[HEX_DIGEST_LEN+1];
      char id[HEX_DIGEST_LEN+1];
      if (!v->signature || !v->good_signature)
        continue;
      base16_encode(sk, sizeof(sk), v->signing_key_digest, DIGEST_LEN);
      base16_encode(id, sizeof(id), v->identity_digest, DIGEST_LEN);
      tor_snprintf(buf, sizeof(buf),
                   "directory-signature %s %s\n-----BEGIN SIGNATURE-----\n",
                   id, sk);
      smartlist_add(elements, tor_strdup(buf));
      base64_encode(buf, sizeof(buf), v->signature, v->signature_len);
      strlcat(buf, "-----END SIGNATURE-----\n", sizeof(buf));
      smartlist_add(elements, tor_strdup(buf));
    });

  result = smartlist_join_strings(elements, "", 0, NULL);

  SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
  smartlist_free(elements);
  return result;
}

/** DOCDOC */
void
ns_detached_signatures_free(ns_detached_signatures_t *s)
{
  if (s->signatures) {
    SMARTLIST_FOREACH(s->signatures, networkstatus_voter_info_t *, v,
      {
        tor_free(v->signature);
        tor_free(v);
      });
    smartlist_free(s->signatures);
  }
  tor_free(s);
}

/* =====
 * Certificate functions
 * ===== */
+17 −0
Changes for src/or/or.h: 17 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -1361,6 +1361,16 @@ typedef struct networkstatus_vote_t {
                                   * otherwise just routerstatus_t. */
} networkstatus_vote_t;

/* XXXX020 merge with networkstatus_vote_t ?? */
/** DOCDOC */
typedef struct ns_detached_signatures_t {
  time_t valid_after;
  time_t fresh_until;
  time_t valid_until;
  char networkstatus_digest[DIGEST_LEN];
  smartlist_t *signatures; /* list of networkstatus_voter_info_t */
} ns_detached_signatures_t;

/** Contents of a directory of onion routers. */
typedef struct {
  /** Map from server identity digest to a member of routers. */
@@ -2796,6 +2806,11 @@ int networkstatus_check_consensus_signature(networkstatus_vote_t *consensus);
int networkstatus_add_consensus_signatures(networkstatus_vote_t *target,
                                           networkstatus_vote_t *src,
                                           char **new_signatures_out);
int networkstatus_add_detached_signatures(networkstatus_vote_t *target,
                                          ns_detached_signatures_t *sigs,
                                          char **new_signatures_out);
char *networkstatus_get_detached_signatures(networkstatus_vote_t *consensus);
void ns_detached_signatures_free(ns_detached_signatures_t *s);

/* cert manipulation */
void authority_cert_free(authority_cert_t *cert);
@@ -3505,6 +3520,8 @@ void dump_distinct_digest_count(int severity);
networkstatus_t *networkstatus_parse_from_string(const char *s);
networkstatus_vote_t *networkstatus_parse_vote_from_string(const char *s,
                                                           int is_vote);
ns_detached_signatures_t *networkstatus_parse_detached_signatures(
                                          const char *s, const char *eos);

authority_cert_t *authority_cert_parse_from_string(const char *s,
                                                   const char **end_of_string);
+101 −2
Changes for src/or/routerparse.c: 101 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -340,6 +340,15 @@ static token_rule_t networkstatus_vote_footer_token_table[] = {
  END_OF_TABLE
};

static token_rule_t networkstatus_detached_signature_token_table[] = {
  T1_START("consensus-digest", K_CONSENSUS_DIGEST, GE(1),       NO_OBJ ),
  T1("valid-after",            K_VALID_AFTER,      CONCAT_ARGS, NO_OBJ ),
  T1("fresh-until",            K_FRESH_UNTIL,      CONCAT_ARGS, NO_OBJ ),
  T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
  T( "directory-signature", K_DIRECTORY_SIGNATURE, GE(2),   NEED_OBJ ),
  END_OF_TABLE
};

#undef T

/* static function prototypes */
@@ -2058,8 +2067,7 @@ networkstatus_parse_vote_from_string(const char *s, int is_vote)
        goto err;
      v->good_signature = 1;
    } else {
      v->signature = tor_memdup(tok->object_body,
                                        tok->object_size);
      v->signature = tor_memdup(tok->object_body, tok->object_size);
      v->signature_len = tok->object_size;
    }
  });
@@ -2095,6 +2103,97 @@ networkstatus_parse_vote_from_string(const char *s, int is_vote)
  return ns;
}

/** DOCDOC */
ns_detached_signatures_t *
networkstatus_parse_detached_signatures(const char *s, const char *eos)
{
  /* XXXX020 there is too much duplicate code here. */
  directory_token_t *tok;

  smartlist_t *tokens = smartlist_create();
  ns_detached_signatures_t *sigs =
    tor_malloc_zero(sizeof(ns_detached_signatures_t));

  if (!eos)
    eos = s + strlen(s);

  if (tokenize_string(s, eos, tokens,
                      networkstatus_detached_signature_token_table)) {
    log_warn(LD_DIR, "Error tokenizing detached networkstatus signatures");
    goto err;
  }

  tok = find_first_by_keyword(tokens, K_CONSENSUS_DIGEST);
  if (strlen(tok->args[0]) != HEX_DIGEST_LEN)
    goto err;
  if (base16_decode(sigs->networkstatus_digest, DIGEST_LEN,
                    tok->args[0], strlen(tok->args[0])) < 0)
    goto err;

  tok = find_first_by_keyword(tokens, K_VALID_AFTER);
  if (parse_iso_time(tok->args[0], &sigs->valid_after))
    goto err;

  tok = find_first_by_keyword(tokens, K_FRESH_UNTIL);
  if (parse_iso_time(tok->args[0], &sigs->fresh_until))
    goto err;

  tok = find_first_by_keyword(tokens, K_VALID_UNTIL);
  if (parse_iso_time(tok->args[0], &sigs->valid_until))
    goto err;

  sigs->signatures = smartlist_create();
  SMARTLIST_FOREACH(tokens, directory_token_t *, _tok,
    {
      char id_digest[DIGEST_LEN];
      char sk_digest[DIGEST_LEN];
      networkstatus_voter_info_t *voter;

      tok = _tok;
      if (tok->tp != K_DIRECTORY_SIGNATURE)
        continue;
      tor_assert(tok->n_args >= 2);

      if (!tok->object_type ||
          strcmp(tok->object_type, "SIGNATURE") ||
          tok->object_size < 128 || tok->object_size > 512) {
        log_warn(LD_DIR, "Bad object type or length on directory-signature");
        goto err;
      }

      if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
          base16_decode(id_digest, sizeof(id_digest),
                        tok->args[0], HEX_DIGEST_LEN) < 0) {
        log_warn(LD_DIR, "Error decoding declared identity %s in "
                 "network-status vote.", escaped(tok->args[0]));
        goto err;
      }
      if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
          base16_decode(sk_digest, sizeof(sk_digest),
                        tok->args[1], HEX_DIGEST_LEN) < 0) {
        log_warn(LD_DIR, "Error decoding declared identity %s in "
                 "network-status vote.", escaped(tok->args[1]));
        goto err;
      }

      voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
      memcpy(voter->identity_digest, id_digest, DIGEST_LEN);
      memcpy(voter->signing_key_digest, sk_digest, DIGEST_LEN);
      voter->signature = tor_memdup(tok->object_body, tok->object_size);
      voter->signature_len = tok->object_size;

      smartlist_add(sigs->signatures, voter);
    });

  goto done;
 err:
  ns_detached_signatures_free(sigs);
  sigs = NULL;
 done:
  SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
  return NULL;
}

/** Parse the addr policy in the string <b>s</b> and return it.  If
 * assume_action is nonnegative, then insert its action (ADDR_POLICY_ACCEPT or
 * ADDR_POLICY_REJECT) for items that specify no action.