dsigs_parse.c 9.1 KB

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