Tor  0.4.7.0-alpha-dev
dsigs_parse.c
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-2021, 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"
16 #include "lib/memarea/memarea.h"
17 
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 ),
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. */
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();
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. */
93  const char *algname;
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;
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:
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
268 {
269  if (!s)
270  return;
271  if (s->signatures) {
272  STRMAP_FOREACH(s->signatures, flavor, smartlist_t *, sigs) {
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 }
int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen)
Definition: binascii.c:506
size_t crypto_digest_algorithm_get_length(digest_algorithm_t alg)
Definition: crypto_digest.c:86
int crypto_digest_algorithm_parse_name(const char *name)
Definition: crypto_digest.c:68
digest_algorithm_t
Definition: crypto_digest.h:44
#define HEX_DIGEST_LEN
Definition: crypto_digest.h:35
int tor_memeq(const void *a, const void *b, size_t sz)
Definition: di_ops.c:107
#define DIGEST_LEN
Definition: digest_sizes.h:20
Authority signature structure.
Code to parse and validate detached-signature objects.
ns_detached_signatures_t * networkstatus_parse_detached_signatures(const char *s, const char *eos)
Definition: dsigs_parse.c:67
void ns_detached_signatures_free_(ns_detached_signatures_t *s)
Definition: dsigs_parse.c:267
const char * escaped(const char *s)
Definition: escape.c:126
#define LD_DIR
Definition: log.h:88
void tor_free_(void *mem)
Definition: malloc.c:227
#define tor_free(p)
Definition: malloc.h:52
memarea_t * memarea_new(void)
Definition: memarea.c:153
Header for memarea.c.
#define memarea_drop_all(area)
Definition: memarea.h:22
Header file for networkstatus.c.
Detached consensus signatures structure.
Master header file for Tor-specific functionality.
void token_clear(directory_token_t *tok)
Definition: parsecommon.c:41
int tokenize_string(memarea_t *area, const char *start, const char *end, smartlist_t *out, const token_rule_t *table, int flags)
Definition: parsecommon.c:53
Header file for parsecommon.c.
@ NO_OBJ
Definition: parsecommon.h:219
@ NEED_OBJ
Definition: parsecommon.h:220
#define T(s, t, a, o)
Definition: parsecommon.h:245
#define T1_START(s, t, a, o)
Definition: parsecommon.h:251
#define T1N(s, t, a, o)
Definition: parsecommon.h:255
#define GE(n)
Definition: parsecommon.h:268
#define CONCAT_ARGS
Definition: parsecommon.h:266
#define T1(s, t, a, o)
Definition: parsecommon.h:249
#define END_OF_TABLE
Definition: parsecommon.h:243
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
char d[N_COMMON_DIGEST_ALGORITHMS][DIGEST256_LEN]
Definition: crypto_digest.h:89
directory_keyword tp
Definition: parsecommon.h:202
char identity_digest[DIGEST_LEN]
digest_algorithm_t alg
char signing_key_digest[DIGEST_LEN]
int parse_iso_time(const char *cp, time_t *t)
Definition: time_fmt.c:392
#define SIZE_T_CEILING
Definition: torint.h:126
Header file for unparseable.c.
#define tor_assert(expr)
Definition: util_bug.h:102
int fast_mem_is_zero(const char *mem, size_t len)
Definition: util_string.c:74