Fix O(n^2) performance when parsing a big pile of extrainfos
[tor.git] / src / or / routerparse.c
blob781c57897d7b5c18630b521a5d676503d064bdef
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-2011, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
7 /**
8 * \file routerparse.c
9 * \brief Code to parse and validate router descriptors and directories.
10 **/
12 #include "or.h"
13 #include "config.h"
14 #include "circuitbuild.h"
15 #include "dirserv.h"
16 #include "dirvote.h"
17 #include "policies.h"
18 #include "rendcommon.h"
19 #include "router.h"
20 #include "routerlist.h"
21 #include "memarea.h"
22 #include "microdesc.h"
23 #include "networkstatus.h"
24 #include "rephist.h"
25 #include "routerparse.h"
26 #undef log
27 #include <math.h>
29 /****************************************************************************/
31 /** Enumeration of possible token types. The ones starting with K_ correspond
32 * to directory 'keywords'. _ERR is an error in the tokenizing process, _EOF
33 * is an end-of-file marker, and _NIL is used to encode not-a-token.
35 typedef enum {
36 K_ACCEPT = 0,
37 K_ACCEPT6,
38 K_DIRECTORY_SIGNATURE,
39 K_RECOMMENDED_SOFTWARE,
40 K_REJECT,
41 K_REJECT6,
42 K_ROUTER,
43 K_SIGNED_DIRECTORY,
44 K_SIGNING_KEY,
45 K_ONION_KEY,
46 K_ROUTER_SIGNATURE,
47 K_PUBLISHED,
48 K_RUNNING_ROUTERS,
49 K_ROUTER_STATUS,
50 K_PLATFORM,
51 K_OPT,
52 K_BANDWIDTH,
53 K_CONTACT,
54 K_NETWORK_STATUS,
55 K_UPTIME,
56 K_DIR_SIGNING_KEY,
57 K_FAMILY,
58 K_FINGERPRINT,
59 K_HIBERNATING,
60 K_READ_HISTORY,
61 K_WRITE_HISTORY,
62 K_NETWORK_STATUS_VERSION,
63 K_DIR_SOURCE,
64 K_DIR_OPTIONS,
65 K_CLIENT_VERSIONS,
66 K_SERVER_VERSIONS,
67 K_OR_ADDRESS,
68 K_P,
69 K_R,
70 K_S,
71 K_V,
72 K_W,
73 K_M,
74 K_EXTRA_INFO,
75 K_EXTRA_INFO_DIGEST,
76 K_CACHES_EXTRA_INFO,
77 K_HIDDEN_SERVICE_DIR,
78 K_ALLOW_SINGLE_HOP_EXITS,
80 K_DIRREQ_END,
81 K_DIRREQ_V2_IPS,
82 K_DIRREQ_V3_IPS,
83 K_DIRREQ_V2_REQS,
84 K_DIRREQ_V3_REQS,
85 K_DIRREQ_V2_SHARE,
86 K_DIRREQ_V3_SHARE,
87 K_DIRREQ_V2_RESP,
88 K_DIRREQ_V3_RESP,
89 K_DIRREQ_V2_DIR,
90 K_DIRREQ_V3_DIR,
91 K_DIRREQ_V2_TUN,
92 K_DIRREQ_V3_TUN,
93 K_ENTRY_END,
94 K_ENTRY_IPS,
95 K_CELL_END,
96 K_CELL_PROCESSED,
97 K_CELL_QUEUED,
98 K_CELL_TIME,
99 K_CELL_CIRCS,
100 K_EXIT_END,
101 K_EXIT_WRITTEN,
102 K_EXIT_READ,
103 K_EXIT_OPENED,
105 K_DIR_KEY_CERTIFICATE_VERSION,
106 K_DIR_IDENTITY_KEY,
107 K_DIR_KEY_PUBLISHED,
108 K_DIR_KEY_EXPIRES,
109 K_DIR_KEY_CERTIFICATION,
110 K_DIR_KEY_CROSSCERT,
111 K_DIR_ADDRESS,
113 K_VOTE_STATUS,
114 K_VALID_AFTER,
115 K_FRESH_UNTIL,
116 K_VALID_UNTIL,
117 K_VOTING_DELAY,
119 K_KNOWN_FLAGS,
120 K_PARAMS,
121 K_BW_WEIGHTS,
122 K_VOTE_DIGEST,
123 K_CONSENSUS_DIGEST,
124 K_ADDITIONAL_DIGEST,
125 K_ADDITIONAL_SIGNATURE,
126 K_CONSENSUS_METHODS,
127 K_CONSENSUS_METHOD,
128 K_LEGACY_DIR_KEY,
129 K_DIRECTORY_FOOTER,
131 A_PURPOSE,
132 A_LAST_LISTED,
133 _A_UNKNOWN,
135 R_RENDEZVOUS_SERVICE_DESCRIPTOR,
136 R_VERSION,
137 R_PERMANENT_KEY,
138 R_SECRET_ID_PART,
139 R_PUBLICATION_TIME,
140 R_PROTOCOL_VERSIONS,
141 R_INTRODUCTION_POINTS,
142 R_SIGNATURE,
144 R_IPO_IDENTIFIER,
145 R_IPO_IP_ADDRESS,
146 R_IPO_ONION_PORT,
147 R_IPO_ONION_KEY,
148 R_IPO_SERVICE_KEY,
150 C_CLIENT_NAME,
151 C_DESCRIPTOR_COOKIE,
152 C_CLIENT_KEY,
154 _ERR,
155 _EOF,
156 _NIL
157 } directory_keyword;
159 #define MIN_ANNOTATION A_PURPOSE
160 #define MAX_ANNOTATION _A_UNKNOWN
162 /** Structure to hold a single directory token.
164 * We parse a directory by breaking it into "tokens", each consisting
165 * of a keyword, a line full of arguments, and a binary object. The
166 * arguments and object are both optional, depending on the keyword
167 * type.
169 * This structure is only allocated in memareas; do not allocate it on
170 * the heap, or token_clear() won't work.
172 typedef struct directory_token_t {
173 directory_keyword tp; /**< Type of the token. */
174 int n_args:30; /**< Number of elements in args */
175 char **args; /**< Array of arguments from keyword line. */
177 char *object_type; /**< -----BEGIN [object_type]-----*/
178 size_t object_size; /**< Bytes in object_body */
179 char *object_body; /**< Contents of object, base64-decoded. */
181 crypto_pk_t *key; /**< For public keys only. Heap-allocated. */
183 char *error; /**< For _ERR tokens only. */
184 } directory_token_t;
186 /* ********************************************************************** */
188 /** We use a table of rules to decide how to parse each token type. */
190 /** Rules for whether the keyword needs an object. */
191 typedef enum {
192 NO_OBJ, /**< No object, ever. */
193 NEED_OBJ, /**< Object is required. */
194 NEED_SKEY_1024,/**< Object is required, and must be a 1024 bit private key */
195 NEED_KEY_1024, /**< Object is required, and must be a 1024 bit public key */
196 NEED_KEY, /**< Object is required, and must be a public key. */
197 OBJ_OK, /**< Object is optional. */
198 } obj_syntax;
200 #define AT_START 1
201 #define AT_END 2
203 /** Determines the parsing rules for a single token type. */
204 typedef struct token_rule_t {
205 /** The string value of the keyword identifying the type of item. */
206 const char *t;
207 /** The corresponding directory_keyword enum. */
208 directory_keyword v;
209 /** Minimum number of arguments for this item */
210 int min_args;
211 /** Maximum number of arguments for this item */
212 int max_args;
213 /** If true, we concatenate all arguments for this item into a single
214 * string. */
215 int concat_args;
216 /** Requirements on object syntax for this item. */
217 obj_syntax os;
218 /** Lowest number of times this item may appear in a document. */
219 int min_cnt;
220 /** Highest number of times this item may appear in a document. */
221 int max_cnt;
222 /** One or more of AT_START/AT_END to limit where the item may appear in a
223 * document. */
224 int pos;
225 /** True iff this token is an annotation. */
226 int is_annotation;
227 } token_rule_t;
230 * Helper macros to define token tables. 's' is a string, 't' is a
231 * directory_keyword, 'a' is a trio of argument multiplicities, and 'o' is an
232 * object syntax.
236 /** Appears to indicate the end of a table. */
237 #define END_OF_TABLE { NULL, _NIL, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 }
238 /** An item with no restrictions: used for obsolete document types */
239 #define T(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 }
240 /** An item with no restrictions on multiplicity or location. */
241 #define T0N(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 }
242 /** An item that must appear exactly once */
243 #define T1(s,t,a,o) { s, t, a, o, 1, 1, 0, 0 }
244 /** An item that must appear exactly once, at the start of the document */
245 #define T1_START(s,t,a,o) { s, t, a, o, 1, 1, AT_START, 0 }
246 /** An item that must appear exactly once, at the end of the document */
247 #define T1_END(s,t,a,o) { s, t, a, o, 1, 1, AT_END, 0 }
248 /** An item that must appear one or more times */
249 #define T1N(s,t,a,o) { s, t, a, o, 1, INT_MAX, 0, 0 }
250 /** An item that must appear no more than once */
251 #define T01(s,t,a,o) { s, t, a, o, 0, 1, 0, 0 }
252 /** An annotation that must appear no more than once */
253 #define A01(s,t,a,o) { s, t, a, o, 0, 1, 0, 1 }
255 /* Argument multiplicity: any number of arguments. */
256 #define ARGS 0,INT_MAX,0
257 /* Argument multiplicity: no arguments. */
258 #define NO_ARGS 0,0,0
259 /* Argument multiplicity: concatenate all arguments. */
260 #define CONCAT_ARGS 1,1,1
261 /* Argument multiplicity: at least <b>n</b> arguments. */
262 #define GE(n) n,INT_MAX,0
263 /* Argument multiplicity: exactly <b>n</b> arguments. */
264 #define EQ(n) n,n,0
266 /** List of tokens allowable in router descriptors */
267 static token_rule_t routerdesc_token_table[] = {
268 T0N("reject", K_REJECT, ARGS, NO_OBJ ),
269 T0N("accept", K_ACCEPT, ARGS, NO_OBJ ),
270 T0N("reject6", K_REJECT6, ARGS, NO_OBJ ),
271 T0N("accept6", K_ACCEPT6, ARGS, NO_OBJ ),
272 T1_START( "router", K_ROUTER, GE(5), NO_OBJ ),
273 T1( "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ),
274 T1( "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ),
275 T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
276 T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
277 T01("uptime", K_UPTIME, GE(1), NO_OBJ ),
278 T01("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
279 T01("hibernating", K_HIBERNATING, GE(1), NO_OBJ ),
280 T01("platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ ),
281 T01("contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
282 T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ),
283 T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ),
284 T01("extra-info-digest", K_EXTRA_INFO_DIGEST, GE(1), NO_OBJ ),
285 T01("hidden-service-dir", K_HIDDEN_SERVICE_DIR, NO_ARGS, NO_OBJ ),
286 T01("allow-single-hop-exits",K_ALLOW_SINGLE_HOP_EXITS, NO_ARGS, NO_OBJ ),
288 T01("family", K_FAMILY, ARGS, NO_OBJ ),
289 T01("caches-extra-info", K_CACHES_EXTRA_INFO, NO_ARGS, NO_OBJ ),
290 T0N("or-address", K_OR_ADDRESS, GE(1), NO_OBJ ),
292 T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
293 T1( "bandwidth", K_BANDWIDTH, GE(3), NO_OBJ ),
294 A01("@purpose", A_PURPOSE, GE(1), NO_OBJ ),
296 END_OF_TABLE
299 /** List of tokens allowable in extra-info documents. */
300 static token_rule_t extrainfo_token_table[] = {
301 T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
302 T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
303 T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
304 T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ),
305 T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ),
306 T01("dirreq-stats-end", K_DIRREQ_END, ARGS, NO_OBJ ),
307 T01("dirreq-v2-ips", K_DIRREQ_V2_IPS, ARGS, NO_OBJ ),
308 T01("dirreq-v3-ips", K_DIRREQ_V3_IPS, ARGS, NO_OBJ ),
309 T01("dirreq-v2-reqs", K_DIRREQ_V2_REQS, ARGS, NO_OBJ ),
310 T01("dirreq-v3-reqs", K_DIRREQ_V3_REQS, ARGS, NO_OBJ ),
311 T01("dirreq-v2-share", K_DIRREQ_V2_SHARE, ARGS, NO_OBJ ),
312 T01("dirreq-v3-share", K_DIRREQ_V3_SHARE, ARGS, NO_OBJ ),
313 T01("dirreq-v2-resp", K_DIRREQ_V2_RESP, ARGS, NO_OBJ ),
314 T01("dirreq-v3-resp", K_DIRREQ_V3_RESP, ARGS, NO_OBJ ),
315 T01("dirreq-v2-direct-dl", K_DIRREQ_V2_DIR, ARGS, NO_OBJ ),
316 T01("dirreq-v3-direct-dl", K_DIRREQ_V3_DIR, ARGS, NO_OBJ ),
317 T01("dirreq-v2-tunneled-dl", K_DIRREQ_V2_TUN, ARGS, NO_OBJ ),
318 T01("dirreq-v3-tunneled-dl", K_DIRREQ_V3_TUN, ARGS, NO_OBJ ),
319 T01("entry-stats-end", K_ENTRY_END, ARGS, NO_OBJ ),
320 T01("entry-ips", K_ENTRY_IPS, ARGS, NO_OBJ ),
321 T01("cell-stats-end", K_CELL_END, ARGS, NO_OBJ ),
322 T01("cell-processed-cells", K_CELL_PROCESSED, ARGS, NO_OBJ ),
323 T01("cell-queued-cells", K_CELL_QUEUED, ARGS, NO_OBJ ),
324 T01("cell-time-in-queue", K_CELL_TIME, ARGS, NO_OBJ ),
325 T01("cell-circuits-per-decile", K_CELL_CIRCS, ARGS, NO_OBJ ),
326 T01("exit-stats-end", K_EXIT_END, ARGS, NO_OBJ ),
327 T01("exit-kibibytes-written", K_EXIT_WRITTEN, ARGS, NO_OBJ ),
328 T01("exit-kibibytes-read", K_EXIT_READ, ARGS, NO_OBJ ),
329 T01("exit-streams-opened", K_EXIT_OPENED, ARGS, NO_OBJ ),
331 T1_START( "extra-info", K_EXTRA_INFO, GE(2), NO_OBJ ),
333 END_OF_TABLE
336 /** List of tokens allowable in the body part of v2 and v3 networkstatus
337 * documents. */
338 static token_rule_t rtrstatus_token_table[] = {
339 T01("p", K_P, CONCAT_ARGS, NO_OBJ ),
340 T1( "r", K_R, GE(7), NO_OBJ ),
341 T1( "s", K_S, ARGS, NO_OBJ ),
342 T01("v", K_V, CONCAT_ARGS, NO_OBJ ),
343 T01("w", K_W, ARGS, NO_OBJ ),
344 T0N("m", K_M, CONCAT_ARGS, NO_OBJ ),
345 T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
346 END_OF_TABLE
349 /** List of tokens allowable in the header part of v2 networkstatus documents.
351 static token_rule_t netstatus_token_table[] = {
352 T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
353 T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
354 T1( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
355 T1( "dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ),
356 T1( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
357 T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
358 GE(1), NO_OBJ ),
359 T1( "dir-source", K_DIR_SOURCE, GE(3), NO_OBJ ),
360 T01("dir-options", K_DIR_OPTIONS, ARGS, NO_OBJ ),
361 T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
362 T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
364 END_OF_TABLE
367 /** List of tokens allowable in the footer of v1/v2 directory/networkstatus
368 * footers. */
369 static token_rule_t dir_footer_token_table[] = {
370 T1("directory-signature", K_DIRECTORY_SIGNATURE, EQ(1), NEED_OBJ ),
371 END_OF_TABLE
374 /** List of tokens allowable in v1 directory headers/footers. */
375 static token_rule_t dir_token_table[] = {
376 /* don't enforce counts; this is obsolete. */
377 T( "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ ),
378 T( "directory-signature", K_DIRECTORY_SIGNATURE, ARGS, NEED_OBJ ),
379 T( "recommended-software",K_RECOMMENDED_SOFTWARE,CONCAT_ARGS, NO_OBJ ),
380 T( "signed-directory", K_SIGNED_DIRECTORY, NO_ARGS, NO_OBJ ),
382 T( "running-routers", K_RUNNING_ROUTERS, ARGS, NO_OBJ ),
383 T( "router-status", K_ROUTER_STATUS, ARGS, NO_OBJ ),
384 T( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
385 T( "opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
386 T( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
387 T( "dir-signing-key", K_DIR_SIGNING_KEY, ARGS, OBJ_OK ),
388 T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
390 END_OF_TABLE
393 /** List of tokens common to V3 authority certificates and V3 consensuses. */
394 #define CERTIFICATE_MEMBERS \
395 T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION, \
396 GE(1), NO_OBJ ), \
397 T1("dir-identity-key", K_DIR_IDENTITY_KEY, NO_ARGS, NEED_KEY ),\
398 T1("dir-key-published",K_DIR_KEY_PUBLISHED, CONCAT_ARGS, NO_OBJ), \
399 T1("dir-key-expires", K_DIR_KEY_EXPIRES, CONCAT_ARGS, NO_OBJ), \
400 T1("dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY ),\
401 T01("dir-key-crosscert", K_DIR_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ),\
402 T1("dir-key-certification", K_DIR_KEY_CERTIFICATION, \
403 NO_ARGS, NEED_OBJ), \
404 T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ),
406 /** List of tokens allowable in V3 authority certificates. */
407 static token_rule_t dir_key_certificate_table[] = {
408 CERTIFICATE_MEMBERS
409 T1("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
410 END_OF_TABLE
413 /** List of tokens allowable in rendezvous service descriptors */
414 static token_rule_t desc_token_table[] = {
415 T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR,
416 EQ(1), NO_OBJ),
417 T1("version", R_VERSION, EQ(1), NO_OBJ),
418 T1("permanent-key", R_PERMANENT_KEY, NO_ARGS, NEED_KEY_1024),
419 T1("secret-id-part", R_SECRET_ID_PART, EQ(1), NO_OBJ),
420 T1("publication-time", R_PUBLICATION_TIME, CONCAT_ARGS, NO_OBJ),
421 T1("protocol-versions", R_PROTOCOL_VERSIONS, EQ(1), NO_OBJ),
422 T01("introduction-points", R_INTRODUCTION_POINTS, NO_ARGS, NEED_OBJ),
423 T1_END("signature", R_SIGNATURE, NO_ARGS, NEED_OBJ),
424 END_OF_TABLE
427 /** List of tokens allowed in the (encrypted) list of introduction points of
428 * rendezvous service descriptors */
429 static token_rule_t ipo_token_table[] = {
430 T1_START("introduction-point", R_IPO_IDENTIFIER, EQ(1), NO_OBJ),
431 T1("ip-address", R_IPO_IP_ADDRESS, EQ(1), NO_OBJ),
432 T1("onion-port", R_IPO_ONION_PORT, EQ(1), NO_OBJ),
433 T1("onion-key", R_IPO_ONION_KEY, NO_ARGS, NEED_KEY_1024),
434 T1("service-key", R_IPO_SERVICE_KEY, NO_ARGS, NEED_KEY_1024),
435 END_OF_TABLE
438 /** List of tokens allowed in the (possibly encrypted) list of introduction
439 * points of rendezvous service descriptors */
440 static token_rule_t client_keys_token_table[] = {
441 T1_START("client-name", C_CLIENT_NAME, CONCAT_ARGS, NO_OBJ),
442 T1("descriptor-cookie", C_DESCRIPTOR_COOKIE, EQ(1), NO_OBJ),
443 T01("client-key", C_CLIENT_KEY, NO_ARGS, NEED_SKEY_1024),
444 END_OF_TABLE
447 /** List of tokens allowed in V3 networkstatus votes. */
448 static token_rule_t networkstatus_token_table[] = {
449 T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
450 GE(1), NO_OBJ ),
451 T1("vote-status", K_VOTE_STATUS, GE(1), NO_OBJ ),
452 T1("published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
453 T1("valid-after", K_VALID_AFTER, CONCAT_ARGS, NO_OBJ ),
454 T1("fresh-until", K_FRESH_UNTIL, CONCAT_ARGS, NO_OBJ ),
455 T1("valid-until", K_VALID_UNTIL, CONCAT_ARGS, NO_OBJ ),
456 T1("voting-delay", K_VOTING_DELAY, GE(2), NO_OBJ ),
457 T1("known-flags", K_KNOWN_FLAGS, ARGS, NO_OBJ ),
458 T01("params", K_PARAMS, ARGS, NO_OBJ ),
459 T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
461 CERTIFICATE_MEMBERS
463 T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
464 T1( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
465 T1( "dir-source", K_DIR_SOURCE, GE(6), NO_OBJ ),
466 T01("legacy-dir-key", K_LEGACY_DIR_KEY, GE(1), NO_OBJ ),
467 T1( "known-flags", K_KNOWN_FLAGS, CONCAT_ARGS, NO_OBJ ),
468 T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
469 T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
470 T1( "consensus-methods", K_CONSENSUS_METHODS, GE(1), NO_OBJ ),
472 END_OF_TABLE
475 /** List of tokens allowed in V3 networkstatus consensuses. */
476 static token_rule_t networkstatus_consensus_token_table[] = {
477 T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
478 GE(1), NO_OBJ ),
479 T1("vote-status", K_VOTE_STATUS, GE(1), NO_OBJ ),
480 T1("valid-after", K_VALID_AFTER, CONCAT_ARGS, NO_OBJ ),
481 T1("fresh-until", K_FRESH_UNTIL, CONCAT_ARGS, NO_OBJ ),
482 T1("valid-until", K_VALID_UNTIL, CONCAT_ARGS, NO_OBJ ),
483 T1("voting-delay", K_VOTING_DELAY, GE(2), NO_OBJ ),
485 T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
487 T1N("dir-source", K_DIR_SOURCE, GE(6), NO_OBJ ),
488 T1N("contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
489 T1N("vote-digest", K_VOTE_DIGEST, GE(1), NO_OBJ ),
491 T1( "known-flags", K_KNOWN_FLAGS, CONCAT_ARGS, NO_OBJ ),
493 T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
494 T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
495 T01("consensus-method", K_CONSENSUS_METHOD, EQ(1), NO_OBJ),
496 T01("params", K_PARAMS, ARGS, NO_OBJ ),
498 END_OF_TABLE
501 /** List of tokens allowable in the footer of v1/v2 directory/networkstatus
502 * footers. */
503 static token_rule_t networkstatus_vote_footer_token_table[] = {
504 T01("directory-footer", K_DIRECTORY_FOOTER, NO_ARGS, NO_OBJ ),
505 T01("bandwidth-weights", K_BW_WEIGHTS, ARGS, NO_OBJ ),
506 T( "directory-signature", K_DIRECTORY_SIGNATURE, GE(2), NEED_OBJ ),
507 END_OF_TABLE
510 /** List of tokens allowable in detached networkstatus signature documents. */
511 static token_rule_t networkstatus_detached_signature_token_table[] = {
512 T1_START("consensus-digest", K_CONSENSUS_DIGEST, GE(1), NO_OBJ ),
513 T("additional-digest", K_ADDITIONAL_DIGEST,GE(3), NO_OBJ ),
514 T1("valid-after", K_VALID_AFTER, CONCAT_ARGS, NO_OBJ ),
515 T1("fresh-until", K_FRESH_UNTIL, CONCAT_ARGS, NO_OBJ ),
516 T1("valid-until", K_VALID_UNTIL, CONCAT_ARGS, NO_OBJ ),
517 T("additional-signature", K_ADDITIONAL_SIGNATURE, GE(4), NEED_OBJ ),
518 T1N("directory-signature", K_DIRECTORY_SIGNATURE, GE(2), NEED_OBJ ),
519 END_OF_TABLE
522 static token_rule_t microdesc_token_table[] = {
523 T1_START("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024),
524 T01("family", K_FAMILY, ARGS, NO_OBJ ),
525 T01("p", K_P, CONCAT_ARGS, NO_OBJ ),
526 A01("@last-listed", A_LAST_LISTED, CONCAT_ARGS, NO_OBJ ),
527 END_OF_TABLE
530 #undef T
532 /* static function prototypes */
533 static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok);
534 static addr_policy_t *router_parse_addr_policy(directory_token_t *tok);
535 static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok);
537 static int router_get_hash_impl(const char *s, size_t s_len, char *digest,
538 const char *start_str, const char *end_str,
539 char end_char,
540 digest_algorithm_t alg);
541 static int router_get_hashes_impl(const char *s, size_t s_len,
542 digests_t *digests,
543 const char *start_str, const char *end_str,
544 char end_char);
545 static void token_clear(directory_token_t *tok);
546 static smartlist_t *find_all_by_keyword(smartlist_t *s, directory_keyword k);
547 static smartlist_t *find_all_exitpolicy(smartlist_t *s);
548 static directory_token_t *_find_by_keyword(smartlist_t *s,
549 directory_keyword keyword,
550 const char *keyword_str);
551 #define find_by_keyword(s, keyword) _find_by_keyword((s), (keyword), #keyword)
552 static directory_token_t *find_opt_by_keyword(smartlist_t *s,
553 directory_keyword keyword);
555 #define TS_ANNOTATIONS_OK 1
556 #define TS_NOCHECK 2
557 #define TS_NO_NEW_ANNOTATIONS 4
558 static int tokenize_string(memarea_t *area,
559 const char *start, const char *end,
560 smartlist_t *out,
561 token_rule_t *table,
562 int flags);
563 static directory_token_t *get_next_token(memarea_t *area,
564 const char **s,
565 const char *eos,
566 token_rule_t *table);
567 #define CST_CHECK_AUTHORITY (1<<0)
568 #define CST_NO_CHECK_OBJTYPE (1<<1)
569 static int check_signature_token(const char *digest,
570 ssize_t digest_len,
571 directory_token_t *tok,
572 crypto_pk_t *pkey,
573 int flags,
574 const char *doctype);
575 static crypto_pk_t *find_dir_signing_key(const char *str, const char *eos);
577 #undef DEBUG_AREA_ALLOC
579 #ifdef DEBUG_AREA_ALLOC
580 #define DUMP_AREA(a,name) STMT_BEGIN \
581 size_t alloc=0, used=0; \
582 memarea_get_stats((a),&alloc,&used); \
583 log_debug(LD_MM, "Area for %s has %lu allocated; using %lu.", \
584 name, (unsigned long)alloc, (unsigned long)used); \
585 STMT_END
586 #else
587 #define DUMP_AREA(a,name) STMT_NIL
588 #endif
590 /** Last time we dumped a descriptor to disk. */
591 static time_t last_desc_dumped = 0;
593 /** For debugging purposes, dump unparseable descriptor *<b>desc</b> of
594 * type *<b>type</b> to file $DATADIR/unparseable-desc. Do not write more
595 * than one descriptor to disk per minute. If there is already such a
596 * file in the data directory, overwrite it. */
597 static void
598 dump_desc(const char *desc, const char *type)
600 time_t now = time(NULL);
601 tor_assert(desc);
602 tor_assert(type);
603 if (!last_desc_dumped || last_desc_dumped + 60 < now) {
604 char *debugfile = get_datadir_fname("unparseable-desc");
605 size_t filelen = 50 + strlen(type) + strlen(desc);
606 char *content = tor_malloc_zero(filelen);
607 tor_snprintf(content, filelen, "Unable to parse descriptor of type "
608 "%s:\n%s", type, desc);
609 write_str_to_file(debugfile, content, 0);
610 log_info(LD_DIR, "Unable to parse descriptor of type %s. See file "
611 "unparseable-desc in data directory for details.", type);
612 tor_free(content);
613 tor_free(debugfile);
614 last_desc_dumped = now;
618 /** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
619 * <b>s</b>. Return 0 on success, -1 on failure.
622 router_get_dir_hash(const char *s, char *digest)
624 return router_get_hash_impl(s, strlen(s), digest,
625 "signed-directory","\ndirectory-signature",'\n',
626 DIGEST_SHA1);
629 /** Set <b>digest</b> to the SHA-1 digest of the hash of the first router in
630 * <b>s</b>. Return 0 on success, -1 on failure.
633 router_get_router_hash(const char *s, size_t s_len, char *digest)
635 return router_get_hash_impl(s, s_len, digest,
636 "router ","\nrouter-signature", '\n',
637 DIGEST_SHA1);
640 /** Set <b>digest</b> to the SHA-1 digest of the hash of the running-routers
641 * string in <b>s</b>. Return 0 on success, -1 on failure.
644 router_get_runningrouters_hash(const char *s, char *digest)
646 return router_get_hash_impl(s, strlen(s), digest,
647 "network-status","\ndirectory-signature", '\n',
648 DIGEST_SHA1);
651 /** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status
652 * string in <b>s</b>. Return 0 on success, -1 on failure. */
654 router_get_networkstatus_v2_hash(const char *s, char *digest)
656 return router_get_hash_impl(s, strlen(s), digest,
657 "network-status-version","\ndirectory-signature",
658 '\n',
659 DIGEST_SHA1);
662 /** Set <b>digests</b> to all the digests of the consensus document in
663 * <b>s</b> */
665 router_get_networkstatus_v3_hashes(const char *s, digests_t *digests)
667 return router_get_hashes_impl(s,strlen(s),digests,
668 "network-status-version",
669 "\ndirectory-signature",
670 ' ');
673 /** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status
674 * string in <b>s</b>. Return 0 on success, -1 on failure. */
676 router_get_networkstatus_v3_hash(const char *s, char *digest,
677 digest_algorithm_t alg)
679 return router_get_hash_impl(s, strlen(s), digest,
680 "network-status-version",
681 "\ndirectory-signature",
682 ' ', alg);
685 /** Set <b>digest</b> to the SHA-1 digest of the hash of the <b>s_len</b>-byte
686 * extrainfo string at <b>s</b>. Return 0 on success, -1 on failure. */
688 router_get_extrainfo_hash(const char *s, size_t s_len, char *digest)
690 return router_get_hash_impl(s, s_len, digest, "extra-info",
691 "\nrouter-signature",'\n', DIGEST_SHA1);
694 /** Helper: used to generate signatures for routers, directories and
695 * network-status objects. Given a digest in <b>digest</b> and a secret
696 * <b>private_key</b>, generate an PKCS1-padded signature, BASE64-encode it,
697 * surround it with -----BEGIN/END----- pairs, and write it to the
698 * <b>buf_len</b>-byte buffer at <b>buf</b>. Return 0 on success, -1 on
699 * failure.
702 router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
703 size_t digest_len, crypto_pk_t *private_key)
705 char *signature;
706 size_t i, keysize;
707 int siglen;
709 keysize = crypto_pk_keysize(private_key);
710 signature = tor_malloc(keysize);
711 siglen = crypto_pk_private_sign(private_key, signature, keysize,
712 digest, digest_len);
713 if (siglen < 0) {
714 log_warn(LD_BUG,"Couldn't sign digest.");
715 goto err;
717 if (strlcat(buf, "-----BEGIN SIGNATURE-----\n", buf_len) >= buf_len)
718 goto truncated;
720 i = strlen(buf);
721 if (base64_encode(buf+i, buf_len-i, signature, siglen) < 0) {
722 log_warn(LD_BUG,"couldn't base64-encode signature");
723 goto err;
726 if (strlcat(buf, "-----END SIGNATURE-----\n", buf_len) >= buf_len)
727 goto truncated;
729 tor_free(signature);
730 return 0;
732 truncated:
733 log_warn(LD_BUG,"tried to exceed string length.");
734 err:
735 tor_free(signature);
736 return -1;
739 /** Return VS_RECOMMENDED if <b>myversion</b> is contained in
740 * <b>versionlist</b>. Else, return VS_EMPTY if versionlist has no
741 * entries. Else, return VS_OLD if every member of
742 * <b>versionlist</b> is newer than <b>myversion</b>. Else, return
743 * VS_NEW_IN_SERIES if there is at least one member of <b>versionlist</b> in
744 * the same series (major.minor.micro) as <b>myversion</b>, but no such member
745 * is newer than <b>myversion.</b>. Else, return VS_NEW if every member of
746 * <b>versionlist</b> is older than <b>myversion</b>. Else, return
747 * VS_UNRECOMMENDED.
749 * (versionlist is a comma-separated list of version strings,
750 * optionally prefixed with "Tor". Versions that can't be parsed are
751 * ignored.)
753 version_status_t
754 tor_version_is_obsolete(const char *myversion, const char *versionlist)
756 tor_version_t mine, other;
757 int found_newer = 0, found_older = 0, found_newer_in_series = 0,
758 found_any_in_series = 0, r, same;
759 version_status_t ret = VS_UNRECOMMENDED;
760 smartlist_t *version_sl;
762 log_debug(LD_CONFIG,"Checking whether version '%s' is in '%s'",
763 myversion, versionlist);
765 if (tor_version_parse(myversion, &mine)) {
766 log_err(LD_BUG,"I couldn't parse my own version (%s)", myversion);
767 tor_assert(0);
769 version_sl = smartlist_new();
770 smartlist_split_string(version_sl, versionlist, ",", SPLIT_SKIP_SPACE, 0);
772 if (!strlen(versionlist)) { /* no authorities cared or agreed */
773 ret = VS_EMPTY;
774 goto done;
777 SMARTLIST_FOREACH(version_sl, const char *, cp, {
778 if (!strcmpstart(cp, "Tor "))
779 cp += 4;
781 if (tor_version_parse(cp, &other)) {
782 /* Couldn't parse other; it can't be a match. */
783 } else {
784 same = tor_version_same_series(&mine, &other);
785 if (same)
786 found_any_in_series = 1;
787 r = tor_version_compare(&mine, &other);
788 if (r==0) {
789 ret = VS_RECOMMENDED;
790 goto done;
791 } else if (r<0) {
792 found_newer = 1;
793 if (same)
794 found_newer_in_series = 1;
795 } else if (r>0) {
796 found_older = 1;
801 /* We didn't find the listed version. Is it new or old? */
802 if (found_any_in_series && !found_newer_in_series && found_newer) {
803 ret = VS_NEW_IN_SERIES;
804 } else if (found_newer && !found_older) {
805 ret = VS_OLD;
806 } else if (found_older && !found_newer) {
807 ret = VS_NEW;
808 } else {
809 ret = VS_UNRECOMMENDED;
812 done:
813 SMARTLIST_FOREACH(version_sl, char *, version, tor_free(version));
814 smartlist_free(version_sl);
815 return ret;
818 /** Read a signed directory from <b>str</b>. If it's well-formed, return 0.
819 * Otherwise, return -1. If we're a directory cache, cache it.
822 router_parse_directory(const char *str)
824 directory_token_t *tok;
825 char digest[DIGEST_LEN];
826 time_t published_on;
827 int r;
828 const char *end, *cp, *str_dup = str;
829 smartlist_t *tokens = NULL;
830 crypto_pk_t *declared_key = NULL;
831 memarea_t *area = memarea_new();
833 /* XXXX This could be simplified a lot, but it will all go away
834 * once pre-0.1.1.8 is obsolete, and for now it's better not to
835 * touch it. */
837 if (router_get_dir_hash(str, digest)) {
838 log_warn(LD_DIR, "Unable to compute digest of directory");
839 goto err;
841 log_debug(LD_DIR,"Received directory hashes to %s",hex_str(digest,4));
843 /* Check signature first, before we try to tokenize. */
844 cp = str;
845 while (cp && (end = strstr(cp+1, "\ndirectory-signature")))
846 cp = end;
847 if (cp == str || !cp) {
848 log_warn(LD_DIR, "No signature found on directory."); goto err;
850 ++cp;
851 tokens = smartlist_new();
852 if (tokenize_string(area,cp,strchr(cp,'\0'),tokens,dir_token_table,0)) {
853 log_warn(LD_DIR, "Error tokenizing directory signature"); goto err;
855 if (smartlist_len(tokens) != 1) {
856 log_warn(LD_DIR, "Unexpected number of tokens in signature"); goto err;
858 tok=smartlist_get(tokens,0);
859 if (tok->tp != K_DIRECTORY_SIGNATURE) {
860 log_warn(LD_DIR,"Expected a single directory signature"); goto err;
862 declared_key = find_dir_signing_key(str, str+strlen(str));
863 note_crypto_pk_op(VERIFY_DIR);
864 if (check_signature_token(digest, DIGEST_LEN, tok, declared_key,
865 CST_CHECK_AUTHORITY, "directory")<0)
866 goto err;
868 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
869 smartlist_clear(tokens);
870 memarea_clear(area);
872 /* Now try to parse the first part of the directory. */
873 if ((end = strstr(str,"\nrouter "))) {
874 ++end;
875 } else if ((end = strstr(str, "\ndirectory-signature"))) {
876 ++end;
877 } else {
878 end = str + strlen(str);
881 if (tokenize_string(area,str,end,tokens,dir_token_table,0)) {
882 log_warn(LD_DIR, "Error tokenizing directory"); goto err;
885 tok = find_by_keyword(tokens, K_PUBLISHED);
886 tor_assert(tok->n_args == 1);
888 if (parse_iso_time(tok->args[0], &published_on) < 0) {
889 goto err;
892 /* Now that we know the signature is okay, and we have a
893 * publication time, cache the directory. */
894 if (directory_caches_v1_dir_info(get_options()) &&
895 !authdir_mode_v1(get_options()))
896 dirserv_set_cached_directory(str, published_on, 0);
898 r = 0;
899 goto done;
900 err:
901 dump_desc(str_dup, "v1 directory");
902 r = -1;
903 done:
904 if (declared_key) crypto_pk_free(declared_key);
905 if (tokens) {
906 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
907 smartlist_free(tokens);
909 if (area) {
910 DUMP_AREA(area, "v1 directory");
911 memarea_drop_all(area);
913 return r;
916 /** Read a signed router status statement from <b>str</b>. If it's
917 * well-formed, return 0. Otherwise, return -1. If we're a directory cache,
918 * cache it.*/
920 router_parse_runningrouters(const char *str)
922 char digest[DIGEST_LEN];
923 directory_token_t *tok;
924 time_t published_on;
925 int r = -1;
926 crypto_pk_t *declared_key = NULL;
927 smartlist_t *tokens = NULL;
928 const char *eos = str + strlen(str), *str_dup = str;
929 memarea_t *area = NULL;
931 if (router_get_runningrouters_hash(str, digest)) {
932 log_warn(LD_DIR, "Unable to compute digest of running-routers");
933 goto err;
935 area = memarea_new();
936 tokens = smartlist_new();
937 if (tokenize_string(area,str,eos,tokens,dir_token_table,0)) {
938 log_warn(LD_DIR, "Error tokenizing running-routers"); goto err;
940 tok = smartlist_get(tokens,0);
941 if (tok->tp != K_NETWORK_STATUS) {
942 log_warn(LD_DIR, "Network-status starts with wrong token");
943 goto err;
946 tok = find_by_keyword(tokens, K_PUBLISHED);
947 tor_assert(tok->n_args == 1);
948 if (parse_iso_time(tok->args[0], &published_on) < 0) {
949 goto err;
951 if (!(tok = find_opt_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) {
952 log_warn(LD_DIR, "Missing signature on running-routers");
953 goto err;
955 declared_key = find_dir_signing_key(str, eos);
956 note_crypto_pk_op(VERIFY_DIR);
957 if (check_signature_token(digest, DIGEST_LEN, tok, declared_key,
958 CST_CHECK_AUTHORITY, "running-routers")
959 < 0)
960 goto err;
962 /* Now that we know the signature is okay, and we have a
963 * publication time, cache the list. */
964 if (get_options()->DirPort && !authdir_mode_v1(get_options()))
965 dirserv_set_cached_directory(str, published_on, 1);
967 r = 0;
968 err:
969 dump_desc(str_dup, "v1 running-routers");
970 if (declared_key) crypto_pk_free(declared_key);
971 if (tokens) {
972 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
973 smartlist_free(tokens);
975 if (area) {
976 DUMP_AREA(area, "v1 running-routers");
977 memarea_drop_all(area);
979 return r;
982 /** Given a directory or running-routers string in <b>str</b>, try to
983 * find the its dir-signing-key token (if any). If this token is
984 * present, extract and return the key. Return NULL on failure. */
985 static crypto_pk_t *
986 find_dir_signing_key(const char *str, const char *eos)
988 const char *cp;
989 directory_token_t *tok;
990 crypto_pk_t *key = NULL;
991 memarea_t *area = NULL;
992 tor_assert(str);
993 tor_assert(eos);
995 /* Is there a dir-signing-key in the directory? */
996 cp = tor_memstr(str, eos-str, "\nopt dir-signing-key");
997 if (!cp)
998 cp = tor_memstr(str, eos-str, "\ndir-signing-key");
999 if (!cp)
1000 return NULL;
1001 ++cp; /* Now cp points to the start of the token. */
1003 area = memarea_new();
1004 tok = get_next_token(area, &cp, eos, dir_token_table);
1005 if (!tok) {
1006 log_warn(LD_DIR, "Unparseable dir-signing-key token");
1007 goto done;
1009 if (tok->tp != K_DIR_SIGNING_KEY) {
1010 log_warn(LD_DIR, "Dir-signing-key token did not parse as expected");
1011 goto done;
1014 if (tok->key) {
1015 key = tok->key;
1016 tok->key = NULL; /* steal reference. */
1017 } else {
1018 log_warn(LD_DIR, "Dir-signing-key token contained no key");
1021 done:
1022 if (tok) token_clear(tok);
1023 if (area) {
1024 DUMP_AREA(area, "dir-signing-key token");
1025 memarea_drop_all(area);
1027 return key;
1030 /** Return true iff <b>key</b> is allowed to sign directories.
1032 static int
1033 dir_signing_key_is_trusted(crypto_pk_t *key)
1035 char digest[DIGEST_LEN];
1036 if (!key) return 0;
1037 if (crypto_pk_get_digest(key, digest) < 0) {
1038 log_warn(LD_DIR, "Error computing dir-signing-key digest");
1039 return 0;
1041 if (!router_digest_is_trusted_dir(digest)) {
1042 log_warn(LD_DIR, "Listed dir-signing-key is not trusted");
1043 return 0;
1045 return 1;
1048 /** Check whether the object body of the token in <b>tok</b> has a good
1049 * signature for <b>digest</b> using key <b>pkey</b>. If
1050 * <b>CST_CHECK_AUTHORITY</b> is set, make sure that <b>pkey</b> is the key of
1051 * a directory authority. If <b>CST_NO_CHECK_OBJTYPE</b> is set, do not check
1052 * the object type of the signature object. Use <b>doctype</b> as the type of
1053 * the document when generating log messages. Return 0 on success, negative
1054 * on failure.
1056 static int
1057 check_signature_token(const char *digest,
1058 ssize_t digest_len,
1059 directory_token_t *tok,
1060 crypto_pk_t *pkey,
1061 int flags,
1062 const char *doctype)
1064 char *signed_digest;
1065 size_t keysize;
1066 const int check_authority = (flags & CST_CHECK_AUTHORITY);
1067 const int check_objtype = ! (flags & CST_NO_CHECK_OBJTYPE);
1069 tor_assert(pkey);
1070 tor_assert(tok);
1071 tor_assert(digest);
1072 tor_assert(doctype);
1074 if (check_authority && !dir_signing_key_is_trusted(pkey)) {
1075 log_warn(LD_DIR, "Key on %s did not come from an authority; rejecting",
1076 doctype);
1077 return -1;
1080 if (check_objtype) {
1081 if (strcmp(tok->object_type, "SIGNATURE")) {
1082 log_warn(LD_DIR, "Bad object type on %s signature", doctype);
1083 return -1;
1087 keysize = crypto_pk_keysize(pkey);
1088 signed_digest = tor_malloc(keysize);
1089 if (crypto_pk_public_checksig(pkey, signed_digest, keysize,
1090 tok->object_body, tok->object_size)
1091 < digest_len) {
1092 log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype);
1093 tor_free(signed_digest);
1094 return -1;
1096 // log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
1097 // hex_str(signed_digest,4));
1098 if (tor_memneq(digest, signed_digest, digest_len)) {
1099 log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
1100 tor_free(signed_digest);
1101 return -1;
1103 tor_free(signed_digest);
1104 return 0;
1107 /** Helper: move *<b>s_ptr</b> ahead to the next router, the next extra-info,
1108 * or to the first of the annotations proceeding the next router or
1109 * extra-info---whichever comes first. Set <b>is_extrainfo_out</b> to true if
1110 * we found an extrainfo, or false if found a router. Do not scan beyond
1111 * <b>eos</b>. Return -1 if we found nothing; 0 if we found something. */
1112 static int
1113 find_start_of_next_router_or_extrainfo(const char **s_ptr,
1114 const char *eos,
1115 int *is_extrainfo_out)
1117 const char *annotations = NULL;
1118 const char *s = *s_ptr;
1120 s = eat_whitespace_eos(s, eos);
1122 while (s < eos-32) { /* 32 gives enough room for a the first keyword. */
1123 /* We're at the start of a line. */
1124 tor_assert(*s != '\n');
1126 if (*s == '@' && !annotations) {
1127 annotations = s;
1128 } else if (*s == 'r' && !strcmpstart(s, "router ")) {
1129 *s_ptr = annotations ? annotations : s;
1130 *is_extrainfo_out = 0;
1131 return 0;
1132 } else if (*s == 'e' && !strcmpstart(s, "extra-info ")) {
1133 *s_ptr = annotations ? annotations : s;
1134 *is_extrainfo_out = 1;
1135 return 0;
1138 if (!(s = memchr(s+1, '\n', eos-(s+1))))
1139 break;
1140 s = eat_whitespace_eos(s, eos);
1142 return -1;
1145 /** Given a string *<b>s</b> containing a concatenated sequence of router
1146 * descriptors (or extra-info documents if <b>is_extrainfo</b> is set), parses
1147 * them and stores the result in <b>dest</b>. All routers are marked running
1148 * and valid. Advances *s to a point immediately following the last router
1149 * entry. Ignore any trailing router entries that are not complete.
1151 * If <b>saved_location</b> isn't SAVED_IN_CACHE, make a local copy of each
1152 * descriptor in the signed_descriptor_body field of each routerinfo_t. If it
1153 * isn't SAVED_NOWHERE, remember the offset of each descriptor.
1155 * Returns 0 on success and -1 on failure.
1158 router_parse_list_from_string(const char **s, const char *eos,
1159 smartlist_t *dest,
1160 saved_location_t saved_location,
1161 int want_extrainfo,
1162 int allow_annotations,
1163 const char *prepend_annotations)
1165 routerinfo_t *router;
1166 extrainfo_t *extrainfo;
1167 signed_descriptor_t *signed_desc;
1168 void *elt;
1169 const char *end, *start;
1170 int have_extrainfo;
1172 tor_assert(s);
1173 tor_assert(*s);
1174 tor_assert(dest);
1176 start = *s;
1177 if (!eos)
1178 eos = *s + strlen(*s);
1180 tor_assert(eos >= *s);
1182 while (1) {
1183 if (find_start_of_next_router_or_extrainfo(s, eos, &have_extrainfo) < 0)
1184 break;
1186 end = tor_memstr(*s, eos-*s, "\nrouter-signature");
1187 if (end)
1188 end = tor_memstr(end, eos-end, "\n-----END SIGNATURE-----\n");
1189 if (end)
1190 end += strlen("\n-----END SIGNATURE-----\n");
1192 if (!end)
1193 break;
1195 elt = NULL;
1197 if (have_extrainfo && want_extrainfo) {
1198 routerlist_t *rl = router_get_routerlist();
1199 extrainfo = extrainfo_parse_entry_from_string(*s, end,
1200 saved_location != SAVED_IN_CACHE,
1201 rl->identity_map);
1202 if (extrainfo) {
1203 signed_desc = &extrainfo->cache_info;
1204 elt = extrainfo;
1206 } else if (!have_extrainfo && !want_extrainfo) {
1207 router = router_parse_entry_from_string(*s, end,
1208 saved_location != SAVED_IN_CACHE,
1209 allow_annotations,
1210 prepend_annotations);
1211 if (router) {
1212 log_debug(LD_DIR, "Read router '%s', purpose '%s'",
1213 router_describe(router),
1214 router_purpose_to_string(router->purpose));
1215 signed_desc = &router->cache_info;
1216 elt = router;
1219 if (!elt) {
1220 *s = end;
1221 continue;
1223 if (saved_location != SAVED_NOWHERE) {
1224 signed_desc->saved_location = saved_location;
1225 signed_desc->saved_offset = *s - start;
1227 *s = end;
1228 smartlist_add(dest, elt);
1231 return 0;
1234 /* For debugging: define to count every descriptor digest we've seen so we
1235 * know if we need to try harder to avoid duplicate verifies. */
1236 #undef COUNT_DISTINCT_DIGESTS
1238 #ifdef COUNT_DISTINCT_DIGESTS
1239 static digestmap_t *verified_digests = NULL;
1240 #endif
1242 /** Log the total count of the number of distinct router digests we've ever
1243 * verified. When compared to the number of times we've verified routerdesc
1244 * signatures <i>in toto</i>, this will tell us if we're doing too much
1245 * multiple-verification. */
1246 void
1247 dump_distinct_digest_count(int severity)
1249 #ifdef COUNT_DISTINCT_DIGESTS
1250 if (!verified_digests)
1251 verified_digests = digestmap_new();
1252 log(severity, LD_GENERAL, "%d *distinct* router digests verified",
1253 digestmap_size(verified_digests));
1254 #else
1255 (void)severity; /* suppress "unused parameter" warning */
1256 #endif
1259 /** Helper function: reads a single router entry from *<b>s</b> ...
1260 * *<b>end</b>. Mallocs a new router and returns it if all goes well, else
1261 * returns NULL. If <b>cache_copy</b> is true, duplicate the contents of
1262 * s through end into the signed_descriptor_body of the resulting
1263 * routerinfo_t.
1265 * If <b>end</b> is NULL, <b>s</b> must be properly NUL-terminated.
1267 * If <b>allow_annotations</b>, it's okay to encounter annotations in <b>s</b>
1268 * before the router; if it's false, reject the router if it's annotated. If
1269 * <b>prepend_annotations</b> is set, it should contain some annotations:
1270 * append them to the front of the router before parsing it, and keep them
1271 * around when caching the router.
1273 * Only one of allow_annotations and prepend_annotations may be set.
1275 routerinfo_t *
1276 router_parse_entry_from_string(const char *s, const char *end,
1277 int cache_copy, int allow_annotations,
1278 const char *prepend_annotations)
1280 routerinfo_t *router = NULL;
1281 char digest[128];
1282 smartlist_t *tokens = NULL, *exit_policy_tokens = NULL;
1283 directory_token_t *tok;
1284 struct in_addr in;
1285 const char *start_of_annotations, *cp, *s_dup = s;
1286 size_t prepend_len = prepend_annotations ? strlen(prepend_annotations) : 0;
1287 int ok = 1;
1288 memarea_t *area = NULL;
1290 tor_assert(!allow_annotations || !prepend_annotations);
1292 if (!end) {
1293 end = s + strlen(s);
1296 /* point 'end' to a point immediately after the final newline. */
1297 while (end > s+2 && *(end-1) == '\n' && *(end-2) == '\n')
1298 --end;
1300 area = memarea_new();
1301 tokens = smartlist_new();
1302 if (prepend_annotations) {
1303 if (tokenize_string(area,prepend_annotations,NULL,tokens,
1304 routerdesc_token_table,TS_NOCHECK)) {
1305 log_warn(LD_DIR, "Error tokenizing router descriptor (annotations).");
1306 goto err;
1310 start_of_annotations = s;
1311 cp = tor_memstr(s, end-s, "\nrouter ");
1312 if (!cp) {
1313 if (end-s < 7 || strcmpstart(s, "router ")) {
1314 log_warn(LD_DIR, "No router keyword found.");
1315 goto err;
1317 } else {
1318 s = cp+1;
1321 if (start_of_annotations != s) { /* We have annotations */
1322 if (allow_annotations) {
1323 if (tokenize_string(area,start_of_annotations,s,tokens,
1324 routerdesc_token_table,TS_NOCHECK)) {
1325 log_warn(LD_DIR, "Error tokenizing router descriptor (annotations).");
1326 goto err;
1328 } else {
1329 log_warn(LD_DIR, "Found unexpected annotations on router descriptor not "
1330 "loaded from disk. Dropping it.");
1331 goto err;
1335 if (router_get_router_hash(s, end - s, digest) < 0) {
1336 log_warn(LD_DIR, "Couldn't compute router hash.");
1337 goto err;
1340 int flags = 0;
1341 if (allow_annotations)
1342 flags |= TS_ANNOTATIONS_OK;
1343 if (prepend_annotations)
1344 flags |= TS_ANNOTATIONS_OK|TS_NO_NEW_ANNOTATIONS;
1346 if (tokenize_string(area,s,end,tokens,routerdesc_token_table, flags)) {
1347 log_warn(LD_DIR, "Error tokenizing router descriptor.");
1348 goto err;
1352 if (smartlist_len(tokens) < 2) {
1353 log_warn(LD_DIR, "Impossibly short router descriptor.");
1354 goto err;
1357 tok = find_by_keyword(tokens, K_ROUTER);
1358 tor_assert(tok->n_args >= 5);
1360 router = tor_malloc_zero(sizeof(routerinfo_t));
1361 router->cache_info.routerlist_index = -1;
1362 router->cache_info.annotations_len = s-start_of_annotations + prepend_len;
1363 router->cache_info.signed_descriptor_len = end-s;
1364 if (cache_copy) {
1365 size_t len = router->cache_info.signed_descriptor_len +
1366 router->cache_info.annotations_len;
1367 char *cp =
1368 router->cache_info.signed_descriptor_body = tor_malloc(len+1);
1369 if (prepend_annotations) {
1370 memcpy(cp, prepend_annotations, prepend_len);
1371 cp += prepend_len;
1373 /* This assertion will always succeed.
1374 * len == signed_desc_len + annotations_len
1375 * == end-s + s-start_of_annotations + prepend_len
1376 * == end-start_of_annotations + prepend_len
1377 * We already wrote prepend_len bytes into the buffer; now we're
1378 * writing end-start_of_annotations -NM. */
1379 tor_assert(cp+(end-start_of_annotations) ==
1380 router->cache_info.signed_descriptor_body+len);
1381 memcpy(cp, start_of_annotations, end-start_of_annotations);
1382 router->cache_info.signed_descriptor_body[len] = '\0';
1383 tor_assert(strlen(router->cache_info.signed_descriptor_body) == len);
1385 memcpy(router->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
1387 router->nickname = tor_strdup(tok->args[0]);
1388 if (!is_legal_nickname(router->nickname)) {
1389 log_warn(LD_DIR,"Router nickname is invalid");
1390 goto err;
1392 router->address = tor_strdup(tok->args[1]);
1393 if (!tor_inet_aton(router->address, &in)) {
1394 log_warn(LD_DIR,"Router address is not an IP address.");
1395 goto err;
1397 router->addr = ntohl(in.s_addr);
1399 router->or_port =
1400 (uint16_t) tor_parse_long(tok->args[2],10,0,65535,&ok,NULL);
1401 if (!ok) {
1402 log_warn(LD_DIR,"Invalid OR port %s", escaped(tok->args[2]));
1403 goto err;
1405 router->dir_port =
1406 (uint16_t) tor_parse_long(tok->args[4],10,0,65535,&ok,NULL);
1407 if (!ok) {
1408 log_warn(LD_DIR,"Invalid dir port %s", escaped(tok->args[4]));
1409 goto err;
1412 tok = find_by_keyword(tokens, K_BANDWIDTH);
1413 tor_assert(tok->n_args >= 3);
1414 router->bandwidthrate = (int)
1415 tor_parse_long(tok->args[0],10,1,INT_MAX,&ok,NULL);
1417 if (!ok) {
1418 log_warn(LD_DIR, "bandwidthrate %s unreadable or 0. Failing.",
1419 escaped(tok->args[0]));
1420 goto err;
1422 router->bandwidthburst =
1423 (int) tor_parse_long(tok->args[1],10,0,INT_MAX,&ok,NULL);
1424 if (!ok) {
1425 log_warn(LD_DIR, "Invalid bandwidthburst %s", escaped(tok->args[1]));
1426 goto err;
1428 router->bandwidthcapacity = (int)
1429 tor_parse_long(tok->args[2],10,0,INT_MAX,&ok,NULL);
1430 if (!ok) {
1431 log_warn(LD_DIR, "Invalid bandwidthcapacity %s", escaped(tok->args[1]));
1432 goto err;
1435 if ((tok = find_opt_by_keyword(tokens, A_PURPOSE))) {
1436 tor_assert(tok->n_args);
1437 router->purpose = router_purpose_from_string(tok->args[0]);
1438 } else {
1439 router->purpose = ROUTER_PURPOSE_GENERAL;
1441 router->cache_info.send_unencrypted =
1442 (router->purpose == ROUTER_PURPOSE_GENERAL) ? 1 : 0;
1444 if ((tok = find_opt_by_keyword(tokens, K_UPTIME))) {
1445 tor_assert(tok->n_args >= 1);
1446 router->uptime = tor_parse_long(tok->args[0],10,0,LONG_MAX,&ok,NULL);
1447 if (!ok) {
1448 log_warn(LD_DIR, "Invalid uptime %s", escaped(tok->args[0]));
1449 goto err;
1453 if ((tok = find_opt_by_keyword(tokens, K_HIBERNATING))) {
1454 tor_assert(tok->n_args >= 1);
1455 router->is_hibernating
1456 = (tor_parse_long(tok->args[0],10,0,LONG_MAX,NULL,NULL) != 0);
1459 tok = find_by_keyword(tokens, K_PUBLISHED);
1460 tor_assert(tok->n_args == 1);
1461 if (parse_iso_time(tok->args[0], &router->cache_info.published_on) < 0)
1462 goto err;
1464 tok = find_by_keyword(tokens, K_ONION_KEY);
1465 if (!crypto_pk_public_exponent_ok(tok->key)) {
1466 log_warn(LD_DIR,
1467 "Relay's onion key had invalid exponent.");
1468 goto err;
1470 router->onion_pkey = tok->key;
1471 tok->key = NULL; /* Prevent free */
1473 tok = find_by_keyword(tokens, K_SIGNING_KEY);
1474 router->identity_pkey = tok->key;
1475 tok->key = NULL; /* Prevent free */
1476 if (crypto_pk_get_digest(router->identity_pkey,
1477 router->cache_info.identity_digest)) {
1478 log_warn(LD_DIR, "Couldn't calculate key digest"); goto err;
1481 if ((tok = find_opt_by_keyword(tokens, K_FINGERPRINT))) {
1482 /* If there's a fingerprint line, it must match the identity digest. */
1483 char d[DIGEST_LEN];
1484 tor_assert(tok->n_args == 1);
1485 tor_strstrip(tok->args[0], " ");
1486 if (base16_decode(d, DIGEST_LEN, tok->args[0], strlen(tok->args[0]))) {
1487 log_warn(LD_DIR, "Couldn't decode router fingerprint %s",
1488 escaped(tok->args[0]));
1489 goto err;
1491 if (tor_memneq(d,router->cache_info.identity_digest, DIGEST_LEN)) {
1492 log_warn(LD_DIR, "Fingerprint '%s' does not match identity digest.",
1493 tok->args[0]);
1494 goto err;
1498 if ((tok = find_opt_by_keyword(tokens, K_PLATFORM))) {
1499 router->platform = tor_strdup(tok->args[0]);
1502 if ((tok = find_opt_by_keyword(tokens, K_CONTACT))) {
1503 router->contact_info = tor_strdup(tok->args[0]);
1506 if (find_opt_by_keyword(tokens, K_REJECT6) ||
1507 find_opt_by_keyword(tokens, K_ACCEPT6)) {
1508 log_warn(LD_DIR, "Rejecting router with reject6/accept6 line: they crash "
1509 "older Tors.");
1510 goto err;
1513 smartlist_t *or_addresses = find_all_by_keyword(tokens, K_OR_ADDRESS);
1514 if (or_addresses) {
1515 SMARTLIST_FOREACH_BEGIN(or_addresses, directory_token_t *, t) {
1516 tor_addr_t a;
1517 maskbits_t bits;
1518 uint16_t port_min, port_max;
1519 /* XXXX Prop186 the full spec allows much more than this. */
1520 if (tor_addr_parse_mask_ports(t->args[0], &a, &bits, &port_min,
1521 &port_max) == AF_INET6 &&
1522 bits == 128 &&
1523 port_min == port_max) {
1524 /* Okay, this is one we can understand. */
1525 tor_addr_copy(&router->ipv6_addr, &a);
1526 router->ipv6_orport = port_min;
1527 break;
1529 } SMARTLIST_FOREACH_END(t);
1530 smartlist_free(or_addresses);
1533 exit_policy_tokens = find_all_exitpolicy(tokens);
1534 if (!smartlist_len(exit_policy_tokens)) {
1535 log_warn(LD_DIR, "No exit policy tokens in descriptor.");
1536 goto err;
1538 SMARTLIST_FOREACH(exit_policy_tokens, directory_token_t *, t,
1539 if (router_add_exit_policy(router,t)<0) {
1540 log_warn(LD_DIR,"Error in exit policy");
1541 goto err;
1543 policy_expand_private(&router->exit_policy);
1544 if (policy_is_reject_star(router->exit_policy))
1545 router->policy_is_reject_star = 1;
1547 if ((tok = find_opt_by_keyword(tokens, K_FAMILY)) && tok->n_args) {
1548 int i;
1549 router->declared_family = smartlist_new();
1550 for (i=0;i<tok->n_args;++i) {
1551 if (!is_legal_nickname_or_hexdigest(tok->args[i])) {
1552 log_warn(LD_DIR, "Illegal nickname %s in family line",
1553 escaped(tok->args[i]));
1554 goto err;
1556 smartlist_add(router->declared_family, tor_strdup(tok->args[i]));
1560 if (find_opt_by_keyword(tokens, K_CACHES_EXTRA_INFO))
1561 router->caches_extra_info = 1;
1563 if (find_opt_by_keyword(tokens, K_ALLOW_SINGLE_HOP_EXITS))
1564 router->allow_single_hop_exits = 1;
1566 if ((tok = find_opt_by_keyword(tokens, K_EXTRA_INFO_DIGEST))) {
1567 tor_assert(tok->n_args >= 1);
1568 if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {
1569 base16_decode(router->cache_info.extra_info_digest,
1570 DIGEST_LEN, tok->args[0], HEX_DIGEST_LEN);
1571 } else {
1572 log_warn(LD_DIR, "Invalid extra info digest %s", escaped(tok->args[0]));
1576 if (find_opt_by_keyword(tokens, K_HIDDEN_SERVICE_DIR)) {
1577 router->wants_to_be_hs_dir = 1;
1580 tok = find_by_keyword(tokens, K_ROUTER_SIGNATURE);
1581 note_crypto_pk_op(VERIFY_RTR);
1582 #ifdef COUNT_DISTINCT_DIGESTS
1583 if (!verified_digests)
1584 verified_digests = digestmap_new();
1585 digestmap_set(verified_digests, signed_digest, (void*)(uintptr_t)1);
1586 #endif
1587 if (check_signature_token(digest, DIGEST_LEN, tok, router->identity_pkey, 0,
1588 "router descriptor") < 0)
1589 goto err;
1591 if (!router->or_port) {
1592 log_warn(LD_DIR,"or_port unreadable or 0. Failing.");
1593 goto err;
1596 if (!router->platform) {
1597 router->platform = tor_strdup("<unknown>");
1600 goto done;
1602 err:
1603 dump_desc(s_dup, "router descriptor");
1604 routerinfo_free(router);
1605 router = NULL;
1606 done:
1607 if (tokens) {
1608 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
1609 smartlist_free(tokens);
1611 smartlist_free(exit_policy_tokens);
1612 if (area) {
1613 DUMP_AREA(area, "routerinfo");
1614 memarea_drop_all(area);
1616 return router;
1619 /** Parse a single extrainfo entry from the string <b>s</b>, ending at
1620 * <b>end</b>. (If <b>end</b> is NULL, parse up to the end of <b>s</b>.) If
1621 * <b>cache_copy</b> is true, make a copy of the extra-info document in the
1622 * cache_info fields of the result. If <b>routermap</b> is provided, use it
1623 * as a map from router identity to routerinfo_t when looking up signing keys.
1625 extrainfo_t *
1626 extrainfo_parse_entry_from_string(const char *s, const char *end,
1627 int cache_copy, struct digest_ri_map_t *routermap)
1629 extrainfo_t *extrainfo = NULL;
1630 char digest[128];
1631 smartlist_t *tokens = NULL;
1632 directory_token_t *tok;
1633 crypto_pk_t *key = NULL;
1634 routerinfo_t *router = NULL;
1635 memarea_t *area = NULL;
1636 const char *s_dup = s;
1638 if (!end) {
1639 end = s + strlen(s);
1642 /* point 'end' to a point immediately after the final newline. */
1643 while (end > s+2 && *(end-1) == '\n' && *(end-2) == '\n')
1644 --end;
1646 if (router_get_extrainfo_hash(s, end-s, digest) < 0) {
1647 log_warn(LD_DIR, "Couldn't compute router hash.");
1648 goto err;
1650 tokens = smartlist_new();
1651 area = memarea_new();
1652 if (tokenize_string(area,s,end,tokens,extrainfo_token_table,0)) {
1653 log_warn(LD_DIR, "Error tokenizing extra-info document.");
1654 goto err;
1657 if (smartlist_len(tokens) < 2) {
1658 log_warn(LD_DIR, "Impossibly short extra-info document.");
1659 goto err;
1662 tok = smartlist_get(tokens,0);
1663 if (tok->tp != K_EXTRA_INFO) {
1664 log_warn(LD_DIR,"Entry does not start with \"extra-info\"");
1665 goto err;
1668 extrainfo = tor_malloc_zero(sizeof(extrainfo_t));
1669 extrainfo->cache_info.is_extrainfo = 1;
1670 if (cache_copy)
1671 extrainfo->cache_info.signed_descriptor_body = tor_strndup(s, end-s);
1672 extrainfo->cache_info.signed_descriptor_len = end-s;
1673 memcpy(extrainfo->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
1675 tor_assert(tok->n_args >= 2);
1676 if (!is_legal_nickname(tok->args[0])) {
1677 log_warn(LD_DIR,"Bad nickname %s on \"extra-info\"",escaped(tok->args[0]));
1678 goto err;
1680 strlcpy(extrainfo->nickname, tok->args[0], sizeof(extrainfo->nickname));
1681 if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
1682 base16_decode(extrainfo->cache_info.identity_digest, DIGEST_LEN,
1683 tok->args[1], HEX_DIGEST_LEN)) {
1684 log_warn(LD_DIR,"Invalid fingerprint %s on \"extra-info\"",
1685 escaped(tok->args[1]));
1686 goto err;
1689 tok = find_by_keyword(tokens, K_PUBLISHED);
1690 if (parse_iso_time(tok->args[0], &extrainfo->cache_info.published_on)) {
1691 log_warn(LD_DIR,"Invalid published time %s on \"extra-info\"",
1692 escaped(tok->args[0]));
1693 goto err;
1696 if (routermap &&
1697 (router = digestmap_get((digestmap_t*)routermap,
1698 extrainfo->cache_info.identity_digest))) {
1699 key = router->identity_pkey;
1702 tok = find_by_keyword(tokens, K_ROUTER_SIGNATURE);
1703 if (strcmp(tok->object_type, "SIGNATURE") ||
1704 tok->object_size < 128 || tok->object_size > 512) {
1705 log_warn(LD_DIR, "Bad object type or length on extra-info signature");
1706 goto err;
1709 if (key) {
1710 note_crypto_pk_op(VERIFY_RTR);
1711 if (check_signature_token(digest, DIGEST_LEN, tok, key, 0,
1712 "extra-info") < 0)
1713 goto err;
1715 if (router)
1716 extrainfo->cache_info.send_unencrypted =
1717 router->cache_info.send_unencrypted;
1718 } else {
1719 extrainfo->pending_sig = tor_memdup(tok->object_body,
1720 tok->object_size);
1721 extrainfo->pending_sig_len = tok->object_size;
1724 goto done;
1725 err:
1726 dump_desc(s_dup, "extra-info descriptor");
1727 extrainfo_free(extrainfo);
1728 extrainfo = NULL;
1729 done:
1730 if (tokens) {
1731 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
1732 smartlist_free(tokens);
1734 if (area) {
1735 DUMP_AREA(area, "extrainfo");
1736 memarea_drop_all(area);
1738 return extrainfo;
1741 /** Parse a key certificate from <b>s</b>; point <b>end-of-string</b> to
1742 * the first character after the certificate. */
1743 authority_cert_t *
1744 authority_cert_parse_from_string(const char *s, const char **end_of_string)
1746 /** Reject any certificate at least this big; it is probably an overflow, an
1747 * attack, a bug, or some other nonsense. */
1748 #define MAX_CERT_SIZE (128*1024)
1750 authority_cert_t *cert = NULL, *old_cert;
1751 smartlist_t *tokens = NULL;
1752 char digest[DIGEST_LEN];
1753 directory_token_t *tok;
1754 char fp_declared[DIGEST_LEN];
1755 char *eos;
1756 size_t len;
1757 int found;
1758 memarea_t *area = NULL;
1759 const char *s_dup = s;
1761 s = eat_whitespace(s);
1762 eos = strstr(s, "\ndir-key-certification");
1763 if (! eos) {
1764 log_warn(LD_DIR, "No signature found on key certificate");
1765 return NULL;
1767 eos = strstr(eos, "\n-----END SIGNATURE-----\n");
1768 if (! eos) {
1769 log_warn(LD_DIR, "No end-of-signature found on key certificate");
1770 return NULL;
1772 eos = strchr(eos+2, '\n');
1773 tor_assert(eos);
1774 ++eos;
1775 len = eos - s;
1777 if (len > MAX_CERT_SIZE) {
1778 log_warn(LD_DIR, "Certificate is far too big (at %lu bytes long); "
1779 "rejecting", (unsigned long)len);
1780 return NULL;
1783 tokens = smartlist_new();
1784 area = memarea_new();
1785 if (tokenize_string(area,s, eos, tokens, dir_key_certificate_table, 0) < 0) {
1786 log_warn(LD_DIR, "Error tokenizing key certificate");
1787 goto err;
1789 if (router_get_hash_impl(s, strlen(s), digest, "dir-key-certificate-version",
1790 "\ndir-key-certification", '\n', DIGEST_SHA1) < 0)
1791 goto err;
1792 tok = smartlist_get(tokens, 0);
1793 if (tok->tp != K_DIR_KEY_CERTIFICATE_VERSION || strcmp(tok->args[0], "3")) {
1794 log_warn(LD_DIR,
1795 "Key certificate does not begin with a recognized version (3).");
1796 goto err;
1799 cert = tor_malloc_zero(sizeof(authority_cert_t));
1800 memcpy(cert->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
1802 tok = find_by_keyword(tokens, K_DIR_SIGNING_KEY);
1803 tor_assert(tok->key);
1804 cert->signing_key = tok->key;
1805 tok->key = NULL;
1806 if (crypto_pk_get_digest(cert->signing_key, cert->signing_key_digest))
1807 goto err;
1809 tok = find_by_keyword(tokens, K_DIR_IDENTITY_KEY);
1810 tor_assert(tok->key);
1811 cert->identity_key = tok->key;
1812 tok->key = NULL;
1814 tok = find_by_keyword(tokens, K_FINGERPRINT);
1815 tor_assert(tok->n_args);
1816 if (base16_decode(fp_declared, DIGEST_LEN, tok->args[0],
1817 strlen(tok->args[0]))) {
1818 log_warn(LD_DIR, "Couldn't decode key certificate fingerprint %s",
1819 escaped(tok->args[0]));
1820 goto err;
1823 if (crypto_pk_get_digest(cert->identity_key,
1824 cert->cache_info.identity_digest))
1825 goto err;
1827 if (tor_memneq(cert->cache_info.identity_digest, fp_declared, DIGEST_LEN)) {
1828 log_warn(LD_DIR, "Digest of certificate key didn't match declared "
1829 "fingerprint");
1830 goto err;
1833 tok = find_opt_by_keyword(tokens, K_DIR_ADDRESS);
1834 if (tok) {
1835 struct in_addr in;
1836 char *address = NULL;
1837 tor_assert(tok->n_args);
1838 /* XXX023 use some tor_addr parse function below instead. -RD */
1839 if (tor_addr_port_split(LOG_WARN, tok->args[0], &address,
1840 &cert->dir_port) < 0 ||
1841 tor_inet_aton(address, &in) == 0) {
1842 log_warn(LD_DIR, "Couldn't parse dir-address in certificate");
1843 tor_free(address);
1844 goto err;
1846 cert->addr = ntohl(in.s_addr);
1847 tor_free(address);
1850 tok = find_by_keyword(tokens, K_DIR_KEY_PUBLISHED);
1851 if (parse_iso_time(tok->args[0], &cert->cache_info.published_on) < 0) {
1852 goto err;
1854 tok = find_by_keyword(tokens, K_DIR_KEY_EXPIRES);
1855 if (parse_iso_time(tok->args[0], &cert->expires) < 0) {
1856 goto err;
1859 tok = smartlist_get(tokens, smartlist_len(tokens)-1);
1860 if (tok->tp != K_DIR_KEY_CERTIFICATION) {
1861 log_warn(LD_DIR, "Certificate didn't end with dir-key-certification.");
1862 goto err;
1865 /* If we already have this cert, don't bother checking the signature. */
1866 old_cert = authority_cert_get_by_digests(
1867 cert->cache_info.identity_digest,
1868 cert->signing_key_digest);
1869 found = 0;
1870 if (old_cert) {
1871 /* XXXX We could just compare signed_descriptor_digest, but that wouldn't
1872 * buy us much. */
1873 if (old_cert->cache_info.signed_descriptor_len == len &&
1874 old_cert->cache_info.signed_descriptor_body &&
1875 tor_memeq(s, old_cert->cache_info.signed_descriptor_body, len)) {
1876 log_debug(LD_DIR, "We already checked the signature on this "
1877 "certificate; no need to do so again.");
1878 found = 1;
1879 cert->is_cross_certified = old_cert->is_cross_certified;
1882 if (!found) {
1883 if (check_signature_token(digest, DIGEST_LEN, tok, cert->identity_key, 0,
1884 "key certificate")) {
1885 goto err;
1888 if ((tok = find_opt_by_keyword(tokens, K_DIR_KEY_CROSSCERT))) {
1889 /* XXXX Once all authorities generate cross-certified certificates,
1890 * make this field mandatory. */
1891 if (check_signature_token(cert->cache_info.identity_digest,
1892 DIGEST_LEN,
1893 tok,
1894 cert->signing_key,
1895 CST_NO_CHECK_OBJTYPE,
1896 "key cross-certification")) {
1897 goto err;
1899 cert->is_cross_certified = 1;
1903 cert->cache_info.signed_descriptor_len = len;
1904 cert->cache_info.signed_descriptor_body = tor_malloc(len+1);
1905 memcpy(cert->cache_info.signed_descriptor_body, s, len);
1906 cert->cache_info.signed_descriptor_body[len] = 0;
1907 cert->cache_info.saved_location = SAVED_NOWHERE;
1909 if (end_of_string) {
1910 *end_of_string = eat_whitespace(eos);
1912 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
1913 smartlist_free(tokens);
1914 if (area) {
1915 DUMP_AREA(area, "authority cert");
1916 memarea_drop_all(area);
1918 return cert;
1919 err:
1920 dump_desc(s_dup, "authority cert");
1921 authority_cert_free(cert);
1922 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
1923 smartlist_free(tokens);
1924 if (area) {
1925 DUMP_AREA(area, "authority cert");
1926 memarea_drop_all(area);
1928 return NULL;
1931 /** Helper: given a string <b>s</b>, return the start of the next router-status
1932 * object (starting with "r " at the start of a line). If none is found,
1933 * return the start of the directory footer, or the next directory signature.
1934 * If none is found, return the end of the string. */
1935 static INLINE const char *
1936 find_start_of_next_routerstatus(const char *s)
1938 const char *eos, *footer, *sig;
1939 if ((eos = strstr(s, "\nr ")))
1940 ++eos;
1941 else
1942 eos = s + strlen(s);
1944 footer = tor_memstr(s, eos-s, "\ndirectory-footer");
1945 sig = tor_memstr(s, eos-s, "\ndirectory-signature");
1947 if (footer && sig)
1948 return MIN(footer, sig) + 1;
1949 else if (footer)
1950 return footer+1;
1951 else if (sig)
1952 return sig+1;
1953 else
1954 return eos;
1957 /** Given a string at *<b>s</b>, containing a routerstatus object, and an
1958 * empty smartlist at <b>tokens</b>, parse and return the first router status
1959 * object in the string, and advance *<b>s</b> to just after the end of the
1960 * router status. Return NULL and advance *<b>s</b> on error.
1962 * If <b>vote</b> and <b>vote_rs</b> are provided, don't allocate a fresh
1963 * routerstatus but use <b>vote_rs</b> instead.
1965 * If <b>consensus_method</b> is nonzero, this routerstatus is part of a
1966 * consensus, and we should parse it according to the method used to
1967 * make that consensus.
1969 * Parse according to the syntax used by the consensus flavor <b>flav</b>.
1971 static routerstatus_t *
1972 routerstatus_parse_entry_from_string(memarea_t *area,
1973 const char **s, smartlist_t *tokens,
1974 networkstatus_t *vote,
1975 vote_routerstatus_t *vote_rs,
1976 int consensus_method,
1977 consensus_flavor_t flav)
1979 const char *eos, *s_dup = *s;
1980 routerstatus_t *rs = NULL;
1981 directory_token_t *tok;
1982 char timebuf[ISO_TIME_LEN+1];
1983 struct in_addr in;
1984 int offset = 0;
1985 tor_assert(tokens);
1986 tor_assert(bool_eq(vote, vote_rs));
1988 if (!consensus_method)
1989 flav = FLAV_NS;
1990 tor_assert(flav == FLAV_NS || flav == FLAV_MICRODESC);
1992 eos = find_start_of_next_routerstatus(*s);
1994 if (tokenize_string(area,*s, eos, tokens, rtrstatus_token_table,0)) {
1995 log_warn(LD_DIR, "Error tokenizing router status");
1996 goto err;
1998 if (smartlist_len(tokens) < 1) {
1999 log_warn(LD_DIR, "Impossibly short router status");
2000 goto err;
2002 tok = find_by_keyword(tokens, K_R);
2003 tor_assert(tok->n_args >= 7); /* guaranteed by GE(7) in K_R setup */
2004 if (flav == FLAV_NS) {
2005 if (tok->n_args < 8) {
2006 log_warn(LD_DIR, "Too few arguments to r");
2007 goto err;
2009 } else if (flav == FLAV_MICRODESC) {
2010 offset = -1; /* There is no identity digest */
2013 if (vote_rs) {
2014 rs = &vote_rs->status;
2015 } else {
2016 rs = tor_malloc_zero(sizeof(routerstatus_t));
2019 if (!is_legal_nickname(tok->args[0])) {
2020 log_warn(LD_DIR,
2021 "Invalid nickname %s in router status; skipping.",
2022 escaped(tok->args[0]));
2023 goto err;
2025 strlcpy(rs->nickname, tok->args[0], sizeof(rs->nickname));
2027 if (digest_from_base64(rs->identity_digest, tok->args[1])) {
2028 log_warn(LD_DIR, "Error decoding identity digest %s",
2029 escaped(tok->args[1]));
2030 goto err;
2033 if (flav == FLAV_NS) {
2034 if (digest_from_base64(rs->descriptor_digest, tok->args[2])) {
2035 log_warn(LD_DIR, "Error decoding descriptor digest %s",
2036 escaped(tok->args[2]));
2037 goto err;
2041 if (tor_snprintf(timebuf, sizeof(timebuf), "%s %s",
2042 tok->args[3+offset], tok->args[4+offset]) < 0 ||
2043 parse_iso_time(timebuf, &rs->published_on)<0) {
2044 log_warn(LD_DIR, "Error parsing time '%s %s' [%d %d]",
2045 tok->args[3+offset], tok->args[4+offset],
2046 offset, (int)flav);
2047 goto err;
2050 if (tor_inet_aton(tok->args[5+offset], &in) == 0) {
2051 log_warn(LD_DIR, "Error parsing router address in network-status %s",
2052 escaped(tok->args[5+offset]));
2053 goto err;
2055 rs->addr = ntohl(in.s_addr);
2057 rs->or_port = (uint16_t) tor_parse_long(tok->args[6+offset],
2058 10,0,65535,NULL,NULL);
2059 rs->dir_port = (uint16_t) tor_parse_long(tok->args[7+offset],
2060 10,0,65535,NULL,NULL);
2062 tok = find_opt_by_keyword(tokens, K_S);
2063 if (tok && vote) {
2064 int i;
2065 vote_rs->flags = 0;
2066 for (i=0; i < tok->n_args; ++i) {
2067 int p = smartlist_string_pos(vote->known_flags, tok->args[i]);
2068 if (p >= 0) {
2069 vote_rs->flags |= (1<<p);
2070 } else {
2071 log_warn(LD_DIR, "Flags line had a flag %s not listed in known_flags.",
2072 escaped(tok->args[i]));
2073 goto err;
2076 } else if (tok) {
2077 int i;
2078 for (i=0; i < tok->n_args; ++i) {
2079 if (!strcmp(tok->args[i], "Exit"))
2080 rs->is_exit = 1;
2081 else if (!strcmp(tok->args[i], "Stable"))
2082 rs->is_stable = 1;
2083 else if (!strcmp(tok->args[i], "Fast"))
2084 rs->is_fast = 1;
2085 else if (!strcmp(tok->args[i], "Running"))
2086 rs->is_flagged_running = 1;
2087 else if (!strcmp(tok->args[i], "Named"))
2088 rs->is_named = 1;
2089 else if (!strcmp(tok->args[i], "Valid"))
2090 rs->is_valid = 1;
2091 else if (!strcmp(tok->args[i], "V2Dir"))
2092 rs->is_v2_dir = 1;
2093 else if (!strcmp(tok->args[i], "Guard"))
2094 rs->is_possible_guard = 1;
2095 else if (!strcmp(tok->args[i], "BadExit"))
2096 rs->is_bad_exit = 1;
2097 else if (!strcmp(tok->args[i], "BadDirectory"))
2098 rs->is_bad_directory = 1;
2099 else if (!strcmp(tok->args[i], "Authority"))
2100 rs->is_authority = 1;
2101 else if (!strcmp(tok->args[i], "Unnamed") &&
2102 consensus_method >= 2) {
2103 /* Unnamed is computed right by consensus method 2 and later. */
2104 rs->is_unnamed = 1;
2105 } else if (!strcmp(tok->args[i], "HSDir")) {
2106 rs->is_hs_dir = 1;
2110 if ((tok = find_opt_by_keyword(tokens, K_V))) {
2111 tor_assert(tok->n_args == 1);
2112 rs->version_known = 1;
2113 if (strcmpstart(tok->args[0], "Tor ")) {
2114 rs->version_supports_begindir = 1;
2115 rs->version_supports_extrainfo_upload = 1;
2116 rs->version_supports_conditional_consensus = 1;
2117 rs->version_supports_microdesc_cache = 1;
2118 rs->version_supports_optimistic_data = 1;
2119 } else {
2120 rs->version_supports_begindir =
2121 tor_version_as_new_as(tok->args[0], "0.2.0.1-alpha");
2122 rs->version_supports_extrainfo_upload =
2123 tor_version_as_new_as(tok->args[0], "0.2.0.0-alpha-dev (r10070)");
2124 rs->version_supports_v3_dir =
2125 tor_version_as_new_as(tok->args[0], "0.2.0.8-alpha");
2126 rs->version_supports_conditional_consensus =
2127 tor_version_as_new_as(tok->args[0], "0.2.1.1-alpha");
2128 rs->version_supports_microdesc_cache =
2129 tor_version_supports_microdescriptors(tok->args[0]);
2130 rs->version_supports_optimistic_data =
2131 tor_version_as_new_as(tok->args[0], "0.2.3.1-alpha");
2133 if (vote_rs) {
2134 vote_rs->version = tor_strdup(tok->args[0]);
2138 /* handle weighting/bandwidth info */
2139 if ((tok = find_opt_by_keyword(tokens, K_W))) {
2140 int i;
2141 for (i=0; i < tok->n_args; ++i) {
2142 if (!strcmpstart(tok->args[i], "Bandwidth=")) {
2143 int ok;
2144 rs->bandwidth = (uint32_t)tor_parse_ulong(strchr(tok->args[i], '=')+1,
2145 10, 0, UINT32_MAX,
2146 &ok, NULL);
2147 if (!ok) {
2148 log_warn(LD_DIR, "Invalid Bandwidth %s", escaped(tok->args[i]));
2149 goto err;
2151 rs->has_bandwidth = 1;
2152 } else if (!strcmpstart(tok->args[i], "Measured=")) {
2153 int ok;
2154 rs->measured_bw =
2155 (uint32_t)tor_parse_ulong(strchr(tok->args[i], '=')+1,
2156 10, 0, UINT32_MAX, &ok, NULL);
2157 if (!ok) {
2158 log_warn(LD_DIR, "Invalid Measured Bandwidth %s",
2159 escaped(tok->args[i]));
2160 goto err;
2162 rs->has_measured_bw = 1;
2167 /* parse exit policy summaries */
2168 if ((tok = find_opt_by_keyword(tokens, K_P))) {
2169 tor_assert(tok->n_args == 1);
2170 if (strcmpstart(tok->args[0], "accept ") &&
2171 strcmpstart(tok->args[0], "reject ")) {
2172 log_warn(LD_DIR, "Unknown exit policy summary type %s.",
2173 escaped(tok->args[0]));
2174 goto err;
2176 /* XXX weasel: parse this into ports and represent them somehow smart,
2177 * maybe not here but somewhere on if we need it for the client.
2178 * we should still parse it here to check it's valid tho.
2180 rs->exitsummary = tor_strdup(tok->args[0]);
2181 rs->has_exitsummary = 1;
2184 if (vote_rs) {
2185 SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, t) {
2186 if (t->tp == K_M && t->n_args) {
2187 vote_microdesc_hash_t *line =
2188 tor_malloc(sizeof(vote_microdesc_hash_t));
2189 line->next = vote_rs->microdesc;
2190 line->microdesc_hash_line = tor_strdup(t->args[0]);
2191 vote_rs->microdesc = line;
2193 } SMARTLIST_FOREACH_END(t);
2194 } else if (flav == FLAV_MICRODESC) {
2195 tok = find_opt_by_keyword(tokens, K_M);
2196 if (tok) {
2197 tor_assert(tok->n_args);
2198 if (digest256_from_base64(rs->descriptor_digest, tok->args[0])) {
2199 log_warn(LD_DIR, "Error decoding microdescriptor digest %s",
2200 escaped(tok->args[0]));
2201 goto err;
2206 if (!strcasecmp(rs->nickname, UNNAMED_ROUTER_NICKNAME))
2207 rs->is_named = 0;
2209 goto done;
2210 err:
2211 dump_desc(s_dup, "routerstatus entry");
2212 if (rs && !vote_rs)
2213 routerstatus_free(rs);
2214 rs = NULL;
2215 done:
2216 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
2217 smartlist_clear(tokens);
2218 if (area) {
2219 DUMP_AREA(area, "routerstatus entry");
2220 memarea_clear(area);
2222 *s = eos;
2224 return rs;
2227 /** Helper to sort a smartlist of pointers to routerstatus_t */
2229 compare_routerstatus_entries(const void **_a, const void **_b)
2231 const routerstatus_t *a = *_a, *b = *_b;
2232 return fast_memcmp(a->identity_digest, b->identity_digest, DIGEST_LEN);
2235 /** Helper: used in call to _smartlist_uniq to clear out duplicate entries. */
2236 static void
2237 _free_duplicate_routerstatus_entry(void *e)
2239 log_warn(LD_DIR,
2240 "Network-status has two entries for the same router. "
2241 "Dropping one.");
2242 routerstatus_free(e);
2245 /** Given a v2 network-status object in <b>s</b>, try to
2246 * parse it and return the result. Return NULL on failure. Check the
2247 * signature of the network status, but do not (yet) check the signing key for
2248 * authority.
2250 networkstatus_v2_t *
2251 networkstatus_v2_parse_from_string(const char *s)
2253 const char *eos, *s_dup = s;
2254 smartlist_t *tokens = smartlist_new();
2255 smartlist_t *footer_tokens = smartlist_new();
2256 networkstatus_v2_t *ns = NULL;
2257 char ns_digest[DIGEST_LEN];
2258 char tmp_digest[DIGEST_LEN];
2259 struct in_addr in;
2260 directory_token_t *tok;
2261 int i;
2262 memarea_t *area = NULL;
2264 if (router_get_networkstatus_v2_hash(s, ns_digest)) {
2265 log_warn(LD_DIR, "Unable to compute digest of network-status");
2266 goto err;
2269 area = memarea_new();
2270 eos = find_start_of_next_routerstatus(s);
2271 if (tokenize_string(area, s, eos, tokens, netstatus_token_table,0)) {
2272 log_warn(LD_DIR, "Error tokenizing network-status header.");
2273 goto err;
2275 ns = tor_malloc_zero(sizeof(networkstatus_v2_t));
2276 memcpy(ns->networkstatus_digest, ns_digest, DIGEST_LEN);
2278 tok = find_by_keyword(tokens, K_NETWORK_STATUS_VERSION);
2279 tor_assert(tok->n_args >= 1);
2280 if (strcmp(tok->args[0], "2")) {
2281 log_warn(LD_BUG, "Got a non-v2 networkstatus. Version was "
2282 "%s", escaped(tok->args[0]));
2283 goto err;
2286 tok = find_by_keyword(tokens, K_DIR_SOURCE);
2287 tor_assert(tok->n_args >= 3);
2288 ns->source_address = tor_strdup(tok->args[0]);
2289 if (tor_inet_aton(tok->args[1], &in) == 0) {
2290 log_warn(LD_DIR, "Error parsing network-status source address %s",
2291 escaped(tok->args[1]));
2292 goto err;
2294 ns->source_addr = ntohl(in.s_addr);
2295 ns->source_dirport =
2296 (uint16_t) tor_parse_long(tok->args[2],10,0,65535,NULL,NULL);
2297 if (ns->source_dirport == 0) {
2298 log_warn(LD_DIR, "Directory source without dirport; skipping.");
2299 goto err;
2302 tok = find_by_keyword(tokens, K_FINGERPRINT);
2303 tor_assert(tok->n_args);
2304 if (base16_decode(ns->identity_digest, DIGEST_LEN, tok->args[0],
2305 strlen(tok->args[0]))) {
2306 log_warn(LD_DIR, "Couldn't decode networkstatus fingerprint %s",
2307 escaped(tok->args[0]));
2308 goto err;
2311 if ((tok = find_opt_by_keyword(tokens, K_CONTACT))) {
2312 tor_assert(tok->n_args);
2313 ns->contact = tor_strdup(tok->args[0]);
2316 tok = find_by_keyword(tokens, K_DIR_SIGNING_KEY);
2317 tor_assert(tok->key);
2318 ns->signing_key = tok->key;
2319 tok->key = NULL;
2321 if (crypto_pk_get_digest(ns->signing_key, tmp_digest)<0) {
2322 log_warn(LD_DIR, "Couldn't compute signing key digest");
2323 goto err;
2325 if (tor_memneq(tmp_digest, ns->identity_digest, DIGEST_LEN)) {
2326 log_warn(LD_DIR,
2327 "network-status fingerprint did not match dir-signing-key");
2328 goto err;
2331 if ((tok = find_opt_by_keyword(tokens, K_DIR_OPTIONS))) {
2332 for (i=0; i < tok->n_args; ++i) {
2333 if (!strcmp(tok->args[i], "Names"))
2334 ns->binds_names = 1;
2335 if (!strcmp(tok->args[i], "Versions"))
2336 ns->recommends_versions = 1;
2337 if (!strcmp(tok->args[i], "BadExits"))
2338 ns->lists_bad_exits = 1;
2339 if (!strcmp(tok->args[i], "BadDirectories"))
2340 ns->lists_bad_directories = 1;
2344 if (ns->recommends_versions) {
2345 if (!(tok = find_opt_by_keyword(tokens, K_CLIENT_VERSIONS))) {
2346 log_warn(LD_DIR, "Missing client-versions on versioning directory");
2347 goto err;
2349 ns->client_versions = tor_strdup(tok->args[0]);
2351 if (!(tok = find_opt_by_keyword(tokens, K_SERVER_VERSIONS)) ||
2352 tok->n_args<1) {
2353 log_warn(LD_DIR, "Missing server-versions on versioning directory");
2354 goto err;
2356 ns->server_versions = tor_strdup(tok->args[0]);
2359 tok = find_by_keyword(tokens, K_PUBLISHED);
2360 tor_assert(tok->n_args == 1);
2361 if (parse_iso_time(tok->args[0], &ns->published_on) < 0) {
2362 goto err;
2365 ns->entries = smartlist_new();
2366 s = eos;
2367 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
2368 smartlist_clear(tokens);
2369 memarea_clear(area);
2370 while (!strcmpstart(s, "r ")) {
2371 routerstatus_t *rs;
2372 if ((rs = routerstatus_parse_entry_from_string(area, &s, tokens,
2373 NULL, NULL, 0, 0)))
2374 smartlist_add(ns->entries, rs);
2376 smartlist_sort(ns->entries, compare_routerstatus_entries);
2377 smartlist_uniq(ns->entries, compare_routerstatus_entries,
2378 _free_duplicate_routerstatus_entry);
2380 if (tokenize_string(area,s, NULL, footer_tokens, dir_footer_token_table,0)) {
2381 log_warn(LD_DIR, "Error tokenizing network-status footer.");
2382 goto err;
2384 if (smartlist_len(footer_tokens) < 1) {
2385 log_warn(LD_DIR, "Too few items in network-status footer.");
2386 goto err;
2388 tok = smartlist_get(footer_tokens, smartlist_len(footer_tokens)-1);
2389 if (tok->tp != K_DIRECTORY_SIGNATURE) {
2390 log_warn(LD_DIR,
2391 "Expected network-status footer to end with a signature.");
2392 goto err;
2395 note_crypto_pk_op(VERIFY_DIR);
2396 if (check_signature_token(ns_digest, DIGEST_LEN, tok, ns->signing_key, 0,
2397 "network-status") < 0)
2398 goto err;
2400 goto done;
2401 err:
2402 dump_desc(s_dup, "v2 networkstatus");
2403 networkstatus_v2_free(ns);
2404 ns = NULL;
2405 done:
2406 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
2407 smartlist_free(tokens);
2408 SMARTLIST_FOREACH(footer_tokens, directory_token_t *, t, token_clear(t));
2409 smartlist_free(footer_tokens);
2410 if (area) {
2411 DUMP_AREA(area, "v2 networkstatus");
2412 memarea_drop_all(area);
2414 return ns;
2417 /** Verify the bandwidth weights of a network status document */
2419 networkstatus_verify_bw_weights(networkstatus_t *ns)
2421 int64_t weight_scale;
2422 int64_t G=0, M=0, E=0, D=0, T=0;
2423 double Wgg, Wgm, Wgd, Wmg, Wmm, Wme, Wmd, Weg, Wem, Wee, Wed;
2424 double Gtotal=0, Mtotal=0, Etotal=0;
2425 const char *casename = NULL;
2426 int valid = 1;
2428 weight_scale = circuit_build_times_get_bw_scale(ns);
2429 Wgg = networkstatus_get_bw_weight(ns, "Wgg", -1);
2430 Wgm = networkstatus_get_bw_weight(ns, "Wgm", -1);
2431 Wgd = networkstatus_get_bw_weight(ns, "Wgd", -1);
2432 Wmg = networkstatus_get_bw_weight(ns, "Wmg", -1);
2433 Wmm = networkstatus_get_bw_weight(ns, "Wmm", -1);
2434 Wme = networkstatus_get_bw_weight(ns, "Wme", -1);
2435 Wmd = networkstatus_get_bw_weight(ns, "Wmd", -1);
2436 Weg = networkstatus_get_bw_weight(ns, "Weg", -1);
2437 Wem = networkstatus_get_bw_weight(ns, "Wem", -1);
2438 Wee = networkstatus_get_bw_weight(ns, "Wee", -1);
2439 Wed = networkstatus_get_bw_weight(ns, "Wed", -1);
2441 if (Wgg<0 || Wgm<0 || Wgd<0 || Wmg<0 || Wmm<0 || Wme<0 || Wmd<0 || Weg<0
2442 || Wem<0 || Wee<0 || Wed<0) {
2443 log_warn(LD_BUG, "No bandwidth weights produced in consensus!");
2444 return 0;
2447 // First, sanity check basic summing properties that hold for all cases
2448 // We use > 1 as the check for these because they are computed as integers.
2449 // Sometimes there are rounding errors.
2450 if (fabs(Wmm - weight_scale) > 1) {
2451 log_warn(LD_BUG, "Wmm=%f != "I64_FORMAT,
2452 Wmm, I64_PRINTF_ARG(weight_scale));
2453 valid = 0;
2456 if (fabs(Wem - Wee) > 1) {
2457 log_warn(LD_BUG, "Wem=%f != Wee=%f", Wem, Wee);
2458 valid = 0;
2461 if (fabs(Wgm - Wgg) > 1) {
2462 log_warn(LD_BUG, "Wgm=%f != Wgg=%f", Wgm, Wgg);
2463 valid = 0;
2466 if (fabs(Weg - Wed) > 1) {
2467 log_warn(LD_BUG, "Wed=%f != Weg=%f", Wed, Weg);
2468 valid = 0;
2471 if (fabs(Wgg + Wmg - weight_scale) > 0.001*weight_scale) {
2472 log_warn(LD_BUG, "Wgg=%f != "I64_FORMAT" - Wmg=%f", Wgg,
2473 I64_PRINTF_ARG(weight_scale), Wmg);
2474 valid = 0;
2477 if (fabs(Wee + Wme - weight_scale) > 0.001*weight_scale) {
2478 log_warn(LD_BUG, "Wee=%f != "I64_FORMAT" - Wme=%f", Wee,
2479 I64_PRINTF_ARG(weight_scale), Wme);
2480 valid = 0;
2483 if (fabs(Wgd + Wmd + Wed - weight_scale) > 0.001*weight_scale) {
2484 log_warn(LD_BUG, "Wgd=%f + Wmd=%f + Wed=%f != "I64_FORMAT,
2485 Wgd, Wmd, Wed, I64_PRINTF_ARG(weight_scale));
2486 valid = 0;
2489 Wgg /= weight_scale;
2490 Wgm /= weight_scale;
2491 Wgd /= weight_scale;
2493 Wmg /= weight_scale;
2494 Wmm /= weight_scale;
2495 Wme /= weight_scale;
2496 Wmd /= weight_scale;
2498 Weg /= weight_scale;
2499 Wem /= weight_scale;
2500 Wee /= weight_scale;
2501 Wed /= weight_scale;
2503 // Then, gather G, M, E, D, T to determine case
2504 SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) {
2505 if (rs->has_bandwidth) {
2506 T += rs->bandwidth;
2507 if (rs->is_exit && rs->is_possible_guard) {
2508 D += rs->bandwidth;
2509 Gtotal += Wgd*rs->bandwidth;
2510 Mtotal += Wmd*rs->bandwidth;
2511 Etotal += Wed*rs->bandwidth;
2512 } else if (rs->is_exit) {
2513 E += rs->bandwidth;
2514 Mtotal += Wme*rs->bandwidth;
2515 Etotal += Wee*rs->bandwidth;
2516 } else if (rs->is_possible_guard) {
2517 G += rs->bandwidth;
2518 Gtotal += Wgg*rs->bandwidth;
2519 Mtotal += Wmg*rs->bandwidth;
2520 } else {
2521 M += rs->bandwidth;
2522 Mtotal += Wmm*rs->bandwidth;
2524 } else {
2525 log_warn(LD_BUG, "Missing consensus bandwidth for router %s",
2526 routerstatus_describe(rs));
2528 } SMARTLIST_FOREACH_END(rs);
2530 // Finally, check equality conditions depending upon case 1, 2 or 3
2531 // Full equality cases: 1, 3b
2532 // Partial equality cases: 2b (E=G), 3a (M=E)
2533 // Fully unknown: 2a
2534 if (3*E >= T && 3*G >= T) {
2535 // Case 1: Neither are scarce
2536 casename = "Case 1";
2537 if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
2538 log_warn(LD_DIR,
2539 "Bw Weight Failure for %s: Etotal %f != Mtotal %f. "
2540 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
2541 " T="I64_FORMAT". "
2542 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2543 casename, Etotal, Mtotal,
2544 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2545 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2546 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2547 valid = 0;
2549 if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
2550 log_warn(LD_DIR,
2551 "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
2552 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
2553 " T="I64_FORMAT". "
2554 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2555 casename, Etotal, Gtotal,
2556 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2557 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2558 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2559 valid = 0;
2561 if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
2562 log_warn(LD_DIR,
2563 "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. "
2564 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
2565 " T="I64_FORMAT". "
2566 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2567 casename, Mtotal, Gtotal,
2568 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2569 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2570 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2571 valid = 0;
2573 } else if (3*E < T && 3*G < T) {
2574 int64_t R = MIN(E, G);
2575 int64_t S = MAX(E, G);
2577 * Case 2: Both Guards and Exits are scarce
2578 * Balance D between E and G, depending upon
2579 * D capacity and scarcity. Devote no extra
2580 * bandwidth to middle nodes.
2582 if (R+D < S) { // Subcase a
2583 double Rtotal, Stotal;
2584 if (E < G) {
2585 Rtotal = Etotal;
2586 Stotal = Gtotal;
2587 } else {
2588 Rtotal = Gtotal;
2589 Stotal = Etotal;
2591 casename = "Case 2a";
2592 // Rtotal < Stotal
2593 if (Rtotal > Stotal) {
2594 log_warn(LD_DIR,
2595 "Bw Weight Failure for %s: Rtotal %f > Stotal %f. "
2596 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
2597 " T="I64_FORMAT". "
2598 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2599 casename, Rtotal, Stotal,
2600 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2601 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2602 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2603 valid = 0;
2605 // Rtotal < T/3
2606 if (3*Rtotal > T) {
2607 log_warn(LD_DIR,
2608 "Bw Weight Failure for %s: 3*Rtotal %f > T "
2609 I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
2610 " D="I64_FORMAT" T="I64_FORMAT". "
2611 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2612 casename, Rtotal*3, I64_PRINTF_ARG(T),
2613 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2614 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2615 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2616 valid = 0;
2618 // Stotal < T/3
2619 if (3*Stotal > T) {
2620 log_warn(LD_DIR,
2621 "Bw Weight Failure for %s: 3*Stotal %f > T "
2622 I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
2623 " D="I64_FORMAT" T="I64_FORMAT". "
2624 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2625 casename, Stotal*3, I64_PRINTF_ARG(T),
2626 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2627 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2628 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2629 valid = 0;
2631 // Mtotal > T/3
2632 if (3*Mtotal < T) {
2633 log_warn(LD_DIR,
2634 "Bw Weight Failure for %s: 3*Mtotal %f < T "
2635 I64_FORMAT". "
2636 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
2637 " T="I64_FORMAT". "
2638 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2639 casename, Mtotal*3, I64_PRINTF_ARG(T),
2640 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2641 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2642 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2643 valid = 0;
2645 } else { // Subcase b: R+D > S
2646 casename = "Case 2b";
2648 /* Check the rare-M redirect case. */
2649 if (D != 0 && 3*M < T) {
2650 casename = "Case 2b (balanced)";
2651 if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
2652 log_warn(LD_DIR,
2653 "Bw Weight Failure for %s: Etotal %f != Mtotal %f. "
2654 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
2655 " T="I64_FORMAT". "
2656 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2657 casename, Etotal, Mtotal,
2658 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2659 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2660 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2661 valid = 0;
2663 if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
2664 log_warn(LD_DIR,
2665 "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
2666 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
2667 " T="I64_FORMAT". "
2668 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2669 casename, Etotal, Gtotal,
2670 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2671 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2672 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2673 valid = 0;
2675 if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
2676 log_warn(LD_DIR,
2677 "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. "
2678 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
2679 " T="I64_FORMAT". "
2680 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2681 casename, Mtotal, Gtotal,
2682 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2683 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2684 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2685 valid = 0;
2687 } else {
2688 if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
2689 log_warn(LD_DIR,
2690 "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
2691 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
2692 " T="I64_FORMAT". "
2693 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2694 casename, Etotal, Gtotal,
2695 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2696 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2697 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2698 valid = 0;
2702 } else { // if (E < T/3 || G < T/3) {
2703 int64_t S = MIN(E, G);
2704 int64_t NS = MAX(E, G);
2705 if (3*(S+D) < T) { // Subcase a:
2706 double Stotal;
2707 double NStotal;
2708 if (G < E) {
2709 casename = "Case 3a (G scarce)";
2710 Stotal = Gtotal;
2711 NStotal = Etotal;
2712 } else { // if (G >= E) {
2713 casename = "Case 3a (E scarce)";
2714 NStotal = Gtotal;
2715 Stotal = Etotal;
2717 // Stotal < T/3
2718 if (3*Stotal > T) {
2719 log_warn(LD_DIR,
2720 "Bw Weight Failure for %s: 3*Stotal %f > T "
2721 I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
2722 " D="I64_FORMAT" T="I64_FORMAT". "
2723 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2724 casename, Stotal*3, I64_PRINTF_ARG(T),
2725 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2726 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2727 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2728 valid = 0;
2730 if (NS >= M) {
2731 if (fabs(NStotal-Mtotal) > 0.01*MAX(NStotal,Mtotal)) {
2732 log_warn(LD_DIR,
2733 "Bw Weight Failure for %s: NStotal %f != Mtotal %f. "
2734 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
2735 " T="I64_FORMAT". "
2736 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2737 casename, NStotal, Mtotal,
2738 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2739 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2740 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2741 valid = 0;
2743 } else {
2744 // if NS < M, NStotal > T/3 because only one of G or E is scarce
2745 if (3*NStotal < T) {
2746 log_warn(LD_DIR,
2747 "Bw Weight Failure for %s: 3*NStotal %f < T "
2748 I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT
2749 " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT". "
2750 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2751 casename, NStotal*3, I64_PRINTF_ARG(T),
2752 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2753 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2754 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2755 valid = 0;
2758 } else { // Subcase b: S+D >= T/3
2759 casename = "Case 3b";
2760 if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
2761 log_warn(LD_DIR,
2762 "Bw Weight Failure for %s: Etotal %f != Mtotal %f. "
2763 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
2764 " T="I64_FORMAT". "
2765 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2766 casename, Etotal, Mtotal,
2767 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2768 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2769 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2770 valid = 0;
2772 if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
2773 log_warn(LD_DIR,
2774 "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
2775 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
2776 " T="I64_FORMAT". "
2777 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2778 casename, Etotal, Gtotal,
2779 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2780 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2781 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2782 valid = 0;
2784 if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
2785 log_warn(LD_DIR,
2786 "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. "
2787 "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
2788 " T="I64_FORMAT". "
2789 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
2790 casename, Mtotal, Gtotal,
2791 I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
2792 I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
2793 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
2794 valid = 0;
2799 if (valid)
2800 log_notice(LD_DIR, "Bandwidth-weight %s is verified and valid.",
2801 casename);
2803 return valid;
2806 /** Parse a v3 networkstatus vote, opinion, or consensus (depending on
2807 * ns_type), from <b>s</b>, and return the result. Return NULL on failure. */
2808 networkstatus_t *
2809 networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
2810 networkstatus_type_t ns_type)
2812 smartlist_t *tokens = smartlist_new();
2813 smartlist_t *rs_tokens = NULL, *footer_tokens = NULL;
2814 networkstatus_voter_info_t *voter = NULL;
2815 networkstatus_t *ns = NULL;
2816 digests_t ns_digests;
2817 const char *cert, *end_of_header, *end_of_footer, *s_dup = s;
2818 directory_token_t *tok;
2819 int ok;
2820 struct in_addr in;
2821 int i, inorder, n_signatures = 0;
2822 memarea_t *area = NULL, *rs_area = NULL;
2823 consensus_flavor_t flav = FLAV_NS;
2824 char *last_kwd=NULL;
2826 tor_assert(s);
2828 if (eos_out)
2829 *eos_out = NULL;
2831 if (router_get_networkstatus_v3_hashes(s, &ns_digests)) {
2832 log_warn(LD_DIR, "Unable to compute digest of network-status");
2833 goto err;
2836 area = memarea_new();
2837 end_of_header = find_start_of_next_routerstatus(s);
2838 if (tokenize_string(area, s, end_of_header, tokens,
2839 (ns_type == NS_TYPE_CONSENSUS) ?
2840 networkstatus_consensus_token_table :
2841 networkstatus_token_table, 0)) {
2842 log_warn(LD_DIR, "Error tokenizing network-status vote header");
2843 goto err;
2846 ns = tor_malloc_zero(sizeof(networkstatus_t));
2847 memcpy(&ns->digests, &ns_digests, sizeof(ns_digests));
2849 tok = find_by_keyword(tokens, K_NETWORK_STATUS_VERSION);
2850 tor_assert(tok);
2851 if (tok->n_args > 1) {
2852 int flavor = networkstatus_parse_flavor_name(tok->args[1]);
2853 if (flavor < 0) {
2854 log_warn(LD_DIR, "Can't parse document with unknown flavor %s",
2855 escaped(tok->args[2]));
2856 goto err;
2858 ns->flavor = flav = flavor;
2860 if (flav != FLAV_NS && ns_type != NS_TYPE_CONSENSUS) {
2861 log_warn(LD_DIR, "Flavor found on non-consensus networkstatus.");
2862 goto err;
2865 if (ns_type != NS_TYPE_CONSENSUS) {
2866 const char *end_of_cert = NULL;
2867 if (!(cert = strstr(s, "\ndir-key-certificate-version")))
2868 goto err;
2869 ++cert;
2870 ns->cert = authority_cert_parse_from_string(cert, &end_of_cert);
2871 if (!ns->cert || !end_of_cert || end_of_cert > end_of_header)
2872 goto err;
2875 tok = find_by_keyword(tokens, K_VOTE_STATUS);
2876 tor_assert(tok->n_args);
2877 if (!strcmp(tok->args[0], "vote")) {
2878 ns->type = NS_TYPE_VOTE;
2879 } else if (!strcmp(tok->args[0], "consensus")) {
2880 ns->type = NS_TYPE_CONSENSUS;
2881 } else if (!strcmp(tok->args[0], "opinion")) {
2882 ns->type = NS_TYPE_OPINION;
2883 } else {
2884 log_warn(LD_DIR, "Unrecognized vote status %s in network-status",
2885 escaped(tok->args[0]));
2886 goto err;
2888 if (ns_type != ns->type) {
2889 log_warn(LD_DIR, "Got the wrong kind of v3 networkstatus.");
2890 goto err;
2893 if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_OPINION) {
2894 tok = find_by_keyword(tokens, K_PUBLISHED);
2895 if (parse_iso_time(tok->args[0], &ns->published))
2896 goto err;
2898 ns->supported_methods = smartlist_new();
2899 tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHODS);
2900 if (tok) {
2901 for (i=0; i < tok->n_args; ++i)
2902 smartlist_add(ns->supported_methods, tor_strdup(tok->args[i]));
2903 } else {
2904 smartlist_add(ns->supported_methods, tor_strdup("1"));
2906 } else {
2907 tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHOD);
2908 if (tok) {
2909 ns->consensus_method = (int)tor_parse_long(tok->args[0], 10, 1, INT_MAX,
2910 &ok, NULL);
2911 if (!ok)
2912 goto err;
2913 } else {
2914 ns->consensus_method = 1;
2918 tok = find_by_keyword(tokens, K_VALID_AFTER);
2919 if (parse_iso_time(tok->args[0], &ns->valid_after))
2920 goto err;
2922 tok = find_by_keyword(tokens, K_FRESH_UNTIL);
2923 if (parse_iso_time(tok->args[0], &ns->fresh_until))
2924 goto err;
2926 tok = find_by_keyword(tokens, K_VALID_UNTIL);
2927 if (parse_iso_time(tok->args[0], &ns->valid_until))
2928 goto err;
2930 tok = find_by_keyword(tokens, K_VOTING_DELAY);
2931 tor_assert(tok->n_args >= 2);
2932 ns->vote_seconds =
2933 (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &ok, NULL);
2934 if (!ok)
2935 goto err;
2936 ns->dist_seconds =
2937 (int) tor_parse_long(tok->args[1], 10, 0, INT_MAX, &ok, NULL);
2938 if (!ok)
2939 goto err;
2940 if (ns->valid_after + MIN_VOTE_INTERVAL > ns->fresh_until) {
2941 log_warn(LD_DIR, "Vote/consensus freshness interval is too short");
2942 goto err;
2944 if (ns->valid_after + MIN_VOTE_INTERVAL*2 > ns->valid_until) {
2945 log_warn(LD_DIR, "Vote/consensus liveness interval is too short");
2946 goto err;
2948 if (ns->vote_seconds < MIN_VOTE_SECONDS) {
2949 log_warn(LD_DIR, "Vote seconds is too short");
2950 goto err;
2952 if (ns->dist_seconds < MIN_DIST_SECONDS) {
2953 log_warn(LD_DIR, "Dist seconds is too short");
2954 goto err;
2957 if ((tok = find_opt_by_keyword(tokens, K_CLIENT_VERSIONS))) {
2958 ns->client_versions = tor_strdup(tok->args[0]);
2960 if ((tok = find_opt_by_keyword(tokens, K_SERVER_VERSIONS))) {
2961 ns->server_versions = tor_strdup(tok->args[0]);
2964 tok = find_by_keyword(tokens, K_KNOWN_FLAGS);
2965 ns->known_flags = smartlist_new();
2966 inorder = 1;
2967 for (i = 0; i < tok->n_args; ++i) {
2968 smartlist_add(ns->known_flags, tor_strdup(tok->args[i]));
2969 if (i>0 && strcmp(tok->args[i-1], tok->args[i])>= 0) {
2970 log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]);
2971 inorder = 0;
2974 if (!inorder) {
2975 log_warn(LD_DIR, "known-flags not in order");
2976 goto err;
2979 tok = find_opt_by_keyword(tokens, K_PARAMS);
2980 if (tok) {
2981 int any_dups = 0;
2982 inorder = 1;
2983 ns->net_params = smartlist_new();
2984 for (i = 0; i < tok->n_args; ++i) {
2985 int ok=0;
2986 char *eq = strchr(tok->args[i], '=');
2987 size_t eq_pos;
2988 if (!eq) {
2989 log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
2990 goto err;
2992 eq_pos = eq-tok->args[i];
2993 tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL);
2994 if (!ok) {
2995 log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
2996 goto err;
2998 if (i > 0 && strcmp(tok->args[i-1], tok->args[i]) >= 0) {
2999 log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]);
3000 inorder = 0;
3002 if (last_kwd && eq_pos == strlen(last_kwd) &&
3003 fast_memeq(last_kwd, tok->args[i], eq_pos)) {
3004 log_warn(LD_DIR, "Duplicate value for %s parameter",
3005 escaped(tok->args[i]));
3006 any_dups = 1;
3008 tor_free(last_kwd);
3009 last_kwd = tor_strndup(tok->args[i], eq_pos);
3010 smartlist_add(ns->net_params, tor_strdup(tok->args[i]));
3012 if (!inorder) {
3013 log_warn(LD_DIR, "params not in order");
3014 goto err;
3016 if (any_dups) {
3017 log_warn(LD_DIR, "Duplicate in parameters");
3018 goto err;
3022 ns->voters = smartlist_new();
3024 SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) {
3025 tok = _tok;
3026 if (tok->tp == K_DIR_SOURCE) {
3027 tor_assert(tok->n_args >= 6);
3029 if (voter)
3030 smartlist_add(ns->voters, voter);
3031 voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
3032 voter->sigs = smartlist_new();
3033 if (ns->type != NS_TYPE_CONSENSUS)
3034 memcpy(voter->vote_digest, ns_digests.d[DIGEST_SHA1], DIGEST_LEN);
3036 voter->nickname = tor_strdup(tok->args[0]);
3037 if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
3038 base16_decode(voter->identity_digest, sizeof(voter->identity_digest),
3039 tok->args[1], HEX_DIGEST_LEN) < 0) {
3040 log_warn(LD_DIR, "Error decoding identity digest %s in "
3041 "network-status vote.", escaped(tok->args[1]));
3042 goto err;
3044 if (ns->type != NS_TYPE_CONSENSUS &&
3045 tor_memneq(ns->cert->cache_info.identity_digest,
3046 voter->identity_digest, DIGEST_LEN)) {
3047 log_warn(LD_DIR,"Mismatch between identities in certificate and vote");
3048 goto err;
3050 voter->address = tor_strdup(tok->args[2]);
3051 if (!tor_inet_aton(tok->args[3], &in)) {
3052 log_warn(LD_DIR, "Error decoding IP address %s in network-status.",
3053 escaped(tok->args[3]));
3054 goto err;
3056 voter->addr = ntohl(in.s_addr);
3057 voter->dir_port = (uint16_t)
3058 tor_parse_long(tok->args[4], 10, 0, 65535, &ok, NULL);
3059 if (!ok)
3060 goto err;
3061 voter->or_port = (uint16_t)
3062 tor_parse_long(tok->args[5], 10, 0, 65535, &ok, NULL);
3063 if (!ok)
3064 goto err;
3065 } else if (tok->tp == K_CONTACT) {
3066 if (!voter || voter->contact) {
3067 log_warn(LD_DIR, "contact element is out of place.");
3068 goto err;
3070 voter->contact = tor_strdup(tok->args[0]);
3071 } else if (tok->tp == K_VOTE_DIGEST) {
3072 tor_assert(ns->type == NS_TYPE_CONSENSUS);
3073 tor_assert(tok->n_args >= 1);
3074 if (!voter || ! tor_digest_is_zero(voter->vote_digest)) {
3075 log_warn(LD_DIR, "vote-digest element is out of place.");
3076 goto err;
3078 if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
3079 base16_decode(voter->vote_digest, sizeof(voter->vote_digest),
3080 tok->args[0], HEX_DIGEST_LEN) < 0) {
3081 log_warn(LD_DIR, "Error decoding vote digest %s in "
3082 "network-status consensus.", escaped(tok->args[0]));
3083 goto err;
3086 } SMARTLIST_FOREACH_END(_tok);
3087 if (voter) {
3088 smartlist_add(ns->voters, voter);
3089 voter = NULL;
3091 if (smartlist_len(ns->voters) == 0) {
3092 log_warn(LD_DIR, "Missing dir-source elements in a vote networkstatus.");
3093 goto err;
3094 } else if (ns->type != NS_TYPE_CONSENSUS && smartlist_len(ns->voters) != 1) {
3095 log_warn(LD_DIR, "Too many dir-source elements in a vote networkstatus.");
3096 goto err;
3099 if (ns->type != NS_TYPE_CONSENSUS &&
3100 (tok = find_opt_by_keyword(tokens, K_LEGACY_DIR_KEY))) {
3101 int bad = 1;
3102 if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {
3103 networkstatus_voter_info_t *voter = smartlist_get(ns->voters, 0);
3104 if (base16_decode(voter->legacy_id_digest, DIGEST_LEN,
3105 tok->args[0], HEX_DIGEST_LEN)<0)
3106 bad = 1;
3107 else
3108 bad = 0;
3110 if (bad) {
3111 log_warn(LD_DIR, "Invalid legacy key digest %s on vote.",
3112 escaped(tok->args[0]));
3116 /* Parse routerstatus lines. */
3117 rs_tokens = smartlist_new();
3118 rs_area = memarea_new();
3119 s = end_of_header;
3120 ns->routerstatus_list = smartlist_new();
3122 while (!strcmpstart(s, "r ")) {
3123 if (ns->type != NS_TYPE_CONSENSUS) {
3124 vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t));
3125 if (routerstatus_parse_entry_from_string(rs_area, &s, rs_tokens, ns,
3126 rs, 0, 0))
3127 smartlist_add(ns->routerstatus_list, rs);
3128 else {
3129 tor_free(rs->version);
3130 tor_free(rs);
3132 } else {
3133 routerstatus_t *rs;
3134 if ((rs = routerstatus_parse_entry_from_string(rs_area, &s, rs_tokens,
3135 NULL, NULL,
3136 ns->consensus_method,
3137 flav)))
3138 smartlist_add(ns->routerstatus_list, rs);
3141 for (i = 1; i < smartlist_len(ns->routerstatus_list); ++i) {
3142 routerstatus_t *rs1, *rs2;
3143 if (ns->type != NS_TYPE_CONSENSUS) {
3144 vote_routerstatus_t *a = smartlist_get(ns->routerstatus_list, i-1);
3145 vote_routerstatus_t *b = smartlist_get(ns->routerstatus_list, i);
3146 rs1 = &a->status; rs2 = &b->status;
3147 } else {
3148 rs1 = smartlist_get(ns->routerstatus_list, i-1);
3149 rs2 = smartlist_get(ns->routerstatus_list, i);
3151 if (fast_memcmp(rs1->identity_digest, rs2->identity_digest, DIGEST_LEN)
3152 >= 0) {
3153 log_warn(LD_DIR, "Vote networkstatus entries not sorted by identity "
3154 "digest");
3155 goto err;
3159 /* Parse footer; check signature. */
3160 footer_tokens = smartlist_new();
3161 if ((end_of_footer = strstr(s, "\nnetwork-status-version ")))
3162 ++end_of_footer;
3163 else
3164 end_of_footer = s + strlen(s);
3165 if (tokenize_string(area,s, end_of_footer, footer_tokens,
3166 networkstatus_vote_footer_token_table, 0)) {
3167 log_warn(LD_DIR, "Error tokenizing network-status vote footer.");
3168 goto err;
3172 int found_sig = 0;
3173 SMARTLIST_FOREACH_BEGIN(footer_tokens, directory_token_t *, _tok) {
3174 tok = _tok;
3175 if (tok->tp == K_DIRECTORY_SIGNATURE)
3176 found_sig = 1;
3177 else if (found_sig) {
3178 log_warn(LD_DIR, "Extraneous token after first directory-signature");
3179 goto err;
3181 } SMARTLIST_FOREACH_END(_tok);
3184 if ((tok = find_opt_by_keyword(footer_tokens, K_DIRECTORY_FOOTER))) {
3185 if (tok != smartlist_get(footer_tokens, 0)) {
3186 log_warn(LD_DIR, "Misplaced directory-footer token");
3187 goto err;
3191 tok = find_opt_by_keyword(footer_tokens, K_BW_WEIGHTS);
3192 if (tok) {
3193 ns->weight_params = smartlist_new();
3194 for (i = 0; i < tok->n_args; ++i) {
3195 int ok=0;
3196 char *eq = strchr(tok->args[i], '=');
3197 if (!eq) {
3198 log_warn(LD_DIR, "Bad element '%s' in weight params",
3199 escaped(tok->args[i]));
3200 goto err;
3202 tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL);
3203 if (!ok) {
3204 log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
3205 goto err;
3207 smartlist_add(ns->weight_params, tor_strdup(tok->args[i]));
3211 SMARTLIST_FOREACH_BEGIN(footer_tokens, directory_token_t *, _tok) {
3212 char declared_identity[DIGEST_LEN];
3213 networkstatus_voter_info_t *v;
3214 document_signature_t *sig;
3215 const char *id_hexdigest = NULL;
3216 const char *sk_hexdigest = NULL;
3217 digest_algorithm_t alg = DIGEST_SHA1;
3218 tok = _tok;
3219 if (tok->tp != K_DIRECTORY_SIGNATURE)
3220 continue;
3221 tor_assert(tok->n_args >= 2);
3222 if (tok->n_args == 2) {
3223 id_hexdigest = tok->args[0];
3224 sk_hexdigest = tok->args[1];
3225 } else {
3226 const char *algname = tok->args[0];
3227 int a;
3228 id_hexdigest = tok->args[1];
3229 sk_hexdigest = tok->args[2];
3230 a = crypto_digest_algorithm_parse_name(algname);
3231 if (a<0) {
3232 log_warn(LD_DIR, "Unknown digest algorithm %s; skipping",
3233 escaped(algname));
3234 continue;
3236 alg = a;
3239 if (!tok->object_type ||
3240 strcmp(tok->object_type, "SIGNATURE") ||
3241 tok->object_size < 128 || tok->object_size > 512) {
3242 log_warn(LD_DIR, "Bad object type or length on directory-signature");
3243 goto err;
3246 if (strlen(id_hexdigest) != HEX_DIGEST_LEN ||
3247 base16_decode(declared_identity, sizeof(declared_identity),
3248 id_hexdigest, HEX_DIGEST_LEN) < 0) {
3249 log_warn(LD_DIR, "Error decoding declared identity %s in "
3250 "network-status vote.", escaped(id_hexdigest));
3251 goto err;
3253 if (!(v = networkstatus_get_voter_by_id(ns, declared_identity))) {
3254 log_warn(LD_DIR, "ID on signature on network-status vote does not match "
3255 "any declared directory source.");
3256 goto err;
3258 sig = tor_malloc_zero(sizeof(document_signature_t));
3259 memcpy(sig->identity_digest, v->identity_digest, DIGEST_LEN);
3260 sig->alg = alg;
3261 if (strlen(sk_hexdigest) != HEX_DIGEST_LEN ||
3262 base16_decode(sig->signing_key_digest, sizeof(sig->signing_key_digest),
3263 sk_hexdigest, HEX_DIGEST_LEN) < 0) {
3264 log_warn(LD_DIR, "Error decoding declared signing key digest %s in "
3265 "network-status vote.", escaped(sk_hexdigest));
3266 tor_free(sig);
3267 goto err;
3270 if (ns->type != NS_TYPE_CONSENSUS) {
3271 if (tor_memneq(declared_identity, ns->cert->cache_info.identity_digest,
3272 DIGEST_LEN)) {
3273 log_warn(LD_DIR, "Digest mismatch between declared and actual on "
3274 "network-status vote.");
3275 tor_free(sig);
3276 goto err;
3280 if (voter_get_sig_by_algorithm(v, sig->alg)) {
3281 /* We already parsed a vote with this algorithm from this voter. Use the
3282 first one. */
3283 log_fn(LOG_PROTOCOL_WARN, LD_DIR, "We received a networkstatus "
3284 "that contains two votes from the same voter with the same "
3285 "algorithm. Ignoring the second vote.");
3286 tor_free(sig);
3287 continue;
3290 if (ns->type != NS_TYPE_CONSENSUS) {
3291 if (check_signature_token(ns_digests.d[DIGEST_SHA1], DIGEST_LEN,
3292 tok, ns->cert->signing_key, 0,
3293 "network-status vote")) {
3294 tor_free(sig);
3295 goto err;
3297 sig->good_signature = 1;
3298 } else {
3299 if (tok->object_size >= INT_MAX || tok->object_size >= SIZE_T_CEILING) {
3300 tor_free(sig);
3301 goto err;
3303 sig->signature = tor_memdup(tok->object_body, tok->object_size);
3304 sig->signature_len = (int) tok->object_size;
3306 smartlist_add(v->sigs, sig);
3308 ++n_signatures;
3309 } SMARTLIST_FOREACH_END(_tok);
3311 if (! n_signatures) {
3312 log_warn(LD_DIR, "No signatures on networkstatus vote.");
3313 goto err;
3314 } else if (ns->type == NS_TYPE_VOTE && n_signatures != 1) {
3315 log_warn(LD_DIR, "Received more than one signature on a "
3316 "network-status vote.");
3317 goto err;
3320 if (eos_out)
3321 *eos_out = end_of_footer;
3323 goto done;
3324 err:
3325 dump_desc(s_dup, "v3 networkstatus");
3326 networkstatus_vote_free(ns);
3327 ns = NULL;
3328 done:
3329 if (tokens) {
3330 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
3331 smartlist_free(tokens);
3333 if (voter) {
3334 if (voter->sigs) {
3335 SMARTLIST_FOREACH(voter->sigs, document_signature_t *, sig,
3336 document_signature_free(sig));
3337 smartlist_free(voter->sigs);
3339 tor_free(voter->nickname);
3340 tor_free(voter->address);
3341 tor_free(voter->contact);
3342 tor_free(voter);
3344 if (rs_tokens) {
3345 SMARTLIST_FOREACH(rs_tokens, directory_token_t *, t, token_clear(t));
3346 smartlist_free(rs_tokens);
3348 if (footer_tokens) {
3349 SMARTLIST_FOREACH(footer_tokens, directory_token_t *, t, token_clear(t));
3350 smartlist_free(footer_tokens);
3352 if (area) {
3353 DUMP_AREA(area, "v3 networkstatus");
3354 memarea_drop_all(area);
3356 if (rs_area)
3357 memarea_drop_all(rs_area);
3358 tor_free(last_kwd);
3360 return ns;
3363 /** Return the digests_t that holds the digests of the
3364 * <b>flavor_name</b>-flavored networkstatus according to the detached
3365 * signatures document <b>sigs</b>, allocating a new digests_t as neeeded. */
3366 static digests_t *
3367 detached_get_digests(ns_detached_signatures_t *sigs, const char *flavor_name)
3369 digests_t *d = strmap_get(sigs->digests, flavor_name);
3370 if (!d) {
3371 d = tor_malloc_zero(sizeof(digests_t));
3372 strmap_set(sigs->digests, flavor_name, d);
3374 return d;
3377 /** Return the list of signatures of the <b>flavor_name</b>-flavored
3378 * networkstatus according to the detached signatures document <b>sigs</b>,
3379 * allocating a new digests_t as neeeded. */
3380 static smartlist_t *
3381 detached_get_signatures(ns_detached_signatures_t *sigs,
3382 const char *flavor_name)
3384 smartlist_t *sl = strmap_get(sigs->signatures, flavor_name);
3385 if (!sl) {
3386 sl = smartlist_new();
3387 strmap_set(sigs->signatures, flavor_name, sl);
3389 return sl;
3392 /** Parse a detached v3 networkstatus signature document between <b>s</b> and
3393 * <b>eos</b> and return the result. Return -1 on failure. */
3394 ns_detached_signatures_t *
3395 networkstatus_parse_detached_signatures(const char *s, const char *eos)
3397 /* XXXX there is too much duplicate shared between this function and
3398 * networkstatus_parse_vote_from_string(). */
3399 directory_token_t *tok;
3400 memarea_t *area = NULL;
3401 digests_t *digests;
3403 smartlist_t *tokens = smartlist_new();
3404 ns_detached_signatures_t *sigs =
3405 tor_malloc_zero(sizeof(ns_detached_signatures_t));
3406 sigs->digests = strmap_new();
3407 sigs->signatures = strmap_new();
3409 if (!eos)
3410 eos = s + strlen(s);
3412 area = memarea_new();
3413 if (tokenize_string(area,s, eos, tokens,
3414 networkstatus_detached_signature_token_table, 0)) {
3415 log_warn(LD_DIR, "Error tokenizing detached networkstatus signatures");
3416 goto err;
3419 /* Grab all the digest-like tokens. */
3420 SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) {
3421 const char *algname;
3422 digest_algorithm_t alg;
3423 const char *flavor;
3424 const char *hexdigest;
3425 size_t expected_length;
3427 tok = _tok;
3429 if (tok->tp == K_CONSENSUS_DIGEST) {
3430 algname = "sha1";
3431 alg = DIGEST_SHA1;
3432 flavor = "ns";
3433 hexdigest = tok->args[0];
3434 } else if (tok->tp == K_ADDITIONAL_DIGEST) {
3435 int a = crypto_digest_algorithm_parse_name(tok->args[1]);
3436 if (a<0) {
3437 log_warn(LD_DIR, "Unrecognized algorithm name %s", tok->args[0]);
3438 continue;
3440 alg = (digest_algorithm_t) a;
3441 flavor = tok->args[0];
3442 algname = tok->args[1];
3443 hexdigest = tok->args[2];
3444 } else {
3445 continue;
3448 expected_length =
3449 (alg == DIGEST_SHA1) ? HEX_DIGEST_LEN : HEX_DIGEST256_LEN;
3451 if (strlen(hexdigest) != expected_length) {
3452 log_warn(LD_DIR, "Wrong length on consensus-digest in detached "
3453 "networkstatus signatures");
3454 goto err;
3456 digests = detached_get_digests(sigs, flavor);
3457 tor_assert(digests);
3458 if (!tor_mem_is_zero(digests->d[alg], DIGEST256_LEN)) {
3459 log_warn(LD_DIR, "Multiple digests for %s with %s on detached "
3460 "signatures document", flavor, algname);
3461 continue;
3463 if (base16_decode(digests->d[alg], DIGEST256_LEN,
3464 hexdigest, strlen(hexdigest)) < 0) {
3465 log_warn(LD_DIR, "Bad encoding on consensus-digest in detached "
3466 "networkstatus signatures");
3467 goto err;
3469 } SMARTLIST_FOREACH_END(_tok);
3471 tok = find_by_keyword(tokens, K_VALID_AFTER);
3472 if (parse_iso_time(tok->args[0], &sigs->valid_after)) {
3473 log_warn(LD_DIR, "Bad valid-after in detached networkstatus signatures");
3474 goto err;
3477 tok = find_by_keyword(tokens, K_FRESH_UNTIL);
3478 if (parse_iso_time(tok->args[0], &sigs->fresh_until)) {
3479 log_warn(LD_DIR, "Bad fresh-until in detached networkstatus signatures");
3480 goto err;
3483 tok = find_by_keyword(tokens, K_VALID_UNTIL);
3484 if (parse_iso_time(tok->args[0], &sigs->valid_until)) {
3485 log_warn(LD_DIR, "Bad valid-until in detached networkstatus signatures");
3486 goto err;
3489 SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) {
3490 const char *id_hexdigest;
3491 const char *sk_hexdigest;
3492 const char *algname;
3493 const char *flavor;
3494 digest_algorithm_t alg;
3496 char id_digest[DIGEST_LEN];
3497 char sk_digest[DIGEST_LEN];
3498 smartlist_t *siglist;
3499 document_signature_t *sig;
3500 int is_duplicate;
3502 tok = _tok;
3503 if (tok->tp == K_DIRECTORY_SIGNATURE) {
3504 tor_assert(tok->n_args >= 2);
3505 flavor = "ns";
3506 algname = "sha1";
3507 id_hexdigest = tok->args[0];
3508 sk_hexdigest = tok->args[1];
3509 } else if (tok->tp == K_ADDITIONAL_SIGNATURE) {
3510 tor_assert(tok->n_args >= 4);
3511 flavor = tok->args[0];
3512 algname = tok->args[1];
3513 id_hexdigest = tok->args[2];
3514 sk_hexdigest = tok->args[3];
3515 } else {
3516 continue;
3520 int a = crypto_digest_algorithm_parse_name(algname);
3521 if (a<0) {
3522 log_warn(LD_DIR, "Unrecognized algorithm name %s", algname);
3523 continue;
3525 alg = (digest_algorithm_t) a;
3528 if (!tok->object_type ||
3529 strcmp(tok->object_type, "SIGNATURE") ||
3530 tok->object_size < 128 || tok->object_size > 512) {
3531 log_warn(LD_DIR, "Bad object type or length on directory-signature");
3532 goto err;
3535 if (strlen(id_hexdigest) != HEX_DIGEST_LEN ||
3536 base16_decode(id_digest, sizeof(id_digest),
3537 id_hexdigest, HEX_DIGEST_LEN) < 0) {
3538 log_warn(LD_DIR, "Error decoding declared identity %s in "
3539 "network-status vote.", escaped(id_hexdigest));
3540 goto err;
3542 if (strlen(sk_hexdigest) != HEX_DIGEST_LEN ||
3543 base16_decode(sk_digest, sizeof(sk_digest),
3544 sk_hexdigest, HEX_DIGEST_LEN) < 0) {
3545 log_warn(LD_DIR, "Error decoding declared signing key digest %s in "
3546 "network-status vote.", escaped(sk_hexdigest));
3547 goto err;
3550 siglist = detached_get_signatures(sigs, flavor);
3551 is_duplicate = 0;
3552 SMARTLIST_FOREACH(siglist, document_signature_t *, dsig, {
3553 if (dsig->alg == alg &&
3554 tor_memeq(id_digest, dsig->identity_digest, DIGEST_LEN) &&
3555 tor_memeq(sk_digest, dsig->signing_key_digest, DIGEST_LEN)) {
3556 is_duplicate = 1;
3559 if (is_duplicate) {
3560 log_warn(LD_DIR, "Two signatures with identical keys and algorithm "
3561 "found.");
3562 continue;
3565 sig = tor_malloc_zero(sizeof(document_signature_t));
3566 sig->alg = alg;
3567 memcpy(sig->identity_digest, id_digest, DIGEST_LEN);
3568 memcpy(sig->signing_key_digest, sk_digest, DIGEST_LEN);
3569 if (tok->object_size >= INT_MAX || tok->object_size >= SIZE_T_CEILING) {
3570 tor_free(sig);
3571 goto err;
3573 sig->signature = tor_memdup(tok->object_body, tok->object_size);
3574 sig->signature_len = (int) tok->object_size;
3576 smartlist_add(siglist, sig);
3577 } SMARTLIST_FOREACH_END(_tok);
3579 goto done;
3580 err:
3581 ns_detached_signatures_free(sigs);
3582 sigs = NULL;
3583 done:
3584 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
3585 smartlist_free(tokens);
3586 if (area) {
3587 DUMP_AREA(area, "detached signatures");
3588 memarea_drop_all(area);
3590 return sigs;
3593 /** Parse the addr policy in the string <b>s</b> and return it. If
3594 * assume_action is nonnegative, then insert its action (ADDR_POLICY_ACCEPT or
3595 * ADDR_POLICY_REJECT) for items that specify no action.
3597 addr_policy_t *
3598 router_parse_addr_policy_item_from_string(const char *s, int assume_action)
3600 directory_token_t *tok = NULL;
3601 const char *cp, *eos;
3602 /* Longest possible policy is "accept ffff:ffff:..255/ffff:...255:0-65535".
3603 * But note that there can be an arbitrary amount of space between the
3604 * accept and the address:mask/port element. */
3605 char line[TOR_ADDR_BUF_LEN*2 + 32];
3606 addr_policy_t *r;
3607 memarea_t *area = NULL;
3609 s = eat_whitespace(s);
3610 if ((*s == '*' || TOR_ISDIGIT(*s)) && assume_action >= 0) {
3611 if (tor_snprintf(line, sizeof(line), "%s %s",
3612 assume_action == ADDR_POLICY_ACCEPT?"accept":"reject", s)<0) {
3613 log_warn(LD_DIR, "Policy %s is too long.", escaped(s));
3614 return NULL;
3616 cp = line;
3617 tor_strlower(line);
3618 } else { /* assume an already well-formed address policy line */
3619 cp = s;
3622 eos = cp + strlen(cp);
3623 area = memarea_new();
3624 tok = get_next_token(area, &cp, eos, routerdesc_token_table);
3625 if (tok->tp == _ERR) {
3626 log_warn(LD_DIR, "Error reading address policy: %s", tok->error);
3627 goto err;
3629 if (tok->tp != K_ACCEPT && tok->tp != K_ACCEPT6 &&
3630 tok->tp != K_REJECT && tok->tp != K_REJECT6) {
3631 log_warn(LD_DIR, "Expected 'accept' or 'reject'.");
3632 goto err;
3635 r = router_parse_addr_policy(tok);
3636 goto done;
3637 err:
3638 r = NULL;
3639 done:
3640 token_clear(tok);
3641 if (area) {
3642 DUMP_AREA(area, "policy item");
3643 memarea_drop_all(area);
3645 return r;
3648 /** Add an exit policy stored in the token <b>tok</b> to the router info in
3649 * <b>router</b>. Return 0 on success, -1 on failure. */
3650 static int
3651 router_add_exit_policy(routerinfo_t *router, directory_token_t *tok)
3653 addr_policy_t *newe;
3654 newe = router_parse_addr_policy(tok);
3655 if (!newe)
3656 return -1;
3657 if (! router->exit_policy)
3658 router->exit_policy = smartlist_new();
3660 if (((tok->tp == K_ACCEPT6 || tok->tp == K_REJECT6) &&
3661 tor_addr_family(&newe->addr) == AF_INET)
3663 ((tok->tp == K_ACCEPT || tok->tp == K_REJECT) &&
3664 tor_addr_family(&newe->addr) == AF_INET6)) {
3665 log_warn(LD_DIR, "Mismatch between field type and address type in exit "
3666 "policy");
3667 addr_policy_free(newe);
3668 return -1;
3671 smartlist_add(router->exit_policy, newe);
3673 return 0;
3676 /** Given a K_ACCEPT or K_REJECT token and a router, create and return
3677 * a new exit_policy_t corresponding to the token. */
3678 static addr_policy_t *
3679 router_parse_addr_policy(directory_token_t *tok)
3681 addr_policy_t newe;
3682 char *arg;
3684 tor_assert(tok->tp == K_REJECT || tok->tp == K_REJECT6 ||
3685 tok->tp == K_ACCEPT || tok->tp == K_ACCEPT6);
3687 if (tok->n_args != 1)
3688 return NULL;
3689 arg = tok->args[0];
3691 if (!strcmpstart(arg,"private"))
3692 return router_parse_addr_policy_private(tok);
3694 memset(&newe, 0, sizeof(newe));
3696 if (tok->tp == K_REJECT || tok->tp == K_REJECT6)
3697 newe.policy_type = ADDR_POLICY_REJECT;
3698 else
3699 newe.policy_type = ADDR_POLICY_ACCEPT;
3701 if (tor_addr_parse_mask_ports(arg, &newe.addr, &newe.maskbits,
3702 &newe.prt_min, &newe.prt_max) < 0) {
3703 log_warn(LD_DIR,"Couldn't parse line %s. Dropping", escaped(arg));
3704 return NULL;
3707 return addr_policy_get_canonical_entry(&newe);
3710 /** Parse an exit policy line of the format "accept/reject private:...".
3711 * This didn't exist until Tor 0.1.1.15, so nobody should generate it in
3712 * router descriptors until earlier versions are obsolete.
3714 static addr_policy_t *
3715 router_parse_addr_policy_private(directory_token_t *tok)
3717 const char *arg;
3718 uint16_t port_min, port_max;
3719 addr_policy_t result;
3721 arg = tok->args[0];
3722 if (strcmpstart(arg, "private"))
3723 return NULL;
3725 arg += strlen("private");
3726 arg = (char*) eat_whitespace(arg);
3727 if (!arg || *arg != ':')
3728 return NULL;
3730 if (parse_port_range(arg+1, &port_min, &port_max)<0)
3731 return NULL;
3733 memset(&result, 0, sizeof(result));
3734 if (tok->tp == K_REJECT || tok->tp == K_REJECT6)
3735 result.policy_type = ADDR_POLICY_REJECT;
3736 else
3737 result.policy_type = ADDR_POLICY_ACCEPT;
3738 result.is_private = 1;
3739 result.prt_min = port_min;
3740 result.prt_max = port_max;
3742 return addr_policy_get_canonical_entry(&result);
3745 /** Log and exit if <b>t</b> is malformed */
3746 void
3747 assert_addr_policy_ok(smartlist_t *lst)
3749 if (!lst) return;
3750 SMARTLIST_FOREACH(lst, addr_policy_t *, t, {
3751 tor_assert(t->policy_type == ADDR_POLICY_REJECT ||
3752 t->policy_type == ADDR_POLICY_ACCEPT);
3753 tor_assert(t->prt_min <= t->prt_max);
3758 * Low-level tokenizer for router descriptors and directories.
3761 /** Free all resources allocated for <b>tok</b> */
3762 static void
3763 token_clear(directory_token_t *tok)
3765 if (tok->key)
3766 crypto_pk_free(tok->key);
3769 #define ALLOC_ZERO(sz) memarea_alloc_zero(area,sz)
3770 #define ALLOC(sz) memarea_alloc(area,sz)
3771 #define STRDUP(str) memarea_strdup(area,str)
3772 #define STRNDUP(str,n) memarea_strndup(area,(str),(n))
3774 #define RET_ERR(msg) \
3775 STMT_BEGIN \
3776 if (tok) token_clear(tok); \
3777 tok = ALLOC_ZERO(sizeof(directory_token_t)); \
3778 tok->tp = _ERR; \
3779 tok->error = STRDUP(msg); \
3780 goto done_tokenizing; \
3781 STMT_END
3783 /** Helper: make sure that the token <b>tok</b> with keyword <b>kwd</b> obeys
3784 * the object syntax of <b>o_syn</b>. Allocate all storage in <b>area</b>.
3785 * Return <b>tok</b> on success, or a new _ERR token if the token didn't
3786 * conform to the syntax we wanted.
3788 static INLINE directory_token_t *
3789 token_check_object(memarea_t *area, const char *kwd,
3790 directory_token_t *tok, obj_syntax o_syn)
3792 char ebuf[128];
3793 switch (o_syn) {
3794 case NO_OBJ:
3795 /* No object is allowed for this token. */
3796 if (tok->object_body) {
3797 tor_snprintf(ebuf, sizeof(ebuf), "Unexpected object for %s", kwd);
3798 RET_ERR(ebuf);
3800 if (tok->key) {
3801 tor_snprintf(ebuf, sizeof(ebuf), "Unexpected public key for %s", kwd);
3802 RET_ERR(ebuf);
3804 break;
3805 case NEED_OBJ:
3806 /* There must be a (non-key) object. */
3807 if (!tok->object_body) {
3808 tor_snprintf(ebuf, sizeof(ebuf), "Missing object for %s", kwd);
3809 RET_ERR(ebuf);
3811 break;
3812 case NEED_KEY_1024: /* There must be a 1024-bit public key. */
3813 case NEED_SKEY_1024: /* There must be a 1024-bit private key. */
3814 if (tok->key && crypto_pk_num_bits(tok->key) != PK_BYTES*8) {
3815 tor_snprintf(ebuf, sizeof(ebuf), "Wrong size on key for %s: %d bits",
3816 kwd, crypto_pk_num_bits(tok->key));
3817 RET_ERR(ebuf);
3819 /* fall through */
3820 case NEED_KEY: /* There must be some kind of key. */
3821 if (!tok->key) {
3822 tor_snprintf(ebuf, sizeof(ebuf), "Missing public key for %s", kwd);
3823 RET_ERR(ebuf);
3825 if (o_syn != NEED_SKEY_1024) {
3826 if (crypto_pk_key_is_private(tok->key)) {
3827 tor_snprintf(ebuf, sizeof(ebuf),
3828 "Private key given for %s, which wants a public key", kwd);
3829 RET_ERR(ebuf);
3831 } else { /* o_syn == NEED_SKEY_1024 */
3832 if (!crypto_pk_key_is_private(tok->key)) {
3833 tor_snprintf(ebuf, sizeof(ebuf),
3834 "Public key given for %s, which wants a private key", kwd);
3835 RET_ERR(ebuf);
3838 break;
3839 case OBJ_OK:
3840 /* Anything goes with this token. */
3841 break;
3844 done_tokenizing:
3845 return tok;
3848 /** Helper: parse space-separated arguments from the string <b>s</b> ending at
3849 * <b>eol</b>, and store them in the args field of <b>tok</b>. Store the
3850 * number of parsed elements into the n_args field of <b>tok</b>. Allocate
3851 * all storage in <b>area</b>. Return the number of arguments parsed, or
3852 * return -1 if there was an insanely high number of arguments. */
3853 static INLINE int
3854 get_token_arguments(memarea_t *area, directory_token_t *tok,
3855 const char *s, const char *eol)
3857 /** Largest number of arguments we'll accept to any token, ever. */
3858 #define MAX_ARGS 512
3859 char *mem = memarea_strndup(area, s, eol-s);
3860 char *cp = mem;
3861 int j = 0;
3862 char *args[MAX_ARGS];
3863 while (*cp) {
3864 if (j == MAX_ARGS)
3865 return -1;
3866 args[j++] = cp;
3867 cp = (char*)find_whitespace(cp);
3868 if (!cp || !*cp)
3869 break; /* End of the line. */
3870 *cp++ = '\0';
3871 cp = (char*)eat_whitespace(cp);
3873 tok->n_args = j;
3874 tok->args = memarea_memdup(area, args, j*sizeof(char*));
3875 return j;
3876 #undef MAX_ARGS
3879 /** Helper function: read the next token from *s, advance *s to the end of the
3880 * token, and return the parsed token. Parse *<b>s</b> according to the list
3881 * of tokens in <b>table</b>.
3883 static directory_token_t *
3884 get_next_token(memarea_t *area,
3885 const char **s, const char *eos, token_rule_t *table)
3887 /** Reject any object at least this big; it is probably an overflow, an
3888 * attack, a bug, or some other nonsense. */
3889 #define MAX_UNPARSED_OBJECT_SIZE (128*1024)
3890 /** Reject any line at least this big; it is probably an overflow, an
3891 * attack, a bug, or some other nonsense. */
3892 #define MAX_LINE_LENGTH (128*1024)
3894 const char *next, *eol, *obstart;
3895 size_t obname_len;
3896 int i;
3897 directory_token_t *tok;
3898 obj_syntax o_syn = NO_OBJ;
3899 char ebuf[128];
3900 const char *kwd = "";
3902 tor_assert(area);
3903 tok = ALLOC_ZERO(sizeof(directory_token_t));
3904 tok->tp = _ERR;
3906 /* Set *s to first token, eol to end-of-line, next to after first token */
3907 *s = eat_whitespace_eos(*s, eos); /* eat multi-line whitespace */
3908 tor_assert(eos >= *s);
3909 eol = memchr(*s, '\n', eos-*s);
3910 if (!eol)
3911 eol = eos;
3912 if (eol - *s > MAX_LINE_LENGTH) {
3913 RET_ERR("Line far too long");
3916 next = find_whitespace_eos(*s, eol);
3918 if (!strcmp_len(*s, "opt", next-*s)) {
3919 /* Skip past an "opt" at the start of the line. */
3920 *s = eat_whitespace_eos_no_nl(next, eol);
3921 next = find_whitespace_eos(*s, eol);
3922 } else if (*s == eos) { /* If no "opt", and end-of-line, line is invalid */
3923 RET_ERR("Unexpected EOF");
3926 /* Search the table for the appropriate entry. (I tried a binary search
3927 * instead, but it wasn't any faster.) */
3928 for (i = 0; table[i].t ; ++i) {
3929 if (!strcmp_len(*s, table[i].t, next-*s)) {
3930 /* We've found the keyword. */
3931 kwd = table[i].t;
3932 tok->tp = table[i].v;
3933 o_syn = table[i].os;
3934 *s = eat_whitespace_eos_no_nl(next, eol);
3935 /* We go ahead whether there are arguments or not, so that tok->args is
3936 * always set if we want arguments. */
3937 if (table[i].concat_args) {
3938 /* The keyword takes the line as a single argument */
3939 tok->args = ALLOC(sizeof(char*));
3940 tok->args[0] = STRNDUP(*s,eol-*s); /* Grab everything on line */
3941 tok->n_args = 1;
3942 } else {
3943 /* This keyword takes multiple arguments. */
3944 if (get_token_arguments(area, tok, *s, eol)<0) {
3945 tor_snprintf(ebuf, sizeof(ebuf),"Far too many arguments to %s", kwd);
3946 RET_ERR(ebuf);
3948 *s = eol;
3950 if (tok->n_args < table[i].min_args) {
3951 tor_snprintf(ebuf, sizeof(ebuf), "Too few arguments to %s", kwd);
3952 RET_ERR(ebuf);
3953 } else if (tok->n_args > table[i].max_args) {
3954 tor_snprintf(ebuf, sizeof(ebuf), "Too many arguments to %s", kwd);
3955 RET_ERR(ebuf);
3957 break;
3961 if (tok->tp == _ERR) {
3962 /* No keyword matched; call it an "K_opt" or "A_unrecognized" */
3963 if (**s == '@')
3964 tok->tp = _A_UNKNOWN;
3965 else
3966 tok->tp = K_OPT;
3967 tok->args = ALLOC(sizeof(char*));
3968 tok->args[0] = STRNDUP(*s, eol-*s);
3969 tok->n_args = 1;
3970 o_syn = OBJ_OK;
3973 /* Check whether there's an object present */
3974 *s = eat_whitespace_eos(eol, eos); /* Scan from end of first line */
3975 tor_assert(eos >= *s);
3976 eol = memchr(*s, '\n', eos-*s);
3977 if (!eol || eol-*s<11 || strcmpstart(*s, "-----BEGIN ")) /* No object. */
3978 goto check_object;
3980 obstart = *s; /* Set obstart to start of object spec */
3981 if (*s+16 >= eol || memchr(*s+11,'\0',eol-*s-16) || /* no short lines, */
3982 strcmp_len(eol-5, "-----", 5) || /* nuls or invalid endings */
3983 (eol-*s) > MAX_UNPARSED_OBJECT_SIZE) { /* name too long */
3984 RET_ERR("Malformed object: bad begin line");
3986 tok->object_type = STRNDUP(*s+11, eol-*s-16);
3987 obname_len = eol-*s-16; /* store objname length here to avoid a strlen() */
3988 *s = eol+1; /* Set *s to possible start of object data (could be eos) */
3990 /* Go to the end of the object */
3991 next = tor_memstr(*s, eos-*s, "-----END ");
3992 if (!next) {
3993 RET_ERR("Malformed object: missing object end line");
3995 tor_assert(eos >= next);
3996 eol = memchr(next, '\n', eos-next);
3997 if (!eol) /* end-of-line marker, or eos if there's no '\n' */
3998 eol = eos;
3999 /* Validate the ending tag, which should be 9 + NAME + 5 + eol */
4000 if ((size_t)(eol-next) != 9+obname_len+5 ||
4001 strcmp_len(next+9, tok->object_type, obname_len) ||
4002 strcmp_len(eol-5, "-----", 5)) {
4003 snprintf(ebuf, sizeof(ebuf), "Malformed object: mismatched end tag %s",
4004 tok->object_type);
4005 ebuf[sizeof(ebuf)-1] = '\0';
4006 RET_ERR(ebuf);
4008 if (next - *s > MAX_UNPARSED_OBJECT_SIZE)
4009 RET_ERR("Couldn't parse object: missing footer or object much too big.");
4011 if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) { /* If it's a public key */
4012 tok->key = crypto_pk_new();
4013 if (crypto_pk_read_public_key_from_string(tok->key, obstart, eol-obstart))
4014 RET_ERR("Couldn't parse public key.");
4015 } else if (!strcmp(tok->object_type, "RSA PRIVATE KEY")) { /* private key */
4016 tok->key = crypto_pk_new();
4017 if (crypto_pk_read_private_key_from_string(tok->key, obstart, eol-obstart))
4018 RET_ERR("Couldn't parse private key.");
4019 } else { /* If it's something else, try to base64-decode it */
4020 int r;
4021 tok->object_body = ALLOC(next-*s); /* really, this is too much RAM. */
4022 r = base64_decode(tok->object_body, next-*s, *s, next-*s);
4023 if (r<0)
4024 RET_ERR("Malformed object: bad base64-encoded data");
4025 tok->object_size = r;
4027 *s = eol;
4029 check_object:
4030 tok = token_check_object(area, kwd, tok, o_syn);
4032 done_tokenizing:
4033 return tok;
4035 #undef RET_ERR
4036 #undef ALLOC
4037 #undef ALLOC_ZERO
4038 #undef STRDUP
4039 #undef STRNDUP
4042 /** Read all tokens from a string between <b>start</b> and <b>end</b>, and add
4043 * them to <b>out</b>. Parse according to the token rules in <b>table</b>.
4044 * Caller must free tokens in <b>out</b>. If <b>end</b> is NULL, use the
4045 * entire string.
4047 static int
4048 tokenize_string(memarea_t *area,
4049 const char *start, const char *end, smartlist_t *out,
4050 token_rule_t *table, int flags)
4052 const char **s;
4053 directory_token_t *tok = NULL;
4054 int counts[_NIL];
4055 int i;
4056 int first_nonannotation;
4057 int prev_len = smartlist_len(out);
4058 tor_assert(area);
4060 s = &start;
4061 if (!end)
4062 end = start+strlen(start);
4063 for (i = 0; i < _NIL; ++i)
4064 counts[i] = 0;
4066 SMARTLIST_FOREACH(out, const directory_token_t *, t, ++counts[t->tp]);
4068 while (*s < end && (!tok || tok->tp != _EOF)) {
4069 tok = get_next_token(area, s, end, table);
4070 if (tok->tp == _ERR) {
4071 log_warn(LD_DIR, "parse error: %s", tok->error);
4072 token_clear(tok);
4073 return -1;
4075 ++counts[tok->tp];
4076 smartlist_add(out, tok);
4077 *s = eat_whitespace_eos(*s, end);
4080 if (flags & TS_NOCHECK)
4081 return 0;
4083 if ((flags & TS_ANNOTATIONS_OK)) {
4084 first_nonannotation = -1;
4085 for (i = 0; i < smartlist_len(out); ++i) {
4086 tok = smartlist_get(out, i);
4087 if (tok->tp < MIN_ANNOTATION || tok->tp > MAX_ANNOTATION) {
4088 first_nonannotation = i;
4089 break;
4092 if (first_nonannotation < 0) {
4093 log_warn(LD_DIR, "parse error: item contains only annotations");
4094 return -1;
4096 for (i=first_nonannotation; i < smartlist_len(out); ++i) {
4097 tok = smartlist_get(out, i);
4098 if (tok->tp >= MIN_ANNOTATION && tok->tp <= MAX_ANNOTATION) {
4099 log_warn(LD_DIR, "parse error: Annotations mixed with keywords");
4100 return -1;
4103 if ((flags & TS_NO_NEW_ANNOTATIONS)) {
4104 if (first_nonannotation != prev_len) {
4105 log_warn(LD_DIR, "parse error: Unexpected annotations.");
4106 return -1;
4109 } else {
4110 for (i=0; i < smartlist_len(out); ++i) {
4111 tok = smartlist_get(out, i);
4112 if (tok->tp >= MIN_ANNOTATION && tok->tp <= MAX_ANNOTATION) {
4113 log_warn(LD_DIR, "parse error: no annotations allowed.");
4114 return -1;
4117 first_nonannotation = 0;
4119 for (i = 0; table[i].t; ++i) {
4120 if (counts[table[i].v] < table[i].min_cnt) {
4121 log_warn(LD_DIR, "Parse error: missing %s element.", table[i].t);
4122 return -1;
4124 if (counts[table[i].v] > table[i].max_cnt) {
4125 log_warn(LD_DIR, "Parse error: too many %s elements.", table[i].t);
4126 return -1;
4128 if (table[i].pos & AT_START) {
4129 if (smartlist_len(out) < 1 ||
4130 (tok = smartlist_get(out, first_nonannotation))->tp != table[i].v) {
4131 log_warn(LD_DIR, "Parse error: first item is not %s.", table[i].t);
4132 return -1;
4135 if (table[i].pos & AT_END) {
4136 if (smartlist_len(out) < 1 ||
4137 (tok = smartlist_get(out, smartlist_len(out)-1))->tp != table[i].v) {
4138 log_warn(LD_DIR, "Parse error: last item is not %s.", table[i].t);
4139 return -1;
4143 return 0;
4146 /** Find the first token in <b>s</b> whose keyword is <b>keyword</b>; return
4147 * NULL if no such keyword is found.
4149 static directory_token_t *
4150 find_opt_by_keyword(smartlist_t *s, directory_keyword keyword)
4152 SMARTLIST_FOREACH(s, directory_token_t *, t, if (t->tp == keyword) return t);
4153 return NULL;
4156 /** Find the first token in <b>s</b> whose keyword is <b>keyword</b>; fail
4157 * with an assert if no such keyword is found.
4159 static directory_token_t *
4160 _find_by_keyword(smartlist_t *s, directory_keyword keyword,
4161 const char *keyword_as_string)
4163 directory_token_t *tok = find_opt_by_keyword(s, keyword);
4164 if (PREDICT_UNLIKELY(!tok)) {
4165 log_err(LD_BUG, "Missing %s [%d] in directory object that should have "
4166 "been validated. Internal error.", keyword_as_string, (int)keyword);
4167 tor_assert(tok);
4169 return tok;
4172 /** DOCDOC */
4173 static smartlist_t *
4174 find_all_by_keyword(smartlist_t *s, directory_keyword k)
4176 smartlist_t *out = NULL;
4177 SMARTLIST_FOREACH(s, directory_token_t *, t,
4178 if (t->tp == k) {
4179 if (!out)
4180 out = smartlist_new();
4181 smartlist_add(out, t);
4183 return out;
4186 /** Return a newly allocated smartlist of all accept or reject tokens in
4187 * <b>s</b>.
4189 static smartlist_t *
4190 find_all_exitpolicy(smartlist_t *s)
4192 smartlist_t *out = smartlist_new();
4193 SMARTLIST_FOREACH(s, directory_token_t *, t,
4194 if (t->tp == K_ACCEPT || t->tp == K_ACCEPT6 ||
4195 t->tp == K_REJECT || t->tp == K_REJECT6)
4196 smartlist_add(out,t));
4197 return out;
4200 static int
4201 router_get_hash_impl_helper(const char *s, size_t s_len,
4202 const char *start_str,
4203 const char *end_str, char end_c,
4204 const char **start_out, const char **end_out)
4206 const char *start, *end;
4207 start = tor_memstr(s, s_len, start_str);
4208 if (!start) {
4209 log_warn(LD_DIR,"couldn't find start of hashed material \"%s\"",start_str);
4210 return -1;
4212 if (start != s && *(start-1) != '\n') {
4213 log_warn(LD_DIR,
4214 "first occurrence of \"%s\" is not at the start of a line",
4215 start_str);
4216 return -1;
4218 end = tor_memstr(start+strlen(start_str),
4219 s_len - (start-s) - strlen(start_str), end_str);
4220 if (!end) {
4221 log_warn(LD_DIR,"couldn't find end of hashed material \"%s\"",end_str);
4222 return -1;
4224 end = memchr(end+strlen(end_str), end_c, s_len - (end-s) - strlen(end_str));
4225 if (!end) {
4226 log_warn(LD_DIR,"couldn't find EOL");
4227 return -1;
4229 ++end;
4231 *start_out = start;
4232 *end_out = end;
4233 return 0;
4236 /** Compute the digest of the substring of <b>s</b> taken from the first
4237 * occurrence of <b>start_str</b> through the first instance of c after the
4238 * first subsequent occurrence of <b>end_str</b>; store the 20-byte result in
4239 * <b>digest</b>; return 0 on success.
4241 * If no such substring exists, return -1.
4243 static int
4244 router_get_hash_impl(const char *s, size_t s_len, char *digest,
4245 const char *start_str,
4246 const char *end_str, char end_c,
4247 digest_algorithm_t alg)
4249 const char *start=NULL, *end=NULL;
4250 if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,
4251 &start,&end)<0)
4252 return -1;
4254 if (alg == DIGEST_SHA1) {
4255 if (crypto_digest(digest, start, end-start)) {
4256 log_warn(LD_BUG,"couldn't compute digest");
4257 return -1;
4259 } else {
4260 if (crypto_digest256(digest, start, end-start, alg)) {
4261 log_warn(LD_BUG,"couldn't compute digest");
4262 return -1;
4266 return 0;
4269 /** As router_get_hash_impl, but compute all hashes. */
4270 static int
4271 router_get_hashes_impl(const char *s, size_t s_len, digests_t *digests,
4272 const char *start_str,
4273 const char *end_str, char end_c)
4275 const char *start=NULL, *end=NULL;
4276 if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,
4277 &start,&end)<0)
4278 return -1;
4280 if (crypto_digest_all(digests, start, end-start)) {
4281 log_warn(LD_BUG,"couldn't compute digests");
4282 return -1;
4285 return 0;
4288 /** Assuming that s starts with a microdesc, return the start of the
4289 * *NEXT* one. Return NULL on "not found." */
4290 static const char *
4291 find_start_of_next_microdesc(const char *s, const char *eos)
4293 int started_with_annotations;
4294 s = eat_whitespace_eos(s, eos);
4295 if (!s)
4296 return NULL;
4298 #define CHECK_LENGTH() STMT_BEGIN \
4299 if (s+32 > eos) \
4300 return NULL; \
4301 STMT_END
4303 #define NEXT_LINE() STMT_BEGIN \
4304 s = memchr(s, '\n', eos-s); \
4305 if (!s || s+1 >= eos) \
4306 return NULL; \
4307 s++; \
4308 STMT_END
4310 CHECK_LENGTH();
4312 started_with_annotations = (*s == '@');
4314 if (started_with_annotations) {
4315 /* Start by advancing to the first non-annotation line. */
4316 while (*s == '@')
4317 NEXT_LINE();
4319 CHECK_LENGTH();
4321 /* Now we should be pointed at an onion-key line. If we are, then skip
4322 * it. */
4323 if (!strcmpstart(s, "onion-key"))
4324 NEXT_LINE();
4326 /* Okay, now we're pointed at the first line of the microdescriptor which is
4327 not an annotation or onion-key. The next line that _is_ an annotation or
4328 onion-key is the start of the next microdescriptor. */
4329 while (s+32 < eos) {
4330 if (*s == '@' || !strcmpstart(s, "onion-key"))
4331 return s;
4332 NEXT_LINE();
4334 return NULL;
4336 #undef CHECK_LENGTH
4337 #undef NEXT_LINE
4340 /** Parse as many microdescriptors as are found from the string starting at
4341 * <b>s</b> and ending at <b>eos</b>. If allow_annotations is set, read any
4342 * annotations we recognize and ignore ones we don't. If <b>copy_body</b> is
4343 * true, then strdup the bodies of the microdescriptors. Return all newly
4344 * parsed microdescriptors in a newly allocated smartlist_t. */
4345 smartlist_t *
4346 microdescs_parse_from_string(const char *s, const char *eos,
4347 int allow_annotations, int copy_body)
4349 smartlist_t *tokens;
4350 smartlist_t *result;
4351 microdesc_t *md = NULL;
4352 memarea_t *area;
4353 const char *start = s;
4354 const char *start_of_next_microdesc;
4355 int flags = allow_annotations ? TS_ANNOTATIONS_OK : 0;
4357 directory_token_t *tok;
4359 if (!eos)
4360 eos = s + strlen(s);
4362 s = eat_whitespace_eos(s, eos);
4363 area = memarea_new();
4364 result = smartlist_new();
4365 tokens = smartlist_new();
4367 while (s < eos) {
4368 start_of_next_microdesc = find_start_of_next_microdesc(s, eos);
4369 if (!start_of_next_microdesc)
4370 start_of_next_microdesc = eos;
4372 if (tokenize_string(area, s, start_of_next_microdesc, tokens,
4373 microdesc_token_table, flags)) {
4374 log_warn(LD_DIR, "Unparseable microdescriptor");
4375 goto next;
4378 md = tor_malloc_zero(sizeof(microdesc_t));
4380 const char *cp = tor_memstr(s, start_of_next_microdesc-s,
4381 "onion-key");
4382 tor_assert(cp);
4384 md->bodylen = start_of_next_microdesc - cp;
4385 if (copy_body)
4386 md->body = tor_strndup(cp, md->bodylen);
4387 else
4388 md->body = (char*)cp;
4389 md->off = cp - start;
4392 if ((tok = find_opt_by_keyword(tokens, A_LAST_LISTED))) {
4393 if (parse_iso_time(tok->args[0], &md->last_listed)) {
4394 log_warn(LD_DIR, "Bad last-listed time in microdescriptor");
4395 goto next;
4399 tok = find_by_keyword(tokens, K_ONION_KEY);
4400 if (!crypto_pk_public_exponent_ok(tok->key)) {
4401 log_warn(LD_DIR,
4402 "Relay's onion key had invalid exponent.");
4403 goto next;
4405 md->onion_pkey = tok->key;
4406 tok->key = NULL;
4408 if ((tok = find_opt_by_keyword(tokens, K_FAMILY))) {
4409 int i;
4410 md->family = smartlist_new();
4411 for (i=0;i<tok->n_args;++i) {
4412 if (!is_legal_nickname_or_hexdigest(tok->args[i])) {
4413 log_warn(LD_DIR, "Illegal nickname %s in family line",
4414 escaped(tok->args[i]));
4415 goto next;
4417 smartlist_add(md->family, tor_strdup(tok->args[i]));
4421 if ((tok = find_opt_by_keyword(tokens, K_P))) {
4422 md->exit_policy = parse_short_policy(tok->args[0]);
4425 crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256);
4427 smartlist_add(result, md);
4429 md = NULL;
4430 next:
4431 microdesc_free(md);
4432 md = NULL;
4434 memarea_clear(area);
4435 smartlist_clear(tokens);
4436 s = start_of_next_microdesc;
4439 memarea_drop_all(area);
4440 smartlist_free(tokens);
4442 return result;
4445 /** Return true iff this Tor version can answer directory questions
4446 * about microdescriptors. */
4448 tor_version_supports_microdescriptors(const char *platform)
4450 return tor_version_as_new_as(platform, "0.2.3.1-alpha");
4453 /** Parse the Tor version of the platform string <b>platform</b>,
4454 * and compare it to the version in <b>cutoff</b>. Return 1 if
4455 * the router is at least as new as the cutoff, else return 0.
4458 tor_version_as_new_as(const char *platform, const char *cutoff)
4460 tor_version_t cutoff_version, router_version;
4461 char *s, *s2, *start;
4462 char tmp[128];
4464 tor_assert(platform);
4466 if (tor_version_parse(cutoff, &cutoff_version)<0) {
4467 log_warn(LD_BUG,"cutoff version '%s' unparseable.",cutoff);
4468 return 0;
4470 if (strcmpstart(platform,"Tor ")) /* nonstandard Tor; be safe and say yes */
4471 return 1;
4473 start = (char *)eat_whitespace(platform+3);
4474 if (!*start) return 0;
4475 s = (char *)find_whitespace(start); /* also finds '\0', which is fine */
4476 s2 = (char*)eat_whitespace(s);
4477 if (!strcmpstart(s2, "(r") || !strcmpstart(s2, "(git-"))
4478 s = (char*)find_whitespace(s2);
4480 if ((size_t)(s-start+1) >= sizeof(tmp)) /* too big, no */
4481 return 0;
4482 strlcpy(tmp, start, s-start+1);
4484 if (tor_version_parse(tmp, &router_version)<0) {
4485 log_info(LD_DIR,"Router version '%s' unparseable.",tmp);
4486 return 1; /* be safe and say yes */
4489 /* Here's why we don't need to do any special handling for svn revisions:
4490 * - If neither has an svn revision, we're fine.
4491 * - If the router doesn't have an svn revision, we can't assume that it
4492 * is "at least" any svn revision, so we need to return 0.
4493 * - If the target version doesn't have an svn revision, any svn revision
4494 * (or none at all) is good enough, so return 1.
4495 * - If both target and router have an svn revision, we compare them.
4498 return tor_version_compare(&router_version, &cutoff_version) >= 0;
4501 /** Parse a tor version from <b>s</b>, and store the result in <b>out</b>.
4502 * Return 0 on success, -1 on failure. */
4504 tor_version_parse(const char *s, tor_version_t *out)
4506 char *eos=NULL;
4507 const char *cp=NULL;
4508 /* Format is:
4509 * "Tor " ? NUM dot NUM dot NUM [ ( pre | rc | dot ) NUM [ - tag ] ]
4511 tor_assert(s);
4512 tor_assert(out);
4514 memset(out, 0, sizeof(tor_version_t));
4516 if (!strcasecmpstart(s, "Tor "))
4517 s += 4;
4519 /* Get major. */
4520 out->major = (int)strtol(s,&eos,10);
4521 if (!eos || eos==s || *eos != '.') return -1;
4522 cp = eos+1;
4524 /* Get minor */
4525 out->minor = (int) strtol(cp,&eos,10);
4526 if (!eos || eos==cp || *eos != '.') return -1;
4527 cp = eos+1;
4529 /* Get micro */
4530 out->micro = (int) strtol(cp,&eos,10);
4531 if (!eos || eos==cp) return -1;
4532 if (!*eos) {
4533 out->status = VER_RELEASE;
4534 out->patchlevel = 0;
4535 return 0;
4537 cp = eos;
4539 /* Get status */
4540 if (*cp == '.') {
4541 out->status = VER_RELEASE;
4542 ++cp;
4543 } else if (0==strncmp(cp, "pre", 3)) {
4544 out->status = VER_PRE;
4545 cp += 3;
4546 } else if (0==strncmp(cp, "rc", 2)) {
4547 out->status = VER_RC;
4548 cp += 2;
4549 } else {
4550 return -1;
4553 /* Get patchlevel */
4554 out->patchlevel = (int) strtol(cp,&eos,10);
4555 if (!eos || eos==cp) return -1;
4556 cp = eos;
4558 /* Get status tag. */
4559 if (*cp == '-' || *cp == '.')
4560 ++cp;
4561 eos = (char*) find_whitespace(cp);
4562 if (eos-cp >= (int)sizeof(out->status_tag))
4563 strlcpy(out->status_tag, cp, sizeof(out->status_tag));
4564 else {
4565 memcpy(out->status_tag, cp, eos-cp);
4566 out->status_tag[eos-cp] = 0;
4568 cp = eat_whitespace(eos);
4570 if (!strcmpstart(cp, "(r")) {
4571 cp += 2;
4572 out->svn_revision = (int) strtol(cp,&eos,10);
4573 } else if (!strcmpstart(cp, "(git-")) {
4574 char *close_paren = strchr(cp, ')');
4575 int hexlen;
4576 char digest[DIGEST_LEN];
4577 if (! close_paren)
4578 return -1;
4579 cp += 5;
4580 if (close_paren-cp > HEX_DIGEST_LEN)
4581 return -1;
4582 hexlen = (int)(close_paren-cp);
4583 memset(digest, 0, sizeof(digest));
4584 if ( hexlen == 0 || (hexlen % 2) == 1)
4585 return -1;
4586 if (base16_decode(digest, hexlen/2, cp, hexlen))
4587 return -1;
4588 memcpy(out->git_tag, digest, hexlen/2);
4589 out->git_tag_len = hexlen/2;
4592 return 0;
4595 /** Compare two tor versions; Return <0 if a < b; 0 if a ==b, >0 if a >
4596 * b. */
4598 tor_version_compare(tor_version_t *a, tor_version_t *b)
4600 int i;
4601 tor_assert(a);
4602 tor_assert(b);
4603 if ((i = a->major - b->major))
4604 return i;
4605 else if ((i = a->minor - b->minor))
4606 return i;
4607 else if ((i = a->micro - b->micro))
4608 return i;
4609 else if ((i = a->status - b->status))
4610 return i;
4611 else if ((i = a->patchlevel - b->patchlevel))
4612 return i;
4613 else if ((i = strcmp(a->status_tag, b->status_tag)))
4614 return i;
4615 else if ((i = a->svn_revision - b->svn_revision))
4616 return i;
4617 else if ((i = a->git_tag_len - b->git_tag_len))
4618 return i;
4619 else if (a->git_tag_len)
4620 return fast_memcmp(a->git_tag, b->git_tag, a->git_tag_len);
4621 else
4622 return 0;
4625 /** Return true iff versions <b>a</b> and <b>b</b> belong to the same series.
4628 tor_version_same_series(tor_version_t *a, tor_version_t *b)
4630 tor_assert(a);
4631 tor_assert(b);
4632 return ((a->major == b->major) &&
4633 (a->minor == b->minor) &&
4634 (a->micro == b->micro));
4637 /** Helper: Given pointers to two strings describing tor versions, return -1
4638 * if _a precedes _b, 1 if _b precedes _a, and 0 if they are equivalent.
4639 * Used to sort a list of versions. */
4640 static int
4641 _compare_tor_version_str_ptr(const void **_a, const void **_b)
4643 const char *a = *_a, *b = *_b;
4644 int ca, cb;
4645 tor_version_t va, vb;
4646 ca = tor_version_parse(a, &va);
4647 cb = tor_version_parse(b, &vb);
4648 /* If they both parse, compare them. */
4649 if (!ca && !cb)
4650 return tor_version_compare(&va,&vb);
4651 /* If one parses, it comes first. */
4652 if (!ca && cb)
4653 return -1;
4654 if (ca && !cb)
4655 return 1;
4656 /* If neither parses, compare strings. Also, the directory server admin
4657 ** needs to be smacked upside the head. But Tor is tolerant and gentle. */
4658 return strcmp(a,b);
4661 /** Sort a list of string-representations of versions in ascending order. */
4662 void
4663 sort_version_list(smartlist_t *versions, int remove_duplicates)
4665 smartlist_sort(versions, _compare_tor_version_str_ptr);
4667 if (remove_duplicates)
4668 smartlist_uniq(versions, _compare_tor_version_str_ptr, _tor_free);
4671 /** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>,
4672 * write the parsed descriptor to the newly allocated *<b>parsed_out</b>, the
4673 * binary descriptor ID of length DIGEST_LEN to <b>desc_id_out</b>, the
4674 * encrypted introduction points to the newly allocated
4675 * *<b>intro_points_encrypted_out</b>, their encrypted size to
4676 * *<b>intro_points_encrypted_size_out</b>, the size of the encoded descriptor
4677 * to *<b>encoded_size_out</b>, and a pointer to the possibly next
4678 * descriptor to *<b>next_out</b>; return 0 for success (including validation)
4679 * and -1 for failure.
4682 rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
4683 char *desc_id_out,
4684 char **intro_points_encrypted_out,
4685 size_t *intro_points_encrypted_size_out,
4686 size_t *encoded_size_out,
4687 const char **next_out, const char *desc)
4689 rend_service_descriptor_t *result =
4690 tor_malloc_zero(sizeof(rend_service_descriptor_t));
4691 char desc_hash[DIGEST_LEN];
4692 const char *eos;
4693 smartlist_t *tokens = smartlist_new();
4694 directory_token_t *tok;
4695 char secret_id_part[DIGEST_LEN];
4696 int i, version, num_ok=1;
4697 smartlist_t *versions;
4698 char public_key_hash[DIGEST_LEN];
4699 char test_desc_id[DIGEST_LEN];
4700 memarea_t *area = NULL;
4701 tor_assert(desc);
4702 /* Check if desc starts correctly. */
4703 if (strncmp(desc, "rendezvous-service-descriptor ",
4704 strlen("rendezvous-service-descriptor "))) {
4705 log_info(LD_REND, "Descriptor does not start correctly.");
4706 goto err;
4708 /* Compute descriptor hash for later validation. */
4709 if (router_get_hash_impl(desc, strlen(desc), desc_hash,
4710 "rendezvous-service-descriptor ",
4711 "\nsignature", '\n', DIGEST_SHA1) < 0) {
4712 log_warn(LD_REND, "Couldn't compute descriptor hash.");
4713 goto err;
4715 /* Determine end of string. */
4716 eos = strstr(desc, "\nrendezvous-service-descriptor ");
4717 if (!eos)
4718 eos = desc + strlen(desc);
4719 else
4720 eos = eos + 1;
4721 /* Check length. */
4722 if (eos-desc > REND_DESC_MAX_SIZE) {
4723 /* XXX023 If we are parsing this descriptor as a server, this
4724 * should be a protocol warning. */
4725 log_warn(LD_REND, "Descriptor length is %d which exceeds "
4726 "maximum rendezvous descriptor size of %d bytes.",
4727 (int)(eos-desc), REND_DESC_MAX_SIZE);
4728 goto err;
4730 /* Tokenize descriptor. */
4731 area = memarea_new();
4732 if (tokenize_string(area, desc, eos, tokens, desc_token_table, 0)) {
4733 log_warn(LD_REND, "Error tokenizing descriptor.");
4734 goto err;
4736 /* Set next to next descriptor, if available. */
4737 *next_out = eos;
4738 /* Set length of encoded descriptor. */
4739 *encoded_size_out = eos - desc;
4740 /* Check min allowed length of token list. */
4741 if (smartlist_len(tokens) < 7) {
4742 log_warn(LD_REND, "Impossibly short descriptor.");
4743 goto err;
4745 /* Parse base32-encoded descriptor ID. */
4746 tok = find_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR);
4747 tor_assert(tok == smartlist_get(tokens, 0));
4748 tor_assert(tok->n_args == 1);
4749 if (strlen(tok->args[0]) != REND_DESC_ID_V2_LEN_BASE32 ||
4750 strspn(tok->args[0], BASE32_CHARS) != REND_DESC_ID_V2_LEN_BASE32) {
4751 log_warn(LD_REND, "Invalid descriptor ID: '%s'", tok->args[0]);
4752 goto err;
4754 if (base32_decode(desc_id_out, DIGEST_LEN,
4755 tok->args[0], REND_DESC_ID_V2_LEN_BASE32) < 0) {
4756 log_warn(LD_REND, "Descriptor ID contains illegal characters: %s",
4757 tok->args[0]);
4758 goto err;
4760 /* Parse descriptor version. */
4761 tok = find_by_keyword(tokens, R_VERSION);
4762 tor_assert(tok->n_args == 1);
4763 result->version =
4764 (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL);
4765 if (result->version != 2 || !num_ok) {
4766 /* If it's <2, it shouldn't be under this format. If the number
4767 * is greater than 2, we bumped it because we broke backward
4768 * compatibility. See how version numbers in our other formats
4769 * work. */
4770 log_warn(LD_REND, "Unrecognized descriptor version: %s",
4771 escaped(tok->args[0]));
4772 goto err;
4774 /* Parse public key. */
4775 tok = find_by_keyword(tokens, R_PERMANENT_KEY);
4776 result->pk = tok->key;
4777 tok->key = NULL; /* Prevent free */
4778 /* Parse secret ID part. */
4779 tok = find_by_keyword(tokens, R_SECRET_ID_PART);
4780 tor_assert(tok->n_args == 1);
4781 if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 ||
4782 strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) {
4783 log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]);
4784 goto err;
4786 if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) < 0) {
4787 log_warn(LD_REND, "Secret ID part contains illegal characters: %s",
4788 tok->args[0]);
4789 goto err;
4791 /* Parse publication time -- up-to-date check is done when storing the
4792 * descriptor. */
4793 tok = find_by_keyword(tokens, R_PUBLICATION_TIME);
4794 tor_assert(tok->n_args == 1);
4795 if (parse_iso_time(tok->args[0], &result->timestamp) < 0) {
4796 log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]);
4797 goto err;
4799 /* Parse protocol versions. */
4800 tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS);
4801 tor_assert(tok->n_args == 1);
4802 versions = smartlist_new();
4803 smartlist_split_string(versions, tok->args[0], ",",
4804 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
4805 for (i = 0; i < smartlist_len(versions); i++) {
4806 version = (int) tor_parse_long(smartlist_get(versions, i),
4807 10, 0, INT_MAX, &num_ok, NULL);
4808 if (!num_ok) /* It's a string; let's ignore it. */
4809 continue;
4810 result->protocols |= 1 << version;
4812 SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp));
4813 smartlist_free(versions);
4814 /* Parse encrypted introduction points. Don't verify. */
4815 tok = find_opt_by_keyword(tokens, R_INTRODUCTION_POINTS);
4816 if (tok) {
4817 if (strcmp(tok->object_type, "MESSAGE")) {
4818 log_warn(LD_DIR, "Bad object type: introduction points should be of "
4819 "type MESSAGE");
4820 goto err;
4822 *intro_points_encrypted_out = tor_memdup(tok->object_body,
4823 tok->object_size);
4824 *intro_points_encrypted_size_out = tok->object_size;
4825 } else {
4826 *intro_points_encrypted_out = NULL;
4827 *intro_points_encrypted_size_out = 0;
4829 /* Parse and verify signature. */
4830 tok = find_by_keyword(tokens, R_SIGNATURE);
4831 note_crypto_pk_op(VERIFY_RTR);
4832 if (check_signature_token(desc_hash, DIGEST_LEN, tok, result->pk, 0,
4833 "v2 rendezvous service descriptor") < 0)
4834 goto err;
4835 /* Verify that descriptor ID belongs to public key and secret ID part. */
4836 crypto_pk_get_digest(result->pk, public_key_hash);
4837 rend_get_descriptor_id_bytes(test_desc_id, public_key_hash,
4838 secret_id_part);
4839 if (tor_memneq(desc_id_out, test_desc_id, DIGEST_LEN)) {
4840 log_warn(LD_REND, "Parsed descriptor ID does not match "
4841 "computed descriptor ID.");
4842 goto err;
4844 goto done;
4845 err:
4846 rend_service_descriptor_free(result);
4847 result = NULL;
4848 done:
4849 if (tokens) {
4850 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
4851 smartlist_free(tokens);
4853 if (area)
4854 memarea_drop_all(area);
4855 *parsed_out = result;
4856 if (result)
4857 return 0;
4858 return -1;
4861 /** Decrypt the encrypted introduction points in <b>ipos_encrypted</b> of
4862 * length <b>ipos_encrypted_size</b> using <b>descriptor_cookie</b> and
4863 * write the result to a newly allocated string that is pointed to by
4864 * <b>ipos_decrypted</b> and its length to <b>ipos_decrypted_size</b>.
4865 * Return 0 if decryption was successful and -1 otherwise. */
4867 rend_decrypt_introduction_points(char **ipos_decrypted,
4868 size_t *ipos_decrypted_size,
4869 const char *descriptor_cookie,
4870 const char *ipos_encrypted,
4871 size_t ipos_encrypted_size)
4873 tor_assert(ipos_encrypted);
4874 tor_assert(descriptor_cookie);
4875 if (ipos_encrypted_size < 2) {
4876 log_warn(LD_REND, "Size of encrypted introduction points is too "
4877 "small.");
4878 return -1;
4880 if (ipos_encrypted[0] == (int)REND_BASIC_AUTH) {
4881 char iv[CIPHER_IV_LEN], client_id[REND_BASIC_AUTH_CLIENT_ID_LEN],
4882 session_key[CIPHER_KEY_LEN], *dec;
4883 int declen, client_blocks;
4884 size_t pos = 0, len, client_entries_len;
4885 crypto_digest_t *digest;
4886 crypto_cipher_t *cipher;
4887 client_blocks = (int) ipos_encrypted[1];
4888 client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE *
4889 REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
4890 if (ipos_encrypted_size < 2 + client_entries_len + CIPHER_IV_LEN + 1) {
4891 log_warn(LD_REND, "Size of encrypted introduction points is too "
4892 "small.");
4893 return -1;
4895 memcpy(iv, ipos_encrypted + 2 + client_entries_len, CIPHER_IV_LEN);
4896 digest = crypto_digest_new();
4897 crypto_digest_add_bytes(digest, descriptor_cookie, REND_DESC_COOKIE_LEN);
4898 crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN);
4899 crypto_digest_get_digest(digest, client_id,
4900 REND_BASIC_AUTH_CLIENT_ID_LEN);
4901 crypto_digest_free(digest);
4902 for (pos = 2; pos < 2 + client_entries_len;
4903 pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN) {
4904 if (tor_memeq(ipos_encrypted + pos, client_id,
4905 REND_BASIC_AUTH_CLIENT_ID_LEN)) {
4906 /* Attempt to decrypt introduction points. */
4907 cipher = crypto_cipher_new(descriptor_cookie);
4908 if (crypto_cipher_decrypt(cipher, session_key, ipos_encrypted
4909 + pos + REND_BASIC_AUTH_CLIENT_ID_LEN,
4910 CIPHER_KEY_LEN) < 0) {
4911 log_warn(LD_REND, "Could not decrypt session key for client.");
4912 crypto_cipher_free(cipher);
4913 return -1;
4915 crypto_cipher_free(cipher);
4917 len = ipos_encrypted_size - 2 - client_entries_len - CIPHER_IV_LEN;
4918 dec = tor_malloc(len);
4919 declen = crypto_cipher_decrypt_with_iv(session_key, dec, len,
4920 ipos_encrypted + 2 + client_entries_len,
4921 ipos_encrypted_size - 2 - client_entries_len);
4923 if (declen < 0) {
4924 log_warn(LD_REND, "Could not decrypt introduction point string.");
4925 tor_free(dec);
4926 return -1;
4928 if (fast_memcmpstart(dec, declen, "introduction-point ")) {
4929 log_warn(LD_REND, "Decrypted introduction points don't "
4930 "look like we could parse them.");
4931 tor_free(dec);
4932 continue;
4934 *ipos_decrypted = dec;
4935 *ipos_decrypted_size = declen;
4936 return 0;
4939 log_warn(LD_REND, "Could not decrypt introduction points. Please "
4940 "check your authorization for this service!");
4941 return -1;
4942 } else if (ipos_encrypted[0] == (int)REND_STEALTH_AUTH) {
4943 char *dec;
4944 int declen;
4945 if (ipos_encrypted_size < CIPHER_IV_LEN + 2) {
4946 log_warn(LD_REND, "Size of encrypted introduction points is too "
4947 "small.");
4948 return -1;
4950 dec = tor_malloc_zero(ipos_encrypted_size - CIPHER_IV_LEN - 1);
4952 declen = crypto_cipher_decrypt_with_iv(descriptor_cookie, dec,
4953 ipos_encrypted_size -
4954 CIPHER_IV_LEN - 1,
4955 ipos_encrypted + 1,
4956 ipos_encrypted_size - 1);
4958 if (declen < 0) {
4959 log_warn(LD_REND, "Decrypting introduction points failed!");
4960 tor_free(dec);
4961 return -1;
4963 *ipos_decrypted = dec;
4964 *ipos_decrypted_size = declen;
4965 return 0;
4966 } else {
4967 log_warn(LD_REND, "Unknown authorization type number: %d",
4968 ipos_encrypted[0]);
4969 return -1;
4973 /** Parse the encoded introduction points in <b>intro_points_encoded</b> of
4974 * length <b>intro_points_encoded_size</b> and write the result to the
4975 * descriptor in <b>parsed</b>; return the number of successfully parsed
4976 * introduction points or -1 in case of a failure. */
4978 rend_parse_introduction_points(rend_service_descriptor_t *parsed,
4979 const char *intro_points_encoded,
4980 size_t intro_points_encoded_size)
4982 const char *current_ipo, *end_of_intro_points;
4983 smartlist_t *tokens;
4984 directory_token_t *tok;
4985 rend_intro_point_t *intro;
4986 extend_info_t *info;
4987 int result, num_ok=1;
4988 memarea_t *area = NULL;
4989 tor_assert(parsed);
4990 /** Function may only be invoked once. */
4991 tor_assert(!parsed->intro_nodes);
4992 tor_assert(intro_points_encoded);
4993 tor_assert(intro_points_encoded_size > 0);
4994 /* Consider one intro point after the other. */
4995 current_ipo = intro_points_encoded;
4996 end_of_intro_points = intro_points_encoded + intro_points_encoded_size;
4997 tokens = smartlist_new();
4998 parsed->intro_nodes = smartlist_new();
4999 area = memarea_new();
5001 while (!fast_memcmpstart(current_ipo, end_of_intro_points-current_ipo,
5002 "introduction-point ")) {
5003 /* Determine end of string. */
5004 const char *eos = tor_memstr(current_ipo, end_of_intro_points-current_ipo,
5005 "\nintroduction-point ");
5006 if (!eos)
5007 eos = end_of_intro_points;
5008 else
5009 eos = eos+1;
5010 tor_assert(eos <= intro_points_encoded+intro_points_encoded_size);
5011 /* Free tokens and clear token list. */
5012 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
5013 smartlist_clear(tokens);
5014 memarea_clear(area);
5015 /* Tokenize string. */
5016 if (tokenize_string(area, current_ipo, eos, tokens, ipo_token_table, 0)) {
5017 log_warn(LD_REND, "Error tokenizing introduction point");
5018 goto err;
5020 /* Advance to next introduction point, if available. */
5021 current_ipo = eos;
5022 /* Check minimum allowed length of introduction point. */
5023 if (smartlist_len(tokens) < 5) {
5024 log_warn(LD_REND, "Impossibly short introduction point.");
5025 goto err;
5027 /* Allocate new intro point and extend info. */
5028 intro = tor_malloc_zero(sizeof(rend_intro_point_t));
5029 info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
5030 /* Parse identifier. */
5031 tok = find_by_keyword(tokens, R_IPO_IDENTIFIER);
5032 if (base32_decode(info->identity_digest, DIGEST_LEN,
5033 tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) {
5034 log_warn(LD_REND, "Identity digest contains illegal characters: %s",
5035 tok->args[0]);
5036 rend_intro_point_free(intro);
5037 goto err;
5039 /* Write identifier to nickname. */
5040 info->nickname[0] = '$';
5041 base16_encode(info->nickname + 1, sizeof(info->nickname) - 1,
5042 info->identity_digest, DIGEST_LEN);
5043 /* Parse IP address. */
5044 tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS);
5045 if (tor_addr_parse(&info->addr, tok->args[0])<0) {
5046 log_warn(LD_REND, "Could not parse introduction point address.");
5047 rend_intro_point_free(intro);
5048 goto err;
5050 if (tor_addr_family(&info->addr) != AF_INET) {
5051 log_warn(LD_REND, "Introduction point address was not ipv4.");
5052 rend_intro_point_free(intro);
5053 goto err;
5056 /* Parse onion port. */
5057 tok = find_by_keyword(tokens, R_IPO_ONION_PORT);
5058 info->port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535,
5059 &num_ok,NULL);
5060 if (!info->port || !num_ok) {
5061 log_warn(LD_REND, "Introduction point onion port %s is invalid",
5062 escaped(tok->args[0]));
5063 rend_intro_point_free(intro);
5064 goto err;
5066 /* Parse onion key. */
5067 tok = find_by_keyword(tokens, R_IPO_ONION_KEY);
5068 if (!crypto_pk_public_exponent_ok(tok->key)) {
5069 log_warn(LD_REND,
5070 "Introduction point's onion key had invalid exponent.");
5071 rend_intro_point_free(intro);
5072 goto err;
5074 info->onion_key = tok->key;
5075 tok->key = NULL; /* Prevent free */
5076 /* Parse service key. */
5077 tok = find_by_keyword(tokens, R_IPO_SERVICE_KEY);
5078 if (!crypto_pk_public_exponent_ok(tok->key)) {
5079 log_warn(LD_REND,
5080 "Introduction point key had invalid exponent.");
5081 rend_intro_point_free(intro);
5082 goto err;
5084 intro->intro_key = tok->key;
5085 tok->key = NULL; /* Prevent free */
5086 /* Add extend info to list of introduction points. */
5087 smartlist_add(parsed->intro_nodes, intro);
5089 result = smartlist_len(parsed->intro_nodes);
5090 goto done;
5092 err:
5093 result = -1;
5095 done:
5096 /* Free tokens and clear token list. */
5097 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
5098 smartlist_free(tokens);
5099 if (area)
5100 memarea_drop_all(area);
5102 return result;
5105 /** Parse the content of a client_key file in <b>ckstr</b> and add
5106 * rend_authorized_client_t's for each parsed client to
5107 * <b>parsed_clients</b>. Return the number of parsed clients as result
5108 * or -1 for failure. */
5110 rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr)
5112 int result = -1;
5113 smartlist_t *tokens;
5114 directory_token_t *tok;
5115 const char *current_entry = NULL;
5116 memarea_t *area = NULL;
5117 if (!ckstr || strlen(ckstr) == 0)
5118 return -1;
5119 tokens = smartlist_new();
5120 /* Begin parsing with first entry, skipping comments or whitespace at the
5121 * beginning. */
5122 area = memarea_new();
5123 current_entry = eat_whitespace(ckstr);
5124 while (!strcmpstart(current_entry, "client-name ")) {
5125 rend_authorized_client_t *parsed_entry;
5126 size_t len;
5127 char descriptor_cookie_tmp[REND_DESC_COOKIE_LEN+2];
5128 /* Determine end of string. */
5129 const char *eos = strstr(current_entry, "\nclient-name ");
5130 if (!eos)
5131 eos = current_entry + strlen(current_entry);
5132 else
5133 eos = eos + 1;
5134 /* Free tokens and clear token list. */
5135 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
5136 smartlist_clear(tokens);
5137 memarea_clear(area);
5138 /* Tokenize string. */
5139 if (tokenize_string(area, current_entry, eos, tokens,
5140 client_keys_token_table, 0)) {
5141 log_warn(LD_REND, "Error tokenizing client keys file.");
5142 goto err;
5144 /* Advance to next entry, if available. */
5145 current_entry = eos;
5146 /* Check minimum allowed length of token list. */
5147 if (smartlist_len(tokens) < 2) {
5148 log_warn(LD_REND, "Impossibly short client key entry.");
5149 goto err;
5151 /* Parse client name. */
5152 tok = find_by_keyword(tokens, C_CLIENT_NAME);
5153 tor_assert(tok == smartlist_get(tokens, 0));
5154 tor_assert(tok->n_args == 1);
5156 len = strlen(tok->args[0]);
5157 if (len < 1 || len > 19 ||
5158 strspn(tok->args[0], REND_LEGAL_CLIENTNAME_CHARACTERS) != len) {
5159 log_warn(LD_CONFIG, "Illegal client name: %s. (Length must be "
5160 "between 1 and 19, and valid characters are "
5161 "[A-Za-z0-9+-_].)", tok->args[0]);
5162 goto err;
5164 /* Check if client name is duplicate. */
5165 if (strmap_get(parsed_clients, tok->args[0])) {
5166 log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains a "
5167 "duplicate client name: '%s'. Ignoring.", tok->args[0]);
5168 goto err;
5170 parsed_entry = tor_malloc_zero(sizeof(rend_authorized_client_t));
5171 parsed_entry->client_name = tor_strdup(tok->args[0]);
5172 strmap_set(parsed_clients, parsed_entry->client_name, parsed_entry);
5173 /* Parse client key. */
5174 tok = find_opt_by_keyword(tokens, C_CLIENT_KEY);
5175 if (tok) {
5176 parsed_entry->client_key = tok->key;
5177 tok->key = NULL; /* Prevent free */
5180 /* Parse descriptor cookie. */
5181 tok = find_by_keyword(tokens, C_DESCRIPTOR_COOKIE);
5182 tor_assert(tok->n_args == 1);
5183 if (strlen(tok->args[0]) != REND_DESC_COOKIE_LEN_BASE64 + 2) {
5184 log_warn(LD_REND, "Descriptor cookie has illegal length: %s",
5185 escaped(tok->args[0]));
5186 goto err;
5188 /* The size of descriptor_cookie_tmp needs to be REND_DESC_COOKIE_LEN+2,
5189 * because a base64 encoding of length 24 does not fit into 16 bytes in all
5190 * cases. */
5191 if (base64_decode(descriptor_cookie_tmp, sizeof(descriptor_cookie_tmp),
5192 tok->args[0], strlen(tok->args[0]))
5193 != REND_DESC_COOKIE_LEN) {
5194 log_warn(LD_REND, "Descriptor cookie contains illegal characters: "
5195 "%s", escaped(tok->args[0]));
5196 goto err;
5198 memcpy(parsed_entry->descriptor_cookie, descriptor_cookie_tmp,
5199 REND_DESC_COOKIE_LEN);
5201 result = strmap_size(parsed_clients);
5202 goto done;
5203 err:
5204 result = -1;
5205 done:
5206 /* Free tokens and clear token list. */
5207 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
5208 smartlist_free(tokens);
5209 if (area)
5210 memarea_drop_all(area);
5211 return result;