"Fossies" - the Fresh Open Source Software Archive

Member "tor-0.4.1.6/src/feature/dirauth/dsigs_parse.c" (10 Jun 2019, 9304 Bytes) of package /linux/misc/tor-0.4.1.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dsigs_parse.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.4.0.5_vs_0.4.1.5.

    1 /* Copyright (c) 2001 Matej Pfajfar.
    2  * Copyright (c) 2001-2004, Roger Dingledine.
    3  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
    4  * Copyright (c) 2007-2019, The Tor Project, Inc. */
    5 /* See LICENSE for licensing information */
    6 
    7 /**
    8  * \file dsigs_parse.h
    9  * \brief Code to parse and validate detached-signature objects
   10  **/
   11 
   12 #include "core/or/or.h"
   13 #include "feature/dirparse/parsecommon.h"
   14 #include "feature/dirparse/unparseable.h"
   15 #include "feature/nodelist/networkstatus.h"
   16 #include "lib/memarea/memarea.h"
   17 
   18 #include "feature/dirauth/dsigs_parse.h"
   19 #include "feature/dirauth/ns_detached_signatures_st.h"
   20 #include "feature/nodelist/document_signature_st.h"
   21 
   22 /** List of tokens recognized in detached networkstatus signature documents. */
   23 static token_rule_t networkstatus_detached_signature_token_table[] = {
   24   T1_START("consensus-digest", K_CONSENSUS_DIGEST, GE(1),       NO_OBJ ),
   25   T("additional-digest",       K_ADDITIONAL_DIGEST,GE(3),       NO_OBJ ),
   26   T1("valid-after",            K_VALID_AFTER,      CONCAT_ARGS, NO_OBJ ),
   27   T1("fresh-until",            K_FRESH_UNTIL,      CONCAT_ARGS, NO_OBJ ),
   28   T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
   29   T("additional-signature",  K_ADDITIONAL_SIGNATURE, GE(4),   NEED_OBJ ),
   30   T1N("directory-signature", K_DIRECTORY_SIGNATURE,  GE(2),   NEED_OBJ ),
   31   END_OF_TABLE
   32 };
   33 
   34 /** Return the common_digests_t that holds the digests of the
   35  * <b>flavor_name</b>-flavored networkstatus according to the detached
   36  * signatures document <b>sigs</b>, allocating a new common_digests_t as
   37  * needed. */
   38 static common_digests_t *
   39 detached_get_digests(ns_detached_signatures_t *sigs, const char *flavor_name)
   40 {
   41   common_digests_t *d = strmap_get(sigs->digests, flavor_name);
   42   if (!d) {
   43     d = tor_malloc_zero(sizeof(common_digests_t));
   44     strmap_set(sigs->digests, flavor_name, d);
   45   }
   46   return d;
   47 }
   48 
   49 /** Return the list of signatures of the <b>flavor_name</b>-flavored
   50  * networkstatus according to the detached signatures document <b>sigs</b>,
   51  * allocating a new common_digests_t as needed. */
   52 static smartlist_t *
   53 detached_get_signatures(ns_detached_signatures_t *sigs,
   54                         const char *flavor_name)
   55 {
   56   smartlist_t *sl = strmap_get(sigs->signatures, flavor_name);
   57   if (!sl) {
   58     sl = smartlist_new();
   59     strmap_set(sigs->signatures, flavor_name, sl);
   60   }
   61   return sl;
   62 }
   63 
   64 /** Parse a detached v3 networkstatus signature document between <b>s</b> and
   65  * <b>eos</b> and return the result.  Return -1 on failure. */
   66 ns_detached_signatures_t *
   67 networkstatus_parse_detached_signatures(const char *s, const char *eos)
   68 {
   69   /* XXXX there is too much duplicate shared between this function and
   70    * networkstatus_parse_vote_from_string(). */
   71   directory_token_t *tok;
   72   memarea_t *area = NULL;
   73   common_digests_t *digests;
   74 
   75   smartlist_t *tokens = smartlist_new();
   76   ns_detached_signatures_t *sigs =
   77     tor_malloc_zero(sizeof(ns_detached_signatures_t));
   78   sigs->digests = strmap_new();
   79   sigs->signatures = strmap_new();
   80 
   81   if (!eos)
   82     eos = s + strlen(s);
   83 
   84   area = memarea_new();
   85   if (tokenize_string(area,s, eos, tokens,
   86                       networkstatus_detached_signature_token_table, 0)) {
   87     log_warn(LD_DIR, "Error tokenizing detached networkstatus signatures");
   88     goto err;
   89   }
   90 
   91   /* Grab all the digest-like tokens. */
   92   SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) {
   93     const char *algname;
   94     digest_algorithm_t alg;
   95     const char *flavor;
   96     const char *hexdigest;
   97     size_t expected_length, digest_length;
   98 
   99     tok = _tok;
  100 
  101     if (tok->tp == K_CONSENSUS_DIGEST) {
  102       algname = "sha1";
  103       alg = DIGEST_SHA1;
  104       flavor = "ns";
  105       hexdigest = tok->args[0];
  106     } else if (tok->tp == K_ADDITIONAL_DIGEST) {
  107       int a = crypto_digest_algorithm_parse_name(tok->args[1]);
  108       if (a<0) {
  109         log_warn(LD_DIR, "Unrecognized algorithm name %s", tok->args[0]);
  110         continue;
  111       }
  112       alg = (digest_algorithm_t) a;
  113       flavor = tok->args[0];
  114       algname = tok->args[1];
  115       hexdigest = tok->args[2];
  116     } else {
  117       continue;
  118     }
  119 
  120     digest_length = crypto_digest_algorithm_get_length(alg);
  121     expected_length = digest_length * 2; /* hex encoding */
  122 
  123     if (strlen(hexdigest) != expected_length) {
  124       log_warn(LD_DIR, "Wrong length on consensus-digest in detached "
  125                "networkstatus signatures");
  126       goto err;
  127     }
  128     digests = detached_get_digests(sigs, flavor);
  129     tor_assert(digests);
  130     if (!fast_mem_is_zero(digests->d[alg], digest_length)) {
  131       log_warn(LD_DIR, "Multiple digests for %s with %s on detached "
  132                "signatures document", flavor, algname);
  133       continue;
  134     }
  135     if (base16_decode(digests->d[alg], digest_length,
  136                       hexdigest, strlen(hexdigest)) != (int) digest_length) {
  137       log_warn(LD_DIR, "Bad encoding on consensus-digest in detached "
  138                "networkstatus signatures");
  139       goto err;
  140     }
  141   } SMARTLIST_FOREACH_END(_tok);
  142 
  143   tok = find_by_keyword(tokens, K_VALID_AFTER);
  144   if (parse_iso_time(tok->args[0], &sigs->valid_after)) {
  145     log_warn(LD_DIR, "Bad valid-after in detached networkstatus signatures");
  146     goto err;
  147   }
  148 
  149   tok = find_by_keyword(tokens, K_FRESH_UNTIL);
  150   if (parse_iso_time(tok->args[0], &sigs->fresh_until)) {
  151     log_warn(LD_DIR, "Bad fresh-until in detached networkstatus signatures");
  152     goto err;
  153   }
  154 
  155   tok = find_by_keyword(tokens, K_VALID_UNTIL);
  156   if (parse_iso_time(tok->args[0], &sigs->valid_until)) {
  157     log_warn(LD_DIR, "Bad valid-until in detached networkstatus signatures");
  158     goto err;
  159   }
  160 
  161   SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) {
  162     const char *id_hexdigest;
  163     const char *sk_hexdigest;
  164     const char *algname;
  165     const char *flavor;
  166     digest_algorithm_t alg;
  167 
  168     char id_digest[DIGEST_LEN];
  169     char sk_digest[DIGEST_LEN];
  170     smartlist_t *siglist;
  171     document_signature_t *sig;
  172     int is_duplicate;
  173 
  174     tok = _tok;
  175     if (tok->tp == K_DIRECTORY_SIGNATURE) {
  176       tor_assert(tok->n_args >= 2);
  177       flavor = "ns";
  178       algname = "sha1";
  179       id_hexdigest = tok->args[0];
  180       sk_hexdigest = tok->args[1];
  181     } else if (tok->tp == K_ADDITIONAL_SIGNATURE) {
  182       tor_assert(tok->n_args >= 4);
  183       flavor = tok->args[0];
  184       algname = tok->args[1];
  185       id_hexdigest = tok->args[2];
  186       sk_hexdigest = tok->args[3];
  187     } else {
  188       continue;
  189     }
  190 
  191     {
  192       int a = crypto_digest_algorithm_parse_name(algname);
  193       if (a<0) {
  194         log_warn(LD_DIR, "Unrecognized algorithm name %s", algname);
  195         continue;
  196       }
  197       alg = (digest_algorithm_t) a;
  198     }
  199 
  200     if (!tok->object_type ||
  201         strcmp(tok->object_type, "SIGNATURE") ||
  202         tok->object_size < 128 || tok->object_size > 512) {
  203       log_warn(LD_DIR, "Bad object type or length on directory-signature");
  204       goto err;
  205     }
  206 
  207     if (strlen(id_hexdigest) != HEX_DIGEST_LEN ||
  208         base16_decode(id_digest, sizeof(id_digest),
  209                       id_hexdigest, HEX_DIGEST_LEN) != sizeof(id_digest)) {
  210       log_warn(LD_DIR, "Error decoding declared identity %s in "
  211                "network-status vote.", escaped(id_hexdigest));
  212       goto err;
  213     }
  214     if (strlen(sk_hexdigest) != HEX_DIGEST_LEN ||
  215         base16_decode(sk_digest, sizeof(sk_digest),
  216                       sk_hexdigest, HEX_DIGEST_LEN) != sizeof(sk_digest)) {
  217       log_warn(LD_DIR, "Error decoding declared signing key digest %s in "
  218                "network-status vote.", escaped(sk_hexdigest));
  219       goto err;
  220     }
  221 
  222     siglist = detached_get_signatures(sigs, flavor);
  223     is_duplicate = 0;
  224     SMARTLIST_FOREACH(siglist, document_signature_t *, dsig, {
  225       if (dsig->alg == alg &&
  226           tor_memeq(id_digest, dsig->identity_digest, DIGEST_LEN) &&
  227           tor_memeq(sk_digest, dsig->signing_key_digest, DIGEST_LEN)) {
  228         is_duplicate = 1;
  229       }
  230     });
  231     if (is_duplicate) {
  232       log_warn(LD_DIR, "Two signatures with identical keys and algorithm "
  233                "found.");
  234       continue;
  235     }
  236 
  237     sig = tor_malloc_zero(sizeof(document_signature_t));
  238     sig->alg = alg;
  239     memcpy(sig->identity_digest, id_digest, DIGEST_LEN);
  240     memcpy(sig->signing_key_digest, sk_digest, DIGEST_LEN);
  241     if (tok->object_size >= INT_MAX || tok->object_size >= SIZE_T_CEILING) {
  242       tor_free(sig);
  243       goto err;
  244     }
  245     sig->signature = tor_memdup(tok->object_body, tok->object_size);
  246     sig->signature_len = (int) tok->object_size;
  247 
  248     smartlist_add(siglist, sig);
  249   } SMARTLIST_FOREACH_END(_tok);
  250 
  251   goto done;
  252  err:
  253   ns_detached_signatures_free(sigs);
  254   sigs = NULL;
  255  done:
  256   SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
  257   smartlist_free(tokens);
  258   if (area) {
  259     DUMP_AREA(area, "detached signatures");
  260     memarea_drop_all(area);
  261   }
  262   return sigs;
  263 }
  264 
  265 /** Release all storage held in <b>s</b>. */
  266 void
  267 ns_detached_signatures_free_(ns_detached_signatures_t *s)
  268 {
  269   if (!s)
  270     return;
  271   if (s->signatures) {
  272     STRMAP_FOREACH(s->signatures, flavor, smartlist_t *, sigs) {
  273       SMARTLIST_FOREACH(sigs, document_signature_t *, sig,
  274                         document_signature_free(sig));
  275       smartlist_free(sigs);
  276     } STRMAP_FOREACH_END;
  277     strmap_free(s->signatures, NULL);
  278     strmap_free(s->digests, tor_free_);
  279   }
  280 
  281   tor_free(s);
  282 }