Rename a field so weasel likes it better
[tor/rransom.git] / src / or / routerparse.c
blobf5dc3ff0b7b0c8a306f7d58f5f6d1b9b00252a58
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-2008, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
6 /* $Id$ */
7 const char routerparse_c_id[] =
8 "$Id$";
10 /**
11 * \file routerparse.c
12 * \brief Code to parse and validate router descriptors and directories.
13 **/
15 #include "or.h"
16 #include "memarea.h"
18 /****************************************************************************/
20 /** Enumeration of possible token types. The ones starting with K_ correspond
21 * to directory 'keywords'. _ERR is an error in the tokenizing process, _EOF
22 * is an end-of-file marker, and _NIL is used to encode not-a-token.
24 typedef enum {
25 K_ACCEPT = 0,
26 K_ACCEPT6,
27 K_DIRECTORY_SIGNATURE,
28 K_RECOMMENDED_SOFTWARE,
29 K_REJECT,
30 K_REJECT6,
31 K_ROUTER,
32 K_SIGNED_DIRECTORY,
33 K_SIGNING_KEY,
34 K_ONION_KEY,
35 K_ROUTER_SIGNATURE,
36 K_PUBLISHED,
37 K_RUNNING_ROUTERS,
38 K_ROUTER_STATUS,
39 K_PLATFORM,
40 K_OPT,
41 K_BANDWIDTH,
42 K_CONTACT,
43 K_NETWORK_STATUS,
44 K_UPTIME,
45 K_DIR_SIGNING_KEY,
46 K_FAMILY,
47 K_FINGERPRINT,
48 K_HIBERNATING,
49 K_READ_HISTORY,
50 K_WRITE_HISTORY,
51 K_NETWORK_STATUS_VERSION,
52 K_DIR_SOURCE,
53 K_DIR_OPTIONS,
54 K_CLIENT_VERSIONS,
55 K_SERVER_VERSIONS,
56 K_P,
57 K_R,
58 K_S,
59 K_V,
60 K_W,
61 K_EVENTDNS,
62 K_EXTRA_INFO,
63 K_EXTRA_INFO_DIGEST,
64 K_CACHES_EXTRA_INFO,
65 K_HIDDEN_SERVICE_DIR,
67 K_DIR_KEY_CERTIFICATE_VERSION,
68 K_DIR_IDENTITY_KEY,
69 K_DIR_KEY_PUBLISHED,
70 K_DIR_KEY_EXPIRES,
71 K_DIR_KEY_CERTIFICATION,
72 K_DIR_ADDRESS,
74 K_VOTE_STATUS,
75 K_VALID_AFTER,
76 K_FRESH_UNTIL,
77 K_VALID_UNTIL,
78 K_VOTING_DELAY,
80 K_KNOWN_FLAGS,
81 K_VOTE_DIGEST,
82 K_CONSENSUS_DIGEST,
83 K_CONSENSUS_METHODS,
84 K_CONSENSUS_METHOD,
85 K_LEGACY_DIR_KEY,
87 A_PURPOSE,
88 _A_UNKNOWN,
90 R_RENDEZVOUS_SERVICE_DESCRIPTOR,
91 R_VERSION,
92 R_PERMANENT_KEY,
93 R_SECRET_ID_PART,
94 R_PUBLICATION_TIME,
95 R_PROTOCOL_VERSIONS,
96 R_INTRODUCTION_POINTS,
97 R_SIGNATURE,
99 R_IPO_IDENTIFIER,
100 R_IPO_IP_ADDRESS,
101 R_IPO_ONION_PORT,
102 R_IPO_ONION_KEY,
103 R_IPO_SERVICE_KEY,
105 C_CLIENT_NAME,
106 C_DESCRIPTOR_COOKIE,
107 C_CLIENT_KEY,
109 _UNRECOGNIZED,
110 _ERR,
111 _EOF,
112 _NIL
113 } directory_keyword;
115 #define MIN_ANNOTATION A_PURPOSE
116 #define MAX_ANNOTATION _A_UNKNOWN
118 /** Structure to hold a single directory token.
120 * We parse a directory by breaking it into "tokens", each consisting
121 * of a keyword, a line full of arguments, and a binary object. The
122 * arguments and object are both optional, depending on the keyword
123 * type.
125 * This structure is only allocated in memareas; do not allocate it on
126 * the heap, or token_free() won't work.
128 typedef struct directory_token_t {
129 directory_keyword tp; /**< Type of the token. */
130 int n_args:30; /**< Number of elements in args */
131 char **args; /**< Array of arguments from keyword line. */
133 char *object_type; /**< -----BEGIN [object_type]-----*/
134 size_t object_size; /**< Bytes in object_body */
135 char *object_body; /**< Contents of object, base64-decoded. */
137 crypto_pk_env_t *key; /**< For public keys only. Heap-allocated. */
139 char *error; /**< For _ERR tokens only. */
140 } directory_token_t;
142 /* ********************************************************************** */
144 /** We use a table of rules to decide how to parse each token type. */
146 /** Rules for whether the keyword needs an object. */
147 typedef enum {
148 NO_OBJ, /**< No object, ever. */
149 NEED_OBJ, /**< Object is required. */
150 NEED_SKEY_1024,/**< Object is required, and must be a 1024 bit private key */
151 NEED_KEY_1024, /**< Object is required, and must be a 1024 bit public key */
152 NEED_KEY, /**< Object is required, and must be a public key. */
153 OBJ_OK, /**< Object is optional. */
154 } obj_syntax;
156 #define AT_START 1
157 #define AT_END 2
159 /** Determines the parsing rules for a single token type. */
160 typedef struct token_rule_t {
161 /** The string value of the keyword identifying the type of item. */
162 const char *t;
163 /** The corresponding directory_keyword enum. */
164 directory_keyword v;
165 /** Minimum number of arguments for this item */
166 int min_args;
167 /** Maximum number of arguments for this item */
168 int max_args;
169 /** If true, we concatenate all arguments for this item into a single
170 * string. */
171 int concat_args;
172 /** Requirments on object syntax for this item. */
173 obj_syntax os;
174 /** Lowest number of times this item may appear in a document. */
175 int min_cnt;
176 /** Highest number of times this item may appear in a document. */
177 int max_cnt;
178 /** One or more of AT_START/AT_END to limit where the item may appear in a
179 * document. */
180 int pos;
181 /** True iff this token is an annotation. */
182 int is_annotation;
183 } token_rule_t;
186 * Helper macros to define token tables. 's' is a string, 't' is a
187 * directory_keyword, 'a' is a trio of argument multiplicities, and 'o' is an
188 * object syntax.
192 /** Appears to indicate the end of a table. */
193 #define END_OF_TABLE { NULL, _NIL, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 }
194 /** An item with no restrictions: used for obsolete document types */
195 #define T(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 }
196 /** An item with no restrictions on multiplicity or location. */
197 #define T0N(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 }
198 /** An item that must appear exactly once */
199 #define T1(s,t,a,o) { s, t, a, o, 1, 1, 0, 0 }
200 /** An item that must appear exactly once, at the start of the document */
201 #define T1_START(s,t,a,o) { s, t, a, o, 1, 1, AT_START, 0 }
202 /** An item that must appear exactly once, at the end of the document */
203 #define T1_END(s,t,a,o) { s, t, a, o, 1, 1, AT_END, 0 }
204 /** An item that must appear one or more times */
205 #define T1N(s,t,a,o) { s, t, a, o, 1, INT_MAX, 0, 0 }
206 /** An item that must appear no more than once */
207 #define T01(s,t,a,o) { s, t, a, o, 0, 1, 0, 0 }
208 /** An annotation that must appear no more than once */
209 #define A01(s,t,a,o) { s, t, a, o, 0, 1, 0, 0 }
211 /* Argument multiplicity: any number of arguments. */
212 #define ARGS 0,INT_MAX,0
213 /* Argument multiplicity: no arguments. */
214 #define NO_ARGS 0,0,0
215 /* Argument multiplicity: concatenate all arguments. */
216 #define CONCAT_ARGS 1,1,1
217 /* Argument multiplicity: at least <b>n</b> arguments. */
218 #define GE(n) n,INT_MAX,0
219 /* Argument multiplicity: exactly <b>n</b> arguments. */
220 #define EQ(n) n,n,0
222 /** List of tokens allowable in router derscriptors */
223 static token_rule_t routerdesc_token_table[] = {
224 T0N("reject", K_REJECT, ARGS, NO_OBJ ),
225 T0N("accept", K_ACCEPT, ARGS, NO_OBJ ),
226 T0N("reject6", K_REJECT6, ARGS, NO_OBJ ),
227 T0N("accept6", K_ACCEPT6, ARGS, NO_OBJ ),
228 T1_START( "router", K_ROUTER, GE(5), NO_OBJ ),
229 T1( "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ),
230 T1( "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ),
231 T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
232 T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
233 T01("uptime", K_UPTIME, GE(1), NO_OBJ ),
234 T01("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
235 T01("hibernating", K_HIBERNATING, GE(1), NO_OBJ ),
236 T01("platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ ),
237 T01("contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
238 T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ),
239 T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ),
240 T01("extra-info-digest", K_EXTRA_INFO_DIGEST, GE(1), NO_OBJ ),
241 T01("hidden-service-dir", K_HIDDEN_SERVICE_DIR, NO_ARGS, NO_OBJ ),
243 T01("family", K_FAMILY, ARGS, NO_OBJ ),
244 T01("caches-extra-info", K_CACHES_EXTRA_INFO, NO_ARGS, NO_OBJ ),
245 T01("eventdns", K_EVENTDNS, ARGS, NO_OBJ ),
247 T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
248 T1( "bandwidth", K_BANDWIDTH, GE(3), NO_OBJ ),
249 A01("@purpose", A_PURPOSE, GE(1), NO_OBJ ),
251 END_OF_TABLE
254 /** List of tokens allowable in extra-info documents. */
255 static token_rule_t extrainfo_token_table[] = {
256 T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
257 T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
258 T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
259 T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ),
260 T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ),
261 T1_START( "extra-info", K_EXTRA_INFO, GE(2), NO_OBJ ),
263 END_OF_TABLE
266 /** List of tokens allowable in the body part of v2 and v3 networkstatus
267 * documents. */
268 static token_rule_t rtrstatus_token_table[] = {
269 T01("p", K_P, GE(2), NO_OBJ ),
270 T1( "r", K_R, GE(8), NO_OBJ ),
271 T1( "s", K_S, ARGS, NO_OBJ ),
272 T01("v", K_V, CONCAT_ARGS, NO_OBJ ),
273 T01("w", K_W, ARGS, NO_OBJ ),
274 T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
275 END_OF_TABLE
278 /** List of tokens allowable in the header part of v2 networkstatus documents.
280 static token_rule_t netstatus_token_table[] = {
281 T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
282 T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
283 T1( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
284 T1( "dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ),
285 T1( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
286 T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
287 GE(1), NO_OBJ ),
288 T1( "dir-source", K_DIR_SOURCE, GE(3), NO_OBJ ),
289 T01("dir-options", K_DIR_OPTIONS, ARGS, NO_OBJ ),
290 T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
291 T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
293 END_OF_TABLE
296 /** List of tokens allowable in the footer of v1/v2 directory/networkstatus
297 * footers. */
298 static token_rule_t dir_footer_token_table[] = {
299 T1("directory-signature", K_DIRECTORY_SIGNATURE, EQ(1), NEED_OBJ ),
300 END_OF_TABLE
303 /** List of tokens allowable in v1 directory headers/footers. */
304 static token_rule_t dir_token_table[] = {
305 /* don't enforce counts; this is obsolete. */
306 T( "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ ),
307 T( "directory-signature", K_DIRECTORY_SIGNATURE, ARGS, NEED_OBJ ),
308 T( "recommended-software",K_RECOMMENDED_SOFTWARE,CONCAT_ARGS, NO_OBJ ),
309 T( "signed-directory", K_SIGNED_DIRECTORY, NO_ARGS, NO_OBJ ),
311 T( "running-routers", K_RUNNING_ROUTERS, ARGS, NO_OBJ ),
312 T( "router-status", K_ROUTER_STATUS, ARGS, NO_OBJ ),
313 T( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
314 T( "opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
315 T( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
316 T( "dir-signing-key", K_DIR_SIGNING_KEY, ARGS, OBJ_OK ),
317 T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
319 END_OF_TABLE
322 #define CERTIFICATE_MEMBERS \
323 T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION, \
324 GE(1), NO_OBJ ), \
325 T1("dir-identity-key", K_DIR_IDENTITY_KEY, NO_ARGS, NEED_KEY ),\
326 T1("dir-key-published",K_DIR_KEY_PUBLISHED, CONCAT_ARGS, NO_OBJ), \
327 T1("dir-key-expires", K_DIR_KEY_EXPIRES, CONCAT_ARGS, NO_OBJ), \
328 T1("dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY ),\
329 T1("dir-key-certification", K_DIR_KEY_CERTIFICATION, \
330 NO_ARGS, NEED_OBJ), \
331 T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ),
333 static token_rule_t dir_key_certificate_table[] = {
334 CERTIFICATE_MEMBERS
335 T1("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
336 END_OF_TABLE
339 /** List of tokens allowable in rendezvous service descriptors */
340 static token_rule_t desc_token_table[] = {
341 T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR,
342 EQ(1), NO_OBJ),
343 T1("version", R_VERSION, EQ(1), NO_OBJ),
344 T1("permanent-key", R_PERMANENT_KEY, NO_ARGS, NEED_KEY_1024),
345 T1("secret-id-part", R_SECRET_ID_PART, EQ(1), NO_OBJ),
346 T1("publication-time", R_PUBLICATION_TIME, CONCAT_ARGS, NO_OBJ),
347 T1("protocol-versions", R_PROTOCOL_VERSIONS, EQ(1), NO_OBJ),
348 T01("introduction-points", R_INTRODUCTION_POINTS, NO_ARGS, NEED_OBJ),
349 T1_END("signature", R_SIGNATURE, NO_ARGS, NEED_OBJ),
350 END_OF_TABLE
353 /** List of tokens allowed in the (encrypted) list of introduction points of
354 * rendezvous service descriptors */
355 static token_rule_t ipo_token_table[] = {
356 T1_START("introduction-point", R_IPO_IDENTIFIER, EQ(1), NO_OBJ),
357 T1("ip-address", R_IPO_IP_ADDRESS, EQ(1), NO_OBJ),
358 T1("onion-port", R_IPO_ONION_PORT, EQ(1), NO_OBJ),
359 T1("onion-key", R_IPO_ONION_KEY, NO_ARGS, NEED_KEY_1024),
360 T1("service-key", R_IPO_SERVICE_KEY, NO_ARGS, NEED_KEY_1024),
361 END_OF_TABLE
364 /** List of tokens allowed in the (possibly encrypted) list of introduction
365 * points of rendezvous service descriptors */
366 static token_rule_t client_keys_token_table[] = {
367 T1_START("client-name", C_CLIENT_NAME, CONCAT_ARGS, NO_OBJ),
368 T1("descriptor-cookie", C_DESCRIPTOR_COOKIE, EQ(1), NO_OBJ),
369 T01("client-key", C_CLIENT_KEY, NO_ARGS, NEED_SKEY_1024),
370 END_OF_TABLE
373 static token_rule_t networkstatus_token_table[] = {
374 T1("network-status-version", K_NETWORK_STATUS_VERSION,
375 GE(1), NO_OBJ ),
376 T1("vote-status", K_VOTE_STATUS, GE(1), NO_OBJ ),
377 T1("published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
378 T1("valid-after", K_VALID_AFTER, CONCAT_ARGS, NO_OBJ ),
379 T1("fresh-until", K_FRESH_UNTIL, CONCAT_ARGS, NO_OBJ ),
380 T1("valid-until", K_VALID_UNTIL, CONCAT_ARGS, NO_OBJ ),
381 T1("voting-delay", K_VOTING_DELAY, GE(2), NO_OBJ ),
382 T1("known-flags", K_KNOWN_FLAGS, ARGS, NO_OBJ ),
383 T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
385 CERTIFICATE_MEMBERS
387 T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
388 T1( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
389 T1( "dir-source", K_DIR_SOURCE, GE(6), NO_OBJ ),
390 T01("legacy-dir-key", K_LEGACY_DIR_KEY, GE(1), NO_OBJ ),
391 T1( "known-flags", K_KNOWN_FLAGS, CONCAT_ARGS, NO_OBJ ),
392 T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
393 T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
394 T1( "consensus-methods", K_CONSENSUS_METHODS, GE(1), NO_OBJ ),
396 END_OF_TABLE
398 static token_rule_t networkstatus_consensus_token_table[] = {
399 T1("network-status-version", K_NETWORK_STATUS_VERSION,
400 GE(1), NO_OBJ ),
401 T1("vote-status", K_VOTE_STATUS, GE(1), NO_OBJ ),
402 T1("valid-after", K_VALID_AFTER, CONCAT_ARGS, NO_OBJ ),
403 T1("fresh-until", K_FRESH_UNTIL, CONCAT_ARGS, NO_OBJ ),
404 T1("valid-until", K_VALID_UNTIL, CONCAT_ARGS, NO_OBJ ),
405 T1("voting-delay", K_VOTING_DELAY, GE(2), NO_OBJ ),
407 T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
409 T1N("dir-source", K_DIR_SOURCE, GE(3), NO_OBJ ),
410 T1N("contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
411 T1N("vote-digest", K_VOTE_DIGEST, GE(1), NO_OBJ ),
413 T1( "known-flags", K_KNOWN_FLAGS, CONCAT_ARGS, NO_OBJ ),
415 T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
416 T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
417 T01("consensus-method", K_CONSENSUS_METHOD, EQ(1), NO_OBJ),
419 END_OF_TABLE
422 /** List of tokens allowable in the footer of v1/v2 directory/networkstatus
423 * footers. */
424 static token_rule_t networkstatus_vote_footer_token_table[] = {
425 T( "directory-signature", K_DIRECTORY_SIGNATURE, GE(2), NEED_OBJ ),
426 END_OF_TABLE
429 static token_rule_t networkstatus_detached_signature_token_table[] = {
430 T1_START("consensus-digest", K_CONSENSUS_DIGEST, GE(1), NO_OBJ ),
431 T1("valid-after", K_VALID_AFTER, CONCAT_ARGS, NO_OBJ ),
432 T1("fresh-until", K_FRESH_UNTIL, CONCAT_ARGS, NO_OBJ ),
433 T1("valid-until", K_VALID_UNTIL, CONCAT_ARGS, NO_OBJ ),
434 T1N("directory-signature", K_DIRECTORY_SIGNATURE, GE(2), NEED_OBJ ),
435 END_OF_TABLE
438 #undef T
440 /* static function prototypes */
441 static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok);
442 static addr_policy_t *router_parse_addr_policy(directory_token_t *tok);
443 static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok);
445 static int router_get_hash_impl(const char *s, char *digest,
446 const char *start_str, const char *end_str,
447 char end_char);
448 static void token_free(directory_token_t *tok);
449 static smartlist_t *find_all_exitpolicy(smartlist_t *s);
450 static directory_token_t *find_first_by_keyword(smartlist_t *s,
451 directory_keyword keyword);
452 #define TS_ANNOTATIONS_OK 1
453 #define TS_NOCHECK 2
454 #define TS_NO_NEW_ANNOTATIONS 4
455 static int tokenize_string(memarea_t *area,
456 const char *start, const char *end,
457 smartlist_t *out,
458 token_rule_t *table,
459 int flags);
460 static directory_token_t *get_next_token(memarea_t *area,
461 const char **s,
462 const char *eos,
463 token_rule_t *table);
464 static int check_signature_token(const char *digest,
465 directory_token_t *tok,
466 crypto_pk_env_t *pkey,
467 int check_authority,
468 const char *doctype);
469 static crypto_pk_env_t *find_dir_signing_key(const char *str, const char *eos);
470 static int tor_version_same_series(tor_version_t *a, tor_version_t *b);
472 #undef DEBUG_AREA_ALLOC
474 #ifdef DEBUG_AREA_ALLOC
475 #define DUMP_AREA(a,name) STMT_BEGIN \
476 size_t alloc=0, used=0; \
477 memarea_get_stats((a),&alloc,&used); \
478 log_debug(LD_MM, "Area for %s has %lu allocated; using %lu.", \
479 name, (unsigned long)alloc, (unsigned long)used); \
480 STMT_END
481 #else
482 #define DUMP_AREA(a,name) STMT_NIL
483 #endif
485 /** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
486 * <b>s</b>. Return 0 on success, -1 on failure.
489 router_get_dir_hash(const char *s, char *digest)
491 return router_get_hash_impl(s,digest,
492 "signed-directory","\ndirectory-signature",'\n');
495 /** Set <b>digest</b> to the SHA-1 digest of the hash of the first router in
496 * <b>s</b>. Return 0 on success, -1 on failure.
499 router_get_router_hash(const char *s, char *digest)
501 return router_get_hash_impl(s,digest,
502 "router ","\nrouter-signature", '\n');
505 /** Set <b>digest</b> to the SHA-1 digest of the hash of the running-routers
506 * string in <b>s</b>. Return 0 on success, -1 on failure.
509 router_get_runningrouters_hash(const char *s, char *digest)
511 return router_get_hash_impl(s,digest,
512 "network-status","\ndirectory-signature", '\n');
515 /** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status
516 * string in <b>s</b>. Return 0 on success, -1 on failure. */
518 router_get_networkstatus_v2_hash(const char *s, char *digest)
520 return router_get_hash_impl(s,digest,
521 "network-status-version","\ndirectory-signature",
522 '\n');
525 /** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status
526 * string in <b>s</b>. Return 0 on success, -1 on failure. */
528 router_get_networkstatus_v3_hash(const char *s, char *digest)
530 return router_get_hash_impl(s,digest,
531 "network-status-version","\ndirectory-signature",
532 ' ');
535 /** Set <b>digest</b> to the SHA-1 digest of the hash of the extrainfo
536 * string in <b>s</b>. Return 0 on success, -1 on failure. */
538 router_get_extrainfo_hash(const char *s, char *digest)
540 return router_get_hash_impl(s,digest,"extra-info","\nrouter-signature",'\n');
543 /** Helper: used to generate signatures for routers, directories and
544 * network-status objects. Given a digest in <b>digest</b> and a secret
545 * <b>private_key</b>, generate an PKCS1-padded signature, BASE64-encode it,
546 * surround it with -----BEGIN/END----- pairs, and write it to the
547 * <b>buf_len</b>-byte buffer at <b>buf</b>. Return 0 on success, -1 on
548 * failure.
551 router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
552 crypto_pk_env_t *private_key)
554 char *signature;
555 size_t i;
557 signature = tor_malloc(crypto_pk_keysize(private_key));
558 if (crypto_pk_private_sign(private_key, signature, digest, DIGEST_LEN) < 0) {
560 log_warn(LD_BUG,"Couldn't sign digest.");
561 goto err;
563 if (strlcat(buf, "-----BEGIN SIGNATURE-----\n", buf_len) >= buf_len)
564 goto truncated;
566 i = strlen(buf);
567 if (base64_encode(buf+i, buf_len-i, signature, 128) < 0) {
568 log_warn(LD_BUG,"couldn't base64-encode signature");
569 goto err;
572 if (strlcat(buf, "-----END SIGNATURE-----\n", buf_len) >= buf_len)
573 goto truncated;
575 tor_free(signature);
576 return 0;
578 truncated:
579 log_warn(LD_BUG,"tried to exceed string length.");
580 err:
581 tor_free(signature);
582 return -1;
585 /** Return VS_RECOMMENDED if <b>myversion</b> is contained in
586 * <b>versionlist</b>. Else, return VS_EMPTY if versionlist has no
587 * entries. Else, return VS_OLD if every member of
588 * <b>versionlist</b> is newer than <b>myversion</b>. Else, return
589 * VS_NEW_IN_SERIES if there is at least one member of <b>versionlist</b> in
590 * the same series (major.minor.micro) as <b>myversion</b>, but no such member
591 * is newer than <b>myversion.</b>. Else, return VS_NEW if every memeber of
592 * <b>versionlist</b> is older than <b>myversion</b>. Else, return
593 * VS_UNRECOMMENDED.
595 * (versionlist is a comma-separated list of version strings,
596 * optionally prefixed with "Tor". Versions that can't be parsed are
597 * ignored.)
599 version_status_t
600 tor_version_is_obsolete(const char *myversion, const char *versionlist)
602 tor_version_t mine, other;
603 int found_newer = 0, found_older = 0, found_newer_in_series = 0,
604 found_any_in_series = 0, r, same;
605 version_status_t ret = VS_UNRECOMMENDED;
606 smartlist_t *version_sl;
608 log_debug(LD_CONFIG,"Checking whether version '%s' is in '%s'",
609 myversion, versionlist);
611 if (tor_version_parse(myversion, &mine)) {
612 log_err(LD_BUG,"I couldn't parse my own version (%s)", myversion);
613 tor_assert(0);
615 version_sl = smartlist_create();
616 smartlist_split_string(version_sl, versionlist, ",", SPLIT_SKIP_SPACE, 0);
618 if (!strlen(versionlist)) { /* no authorities cared or agreed */
619 ret = VS_EMPTY;
620 goto done;
623 SMARTLIST_FOREACH(version_sl, const char *, cp, {
624 if (!strcmpstart(cp, "Tor "))
625 cp += 4;
627 if (tor_version_parse(cp, &other)) {
628 /* Couldn't parse other; it can't be a match. */
629 } else {
630 same = tor_version_same_series(&mine, &other);
631 if (same)
632 found_any_in_series = 1;
633 r = tor_version_compare(&mine, &other);
634 if (r==0) {
635 ret = VS_RECOMMENDED;
636 goto done;
637 } else if (r<0) {
638 found_newer = 1;
639 if (same)
640 found_newer_in_series = 1;
641 } else if (r>0) {
642 found_older = 1;
647 /* We didn't find the listed version. Is it new or old? */
648 if (found_any_in_series && !found_newer_in_series && found_newer) {
649 ret = VS_NEW_IN_SERIES;
650 } else if (found_newer && !found_older) {
651 ret = VS_OLD;
652 } else if (found_older && !found_newer) {
653 ret = VS_NEW;
654 } else {
655 ret = VS_UNRECOMMENDED;
658 done:
659 SMARTLIST_FOREACH(version_sl, char *, version, tor_free(version));
660 smartlist_free(version_sl);
661 return ret;
664 /** Read a signed directory from <b>str</b>. If it's well-formed, return 0.
665 * Otherwise, return -1. If we're a directory cache, cache it.
668 router_parse_directory(const char *str)
670 directory_token_t *tok;
671 char digest[DIGEST_LEN];
672 time_t published_on;
673 int r;
674 const char *end, *cp;
675 smartlist_t *tokens = NULL;
676 crypto_pk_env_t *declared_key = NULL;
677 memarea_t *area = memarea_new(8192);
679 /* XXXX This could be simplified a lot, but it will all go away
680 * once pre-0.1.1.8 is obsolete, and for now it's better not to
681 * touch it. */
683 if (router_get_dir_hash(str, digest)) {
684 log_warn(LD_DIR, "Unable to compute digest of directory");
685 goto err;
687 log_debug(LD_DIR,"Received directory hashes to %s",hex_str(digest,4));
689 /* Check signature first, before we try to tokenize. */
690 cp = str;
691 while (cp && (end = strstr(cp+1, "\ndirectory-signature")))
692 cp = end;
693 if (cp == str || !cp) {
694 log_warn(LD_DIR, "No signature found on directory."); goto err;
696 ++cp;
697 tokens = smartlist_create();
698 if (tokenize_string(area,cp,strchr(cp,'\0'),tokens,dir_token_table,0)) {
699 log_warn(LD_DIR, "Error tokenizing directory signature"); goto err;
701 if (smartlist_len(tokens) != 1) {
702 log_warn(LD_DIR, "Unexpected number of tokens in signature"); goto err;
704 tok=smartlist_get(tokens,0);
705 if (tok->tp != K_DIRECTORY_SIGNATURE) {
706 log_warn(LD_DIR,"Expected a single directory signature"); goto err;
708 declared_key = find_dir_signing_key(str, str+strlen(str));
709 note_crypto_pk_op(VERIFY_DIR);
710 if (check_signature_token(digest, tok, declared_key, 1, "directory")<0)
711 goto err;
713 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
714 smartlist_clear(tokens);
715 memarea_clear(area);
717 /* Now try to parse the first part of the directory. */
718 if ((end = strstr(str,"\nrouter "))) {
719 ++end;
720 } else if ((end = strstr(str, "\ndirectory-signature"))) {
721 ++end;
722 } else {
723 end = str + strlen(str);
726 if (tokenize_string(area,str,end,tokens,dir_token_table,0)) {
727 log_warn(LD_DIR, "Error tokenizing directory"); goto err;
730 tok = find_first_by_keyword(tokens, K_PUBLISHED);
731 tor_assert(tok);
732 tor_assert(tok->n_args == 1);
734 if (parse_iso_time(tok->args[0], &published_on) < 0) {
735 goto err;
738 /* Now that we know the signature is okay, and we have a
739 * publication time, cache the directory. */
740 if (directory_caches_v1_dir_info(get_options()) &&
741 !authdir_mode_v1(get_options()))
742 dirserv_set_cached_directory(str, published_on, 0);
744 r = 0;
745 goto done;
746 err:
747 r = -1;
748 done:
749 if (declared_key) crypto_free_pk_env(declared_key);
750 if (tokens) {
751 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
752 smartlist_free(tokens);
754 if (area) {
755 DUMP_AREA(area, "v1 directory");
756 memarea_drop_all(area);
758 return r;
761 /** Read a signed router status statement from <b>str</b>. If it's
762 * well-formed, return 0. Otherwise, return -1. If we're a directory cache,
763 * cache it.*/
765 router_parse_runningrouters(const char *str)
767 char digest[DIGEST_LEN];
768 directory_token_t *tok;
769 time_t published_on;
770 int r = -1;
771 crypto_pk_env_t *declared_key = NULL;
772 smartlist_t *tokens = NULL;
773 const char *eos = str + strlen(str);
774 memarea_t *area = NULL;
776 if (router_get_runningrouters_hash(str, digest)) {
777 log_warn(LD_DIR, "Unable to compute digest of running-routers");
778 goto err;
780 area = memarea_new(8192);
781 tokens = smartlist_create();
782 if (tokenize_string(area,str,eos,tokens,dir_token_table,0)) {
783 log_warn(LD_DIR, "Error tokenizing running-routers"); goto err;
785 tok = smartlist_get(tokens,0);
786 if (tok->tp != K_NETWORK_STATUS) {
787 log_warn(LD_DIR, "Network-status starts with wrong token");
788 goto err;
791 tok = find_first_by_keyword(tokens, K_PUBLISHED);
792 tor_assert(tok);
793 tor_assert(tok->n_args == 1);
794 if (parse_iso_time(tok->args[0], &published_on) < 0) {
795 goto err;
797 if (!(tok = find_first_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) {
798 log_warn(LD_DIR, "Missing signature on running-routers");
799 goto err;
801 declared_key = find_dir_signing_key(str, eos);
802 note_crypto_pk_op(VERIFY_DIR);
803 if (check_signature_token(digest, tok, declared_key, 1, "running-routers")
804 < 0)
805 goto err;
807 /* Now that we know the signature is okay, and we have a
808 * publication time, cache the list. */
809 if (get_options()->DirPort && !authdir_mode_v1(get_options()))
810 dirserv_set_cached_directory(str, published_on, 1);
812 r = 0;
813 err:
814 if (declared_key) crypto_free_pk_env(declared_key);
815 if (tokens) {
816 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
817 smartlist_free(tokens);
819 if (area) {
820 DUMP_AREA(area, "v1 running-routers");
821 memarea_drop_all(area);
823 return r;
826 /** Given a directory or running-routers string in <b>str</b>, try to
827 * find the its dir-signing-key token (if any). If this token is
828 * present, extract and return the key. Return NULL on failure. */
829 static crypto_pk_env_t *
830 find_dir_signing_key(const char *str, const char *eos)
832 const char *cp;
833 directory_token_t *tok;
834 crypto_pk_env_t *key = NULL;
835 memarea_t *area = NULL;
836 tor_assert(str);
837 tor_assert(eos);
839 /* Is there a dir-signing-key in the directory? */
840 cp = tor_memstr(str, eos-str, "\nopt dir-signing-key");
841 if (!cp)
842 cp = tor_memstr(str, eos-str, "\ndir-signing-key");
843 if (!cp)
844 return NULL;
845 ++cp; /* Now cp points to the start of the token. */
847 area = memarea_new(1024);
848 tok = get_next_token(area, &cp, eos, dir_token_table);
849 if (!tok) {
850 log_warn(LD_DIR, "Unparseable dir-signing-key token");
851 goto done;
853 if (tok->tp != K_DIR_SIGNING_KEY) {
854 log_warn(LD_DIR, "Dir-signing-key token did not parse as expected");
855 goto done;
858 if (tok->key) {
859 key = tok->key;
860 tok->key = NULL; /* steal reference. */
861 } else {
862 log_warn(LD_DIR, "Dir-signing-key token contained no key");
865 done:
866 if (tok) token_free(tok);
867 if (area) {
868 DUMP_AREA(area, "dir-signing-key token");
869 memarea_drop_all(area);
871 return key;
874 /** Return true iff <b>key</b> is allowed to sign directories.
876 static int
877 dir_signing_key_is_trusted(crypto_pk_env_t *key)
879 char digest[DIGEST_LEN];
880 if (!key) return 0;
881 if (crypto_pk_get_digest(key, digest) < 0) {
882 log_warn(LD_DIR, "Error computing dir-signing-key digest");
883 return 0;
885 if (!router_digest_is_trusted_dir(digest)) {
886 log_warn(LD_DIR, "Listed dir-signing-key is not trusted");
887 return 0;
889 return 1;
892 /** Check whether the object body of the token in <b>tok</b> has a good
893 * signature for <b>digest</b> using key <b>pkey</b>. If
894 * <b>check_authority</b> is set, make sure that <b>pkey</b> is the key of a
895 * directory authority. Use <b>doctype</b> as the type of the document when
896 * generating log messages. Return 0 on success, negative on failure.
898 static int
899 check_signature_token(const char *digest,
900 directory_token_t *tok,
901 crypto_pk_env_t *pkey,
902 int check_authority,
903 const char *doctype)
905 char *signed_digest;
907 tor_assert(pkey);
908 tor_assert(tok);
909 tor_assert(digest);
910 tor_assert(doctype);
912 if (check_authority && !dir_signing_key_is_trusted(pkey)) {
913 log_warn(LD_DIR, "Key on %s did not come from an authority; rejecting",
914 doctype);
915 return -1;
918 if (strcmp(tok->object_type, "SIGNATURE")) {
919 log_warn(LD_DIR, "Bad object type on %s signature", doctype);
920 return -1;
923 signed_digest = tor_malloc(tok->object_size);
924 if (crypto_pk_public_checksig(pkey, signed_digest, tok->object_body,
925 tok->object_size)
926 != DIGEST_LEN) {
927 log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype);
928 tor_free(signed_digest);
929 return -1;
931 // log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
932 // hex_str(signed_digest,4));
933 if (memcmp(digest, signed_digest, DIGEST_LEN)) {
934 log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
935 tor_free(signed_digest);
936 return -1;
938 tor_free(signed_digest);
939 return 0;
942 /** Helper: move *<b>s_ptr</b> ahead to the next router, the next extra-info,
943 * or to the first of the annotations proceeding the next router or
944 * extra-info---whichever comes first. Set <b>is_extrainfo_out</b> to true if
945 * we found an extrainfo, or false if found a router. Do not scan beyond
946 * <b>eos</b>. Return -1 if we found nothing; 0 if we found something. */
947 static int
948 find_start_of_next_router_or_extrainfo(const char **s_ptr,
949 const char *eos,
950 int *is_extrainfo_out)
952 const char *annotations = NULL;
953 const char *s = *s_ptr;
955 s = eat_whitespace_eos(s, eos);
957 while (s < eos-32) { /* 32 gives enough room for a the first keyword. */
958 /* We're at the start of a line. */
959 tor_assert(*s != '\n');
961 if (*s == '@' && !annotations) {
962 annotations = s;
963 } else if (*s == 'r' && !strcmpstart(s, "router ")) {
964 *s_ptr = annotations ? annotations : s;
965 *is_extrainfo_out = 0;
966 return 0;
967 } else if (*s == 'e' && !strcmpstart(s, "extra-info ")) {
968 *s_ptr = annotations ? annotations : s;
969 *is_extrainfo_out = 1;
970 return 0;
973 if (!(s = memchr(s+1, '\n', eos-(s+1))))
974 break;
975 s = eat_whitespace_eos(s, eos);
977 return -1;
980 /** Given a string *<b>s</b> containing a concatenated sequence of router
981 * descriptors (or extra-info documents if <b>is_extrainfo</b> is set), parses
982 * them and stores the result in <b>dest</b>. All routers are marked running
983 * and valid. Advances *s to a point immediately following the last router
984 * entry. Ignore any trailing router entries that are not complete.
986 * If <b>saved_location</b> isn't SAVED_IN_CACHE, make a local copy of each
987 * descriptor in the signed_descriptor_body field of each routerinfo_t. If it
988 * isn't SAVED_NOWHERE, remember the offset of each descriptor.
990 * Returns 0 on success and -1 on failure.
993 router_parse_list_from_string(const char **s, const char *eos,
994 smartlist_t *dest,
995 saved_location_t saved_location,
996 int want_extrainfo,
997 int allow_annotations,
998 const char *prepend_annotations)
1000 routerinfo_t *router;
1001 extrainfo_t *extrainfo;
1002 signed_descriptor_t *signed_desc;
1003 void *elt;
1004 const char *end, *start;
1005 int have_extrainfo;
1007 tor_assert(s);
1008 tor_assert(*s);
1009 tor_assert(dest);
1011 start = *s;
1012 if (!eos)
1013 eos = *s + strlen(*s);
1015 tor_assert(eos >= *s);
1017 while (1) {
1018 if (find_start_of_next_router_or_extrainfo(s, eos, &have_extrainfo) < 0)
1019 break;
1021 end = tor_memstr(*s, eos-*s, "\nrouter-signature");
1022 if (end)
1023 end = tor_memstr(end, eos-end, "\n-----END SIGNATURE-----\n");
1024 if (end)
1025 end += strlen("\n-----END SIGNATURE-----\n");
1027 if (!end)
1028 break;
1030 elt = NULL;
1032 if (have_extrainfo && want_extrainfo) {
1033 routerlist_t *rl = router_get_routerlist();
1034 extrainfo = extrainfo_parse_entry_from_string(*s, end,
1035 saved_location != SAVED_IN_CACHE,
1036 rl->identity_map);
1037 if (extrainfo) {
1038 signed_desc = &extrainfo->cache_info;
1039 elt = extrainfo;
1041 } else if (!have_extrainfo && !want_extrainfo) {
1042 router = router_parse_entry_from_string(*s, end,
1043 saved_location != SAVED_IN_CACHE,
1044 allow_annotations,
1045 prepend_annotations);
1046 if (router) {
1047 log_debug(LD_DIR, "Read router '%s', purpose '%s'",
1048 router->nickname, router_purpose_to_string(router->purpose));
1049 signed_desc = &router->cache_info;
1050 elt = router;
1053 if (!elt) {
1054 *s = end;
1055 continue;
1057 if (saved_location != SAVED_NOWHERE) {
1058 signed_desc->saved_location = saved_location;
1059 signed_desc->saved_offset = *s - start;
1061 *s = end;
1062 smartlist_add(dest, elt);
1065 return 0;
1068 /* For debugging: define to count every descriptor digest we've seen so we
1069 * know if we need to try harder to avoid duplicate verifies. */
1070 #undef COUNT_DISTINCT_DIGESTS
1072 #ifdef COUNT_DISTINCT_DIGESTS
1073 static digestmap_t *verified_digests = NULL;
1074 #endif
1076 /** Log the total count of the number of distinct router digests we've ever
1077 * verified. When compared to the number of times we've verified routerdesc
1078 * signatures <i>in toto</i>, this will tell us if we're doing too much
1079 * multiple-verification. */
1080 void
1081 dump_distinct_digest_count(int severity)
1083 #ifdef COUNT_DISTINCT_DIGESTS
1084 if (!verified_digests)
1085 verified_digests = digestmap_new();
1086 log(severity, LD_GENERAL, "%d *distinct* router digests verified",
1087 digestmap_size(verified_digests));
1088 #else
1089 (void)severity; /* suppress "unused parameter" warning */
1090 #endif
1093 /** Helper function: reads a single router entry from *<b>s</b> ...
1094 * *<b>end</b>. Mallocs a new router and returns it if all goes well, else
1095 * returns NULL. If <b>cache_copy</b> is true, duplicate the contents of
1096 * s through end into the signed_descriptor_body of the resulting
1097 * routerinfo_t.
1099 * If <b>allow_annotations</b>, it's okay to encounter annotations in <b>s</b>
1100 * before the router; if it's false, reject the router if it's annotated. If
1101 * <b>prepend_annotations</b> is set, it should contain some annotations:
1102 * append them to the front of the router before parsing it, and keep them
1103 * around when caching the router.
1105 * Only one of allow_annotations and prepend_annotations may be set.
1107 routerinfo_t *
1108 router_parse_entry_from_string(const char *s, const char *end,
1109 int cache_copy, int allow_annotations,
1110 const char *prepend_annotations)
1112 routerinfo_t *router = NULL;
1113 char digest[128];
1114 smartlist_t *tokens = NULL, *exit_policy_tokens = NULL;
1115 directory_token_t *tok;
1116 struct in_addr in;
1117 const char *start_of_annotations, *cp;
1118 size_t prepend_len = prepend_annotations ? strlen(prepend_annotations) : 0;
1119 int ok = 1;
1120 memarea_t *area = NULL;
1122 tor_assert(!allow_annotations || !prepend_annotations);
1124 if (!end) {
1125 end = s + strlen(s);
1128 /* point 'end' to a point immediately after the final newline. */
1129 while (end > s+2 && *(end-1) == '\n' && *(end-2) == '\n')
1130 --end;
1132 area = memarea_new(4096);
1133 tokens = smartlist_create();
1134 if (prepend_annotations) {
1135 if (tokenize_string(area,prepend_annotations,NULL,tokens,
1136 routerdesc_token_table,TS_NOCHECK)) {
1137 log_warn(LD_DIR, "Error tokenizing router descriptor (annotations).");
1138 goto err;
1142 start_of_annotations = s;
1143 cp = tor_memstr(s, end-s, "\nrouter ");
1144 if (!cp) {
1145 if (end-s < 7 || strcmpstart(s, "router ")) {
1146 log_warn(LD_DIR, "No router keyword found.");
1147 goto err;
1149 } else {
1150 s = cp+1;
1153 if (allow_annotations && start_of_annotations != s) {
1154 if (tokenize_string(area,start_of_annotations,s,tokens,
1155 routerdesc_token_table,TS_NOCHECK)) {
1156 log_warn(LD_DIR, "Error tokenizing router descriptor (annotations).");
1157 goto err;
1161 if (router_get_router_hash(s, digest) < 0) {
1162 log_warn(LD_DIR, "Couldn't compute router hash.");
1163 goto err;
1166 int flags = 0;
1167 if (allow_annotations)
1168 flags |= TS_ANNOTATIONS_OK;
1169 if (prepend_annotations)
1170 flags |= TS_ANNOTATIONS_OK|TS_NO_NEW_ANNOTATIONS;
1172 if (tokenize_string(area,s,end,tokens,routerdesc_token_table, flags)) {
1173 log_warn(LD_DIR, "Error tokenizing router descriptor.");
1174 goto err;
1178 if (smartlist_len(tokens) < 2) {
1179 log_warn(LD_DIR, "Impossibly short router descriptor.");
1180 goto err;
1183 tok = find_first_by_keyword(tokens, K_ROUTER);
1184 tor_assert(tok->n_args >= 5);
1186 router = tor_malloc_zero(sizeof(routerinfo_t));
1187 router->cache_info.routerlist_index = -1;
1188 router->cache_info.annotations_len = s-start_of_annotations + prepend_len;
1189 router->cache_info.signed_descriptor_len = end-s;
1190 if (cache_copy) {
1191 size_t len = router->cache_info.signed_descriptor_len +
1192 router->cache_info.annotations_len;
1193 char *cp =
1194 router->cache_info.signed_descriptor_body = tor_malloc(len+1);
1195 if (prepend_annotations) {
1196 memcpy(cp, prepend_annotations, prepend_len);
1197 cp += prepend_len;
1199 /* This assertion will always succeed.
1200 * len == signed_desc_len + annotations_len
1201 * == end-s + s-start_of_annotations + prepend_len
1202 * == end-start_of_annotations + prepend_len
1203 * We already wrote prepend_len bytes into the buffer; now we're
1204 * writing end-start_of_annotations -NM. */
1205 tor_assert(cp+(end-start_of_annotations) ==
1206 router->cache_info.signed_descriptor_body+len);
1207 memcpy(cp, start_of_annotations, end-start_of_annotations);
1208 router->cache_info.signed_descriptor_body[len] = '\0';
1209 tor_assert(strlen(router->cache_info.signed_descriptor_body) == len);
1211 memcpy(router->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
1213 router->nickname = tor_strdup(tok->args[0]);
1214 if (!is_legal_nickname(router->nickname)) {
1215 log_warn(LD_DIR,"Router nickname is invalid");
1216 goto err;
1218 router->address = tor_strdup(tok->args[1]);
1219 if (!tor_inet_aton(router->address, &in)) {
1220 log_warn(LD_DIR,"Router address is not an IP address.");
1221 goto err;
1223 router->addr = ntohl(in.s_addr);
1225 router->or_port =
1226 (uint16_t) tor_parse_long(tok->args[2],10,0,65535,&ok,NULL);
1227 if (!ok) {
1228 log_warn(LD_DIR,"Invalid OR port %s", escaped(tok->args[2]));
1229 goto err;
1231 router->dir_port =
1232 (uint16_t) tor_parse_long(tok->args[4],10,0,65535,&ok,NULL);
1233 if (!ok) {
1234 log_warn(LD_DIR,"Invalid dir port %s", escaped(tok->args[4]));
1235 goto err;
1238 tok = find_first_by_keyword(tokens, K_BANDWIDTH);
1239 tor_assert(tok && tok->n_args >= 3);
1240 router->bandwidthrate = (int)
1241 tor_parse_long(tok->args[0],10,1,INT_MAX,&ok,NULL);
1243 if (!ok) {
1244 log_warn(LD_DIR, "bandwidthrate %s unreadable or 0. Failing.",
1245 escaped(tok->args[0]));
1246 goto err;
1248 router->bandwidthburst =
1249 (int) tor_parse_long(tok->args[1],10,0,INT_MAX,&ok,NULL);
1250 if (!ok) {
1251 log_warn(LD_DIR, "Invalid bandwidthburst %s", escaped(tok->args[1]));
1252 goto err;
1254 router->bandwidthcapacity = (int)
1255 tor_parse_long(tok->args[2],10,0,INT_MAX,&ok,NULL);
1256 if (!ok) {
1257 log_warn(LD_DIR, "Invalid bandwidthcapacity %s", escaped(tok->args[1]));
1258 goto err;
1261 if ((tok = find_first_by_keyword(tokens, A_PURPOSE))) {
1262 tor_assert(tok->n_args != 0);
1263 router->purpose = router_purpose_from_string(tok->args[0]);
1264 } else {
1265 router->purpose = ROUTER_PURPOSE_GENERAL;
1267 router->cache_info.send_unencrypted =
1268 (router->purpose == ROUTER_PURPOSE_GENERAL) ? 1 : 0;
1270 if ((tok = find_first_by_keyword(tokens, K_UPTIME))) {
1271 tor_assert(tok->n_args >= 1);
1272 router->uptime = tor_parse_long(tok->args[0],10,0,LONG_MAX,&ok,NULL);
1273 if (!ok) {
1274 log_warn(LD_DIR, "Invalid uptime %s", escaped(tok->args[0]));
1275 goto err;
1279 if ((tok = find_first_by_keyword(tokens, K_HIBERNATING))) {
1280 tor_assert(tok->n_args >= 1);
1281 router->is_hibernating
1282 = (tor_parse_long(tok->args[0],10,0,LONG_MAX,NULL,NULL) != 0);
1285 tok = find_first_by_keyword(tokens, K_PUBLISHED);
1286 tor_assert(tok);
1287 tor_assert(tok->n_args == 1);
1288 if (parse_iso_time(tok->args[0], &router->cache_info.published_on) < 0)
1289 goto err;
1291 tok = find_first_by_keyword(tokens, K_ONION_KEY);
1292 tor_assert(tok);
1293 router->onion_pkey = tok->key;
1294 tok->key = NULL; /* Prevent free */
1296 tok = find_first_by_keyword(tokens, K_SIGNING_KEY);
1297 tor_assert(tok);
1298 router->identity_pkey = tok->key;
1299 tok->key = NULL; /* Prevent free */
1300 if (crypto_pk_get_digest(router->identity_pkey,
1301 router->cache_info.identity_digest)) {
1302 log_warn(LD_DIR, "Couldn't calculate key digest"); goto err;
1305 if ((tok = find_first_by_keyword(tokens, K_FINGERPRINT))) {
1306 /* If there's a fingerprint line, it must match the identity digest. */
1307 char d[DIGEST_LEN];
1308 tor_assert(tok->n_args == 1);
1309 tor_strstrip(tok->args[0], " ");
1310 if (base16_decode(d, DIGEST_LEN, tok->args[0], strlen(tok->args[0]))) {
1311 log_warn(LD_DIR, "Couldn't decode router fingerprint %s",
1312 escaped(tok->args[0]));
1313 goto err;
1315 if (memcmp(d,router->cache_info.identity_digest, DIGEST_LEN)!=0) {
1316 log_warn(LD_DIR, "Fingerprint '%s' does not match identity digest.",
1317 tok->args[0]);
1318 goto err;
1322 if ((tok = find_first_by_keyword(tokens, K_PLATFORM))) {
1323 router->platform = tor_strdup(tok->args[0]);
1326 if ((tok = find_first_by_keyword(tokens, K_CONTACT))) {
1327 router->contact_info = tor_strdup(tok->args[0]);
1330 if ((tok = find_first_by_keyword(tokens, K_EVENTDNS))) {
1331 router->has_old_dnsworkers = tok->n_args && !strcmp(tok->args[0], "0");
1332 } else if (router->platform) {
1333 if (! tor_version_as_new_as(router->platform, "0.1.2.2-alpha"))
1334 router->has_old_dnsworkers = 1;
1337 exit_policy_tokens = find_all_exitpolicy(tokens);
1338 if (!smartlist_len(exit_policy_tokens)) {
1339 log_warn(LD_DIR, "No exit policy tokens in descriptor.");
1340 goto err;
1342 SMARTLIST_FOREACH(exit_policy_tokens, directory_token_t *, t,
1343 if (router_add_exit_policy(router,t)<0) {
1344 log_warn(LD_DIR,"Error in exit policy");
1345 goto err;
1347 policy_expand_private(&router->exit_policy);
1349 if ((tok = find_first_by_keyword(tokens, K_FAMILY)) && tok->n_args) {
1350 int i;
1351 router->declared_family = smartlist_create();
1352 for (i=0;i<tok->n_args;++i) {
1353 if (!is_legal_nickname_or_hexdigest(tok->args[i])) {
1354 log_warn(LD_DIR, "Illegal nickname %s in family line",
1355 escaped(tok->args[i]));
1356 goto err;
1358 smartlist_add(router->declared_family, tor_strdup(tok->args[i]));
1362 if ((tok = find_first_by_keyword(tokens, K_CACHES_EXTRA_INFO)))
1363 router->caches_extra_info = 1;
1365 if ((tok = find_first_by_keyword(tokens, K_EXTRA_INFO_DIGEST))) {
1366 tor_assert(tok->n_args >= 1);
1367 if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {
1368 base16_decode(router->cache_info.extra_info_digest,
1369 DIGEST_LEN, tok->args[0], HEX_DIGEST_LEN);
1370 } else {
1371 log_warn(LD_DIR, "Invalid extra info digest %s", escaped(tok->args[0]));
1375 if ((tok = find_first_by_keyword(tokens, K_HIDDEN_SERVICE_DIR))) {
1376 router->wants_to_be_hs_dir = 1;
1379 tok = find_first_by_keyword(tokens, K_ROUTER_SIGNATURE);
1380 tor_assert(tok);
1381 note_crypto_pk_op(VERIFY_RTR);
1382 #ifdef COUNT_DISTINCT_DIGESTS
1383 if (!verified_digests)
1384 verified_digests = digestmap_new();
1385 digestmap_set(verified_digests, signed_digest, (void*)(uintptr_t)1);
1386 #endif
1387 if (check_signature_token(digest, tok, router->identity_pkey, 0,
1388 "router descriptor") < 0)
1389 goto err;
1391 if (!router->or_port) {
1392 log_warn(LD_DIR,"or_port unreadable or 0. Failing.");
1393 goto err;
1396 if (!router->platform) {
1397 router->platform = tor_strdup("<unknown>");
1400 goto done;
1402 err:
1403 routerinfo_free(router);
1404 router = NULL;
1405 done:
1406 if (tokens) {
1407 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
1408 smartlist_free(tokens);
1410 if (exit_policy_tokens) {
1411 smartlist_free(exit_policy_tokens);
1413 if (area) {
1414 DUMP_AREA(area, "routerinfo");
1415 memarea_drop_all(area);
1417 return router;
1420 /** Parse a single extrainfo entry from the string <b>s</b>, ending at
1421 * <b>end</b>. (If <b>end</b> is NULL, parse up to the end of <b>s</b>.) If
1422 * <b>cache_copy</b> is true, make a copy of the extra-info document in the
1423 * cache_info fields of the result. If <b>routermap</b> is provided, use it
1424 * as a map from router identity to routerinfo_t when looking up signing keys.
1426 extrainfo_t *
1427 extrainfo_parse_entry_from_string(const char *s, const char *end,
1428 int cache_copy, struct digest_ri_map_t *routermap)
1430 extrainfo_t *extrainfo = NULL;
1431 char digest[128];
1432 smartlist_t *tokens = NULL;
1433 directory_token_t *tok;
1434 crypto_pk_env_t *key = NULL;
1435 routerinfo_t *router = NULL;
1436 memarea_t *area = NULL;
1438 if (!end) {
1439 end = s + strlen(s);
1442 /* point 'end' to a point immediately after the final newline. */
1443 while (end > s+2 && *(end-1) == '\n' && *(end-2) == '\n')
1444 --end;
1446 if (router_get_extrainfo_hash(s, digest) < 0) {
1447 log_warn(LD_DIR, "Couldn't compute router hash.");
1448 return NULL;
1450 tokens = smartlist_create();
1451 area = memarea_new(8192);
1452 if (tokenize_string(area,s,end,tokens,extrainfo_token_table,0)) {
1453 log_warn(LD_DIR, "Error tokenizing extra-info document.");
1454 goto err;
1457 if (smartlist_len(tokens) < 2) {
1458 log_warn(LD_DIR, "Impossibly short extra-info document.");
1459 goto err;
1462 tok = smartlist_get(tokens,0);
1463 if (tok->tp != K_EXTRA_INFO) {
1464 log_warn(LD_DIR,"Entry does not start with \"extra-info\"");
1465 goto err;
1468 extrainfo = tor_malloc_zero(sizeof(extrainfo_t));
1469 extrainfo->cache_info.is_extrainfo = 1;
1470 if (cache_copy)
1471 extrainfo->cache_info.signed_descriptor_body = tor_strndup(s, end-s);
1472 extrainfo->cache_info.signed_descriptor_len = end-s;
1473 memcpy(extrainfo->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
1475 tor_assert(tok->n_args >= 2);
1476 if (!is_legal_nickname(tok->args[0])) {
1477 log_warn(LD_DIR,"Bad nickname %s on \"extra-info\"",escaped(tok->args[0]));
1478 goto err;
1480 strlcpy(extrainfo->nickname, tok->args[0], sizeof(extrainfo->nickname));
1481 if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
1482 base16_decode(extrainfo->cache_info.identity_digest, DIGEST_LEN,
1483 tok->args[1], HEX_DIGEST_LEN)) {
1484 log_warn(LD_DIR,"Invalid fingerprint %s on \"extra-info\"",
1485 escaped(tok->args[1]));
1486 goto err;
1489 tok = find_first_by_keyword(tokens, K_PUBLISHED);
1490 tor_assert(tok);
1491 if (parse_iso_time(tok->args[0], &extrainfo->cache_info.published_on)) {
1492 log_warn(LD_DIR,"Invalid published time %s on \"extra-info\"",
1493 escaped(tok->args[0]));
1494 goto err;
1497 if (routermap &&
1498 (router = digestmap_get((digestmap_t*)routermap,
1499 extrainfo->cache_info.identity_digest))) {
1500 key = router->identity_pkey;
1503 tok = find_first_by_keyword(tokens, K_ROUTER_SIGNATURE);
1504 tor_assert(tok);
1505 if (strcmp(tok->object_type, "SIGNATURE") ||
1506 tok->object_size < 128 || tok->object_size > 512) {
1507 log_warn(LD_DIR, "Bad object type or length on extra-info signature");
1508 goto err;
1511 if (key) {
1512 note_crypto_pk_op(VERIFY_RTR);
1513 if (check_signature_token(digest, tok, key, 0, "extra-info") < 0)
1514 goto err;
1516 if (router)
1517 extrainfo->cache_info.send_unencrypted =
1518 router->cache_info.send_unencrypted;
1519 } else {
1520 extrainfo->pending_sig = tor_memdup(tok->object_body,
1521 tok->object_size);
1522 extrainfo->pending_sig_len = tok->object_size;
1525 goto done;
1526 err:
1527 if (extrainfo)
1528 extrainfo_free(extrainfo);
1529 extrainfo = NULL;
1530 done:
1531 if (tokens) {
1532 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
1533 smartlist_free(tokens);
1535 if (area) {
1536 DUMP_AREA(area, "extrainfo");
1537 memarea_drop_all(area);
1539 return extrainfo;
1542 /** Parse a key certificate from <b>s</b>; point <b>end-of-string</b> to
1543 * the first character after the certificate. */
1544 authority_cert_t *
1545 authority_cert_parse_from_string(const char *s, const char **end_of_string)
1547 authority_cert_t *cert = NULL, *old_cert;
1548 smartlist_t *tokens = NULL;
1549 char digest[DIGEST_LEN];
1550 directory_token_t *tok;
1551 char fp_declared[DIGEST_LEN];
1552 char *eos;
1553 size_t len;
1554 int found;
1555 memarea_t *area = NULL;
1557 s = eat_whitespace(s);
1558 eos = strstr(s, "\n-----END SIGNATURE-----\n");
1559 if (! eos) {
1560 log_warn(LD_DIR, "No end-of-signature found on key certificate");
1561 return NULL;
1563 eos = strchr(eos+2, '\n');
1564 tor_assert(eos);
1565 ++eos;
1566 len = eos - s;
1568 tokens = smartlist_create();
1569 area = memarea_new(8192);
1570 if (tokenize_string(area,s, eos, tokens, dir_key_certificate_table, 0) < 0) {
1571 log_warn(LD_DIR, "Error tokenizing key certificate");
1572 goto err;
1574 if (router_get_hash_impl(s, digest, "dir-key-certificate-version",
1575 "\ndir-key-certification", '\n') < 0)
1576 goto err;
1577 tok = smartlist_get(tokens, 0);
1578 if (tok->tp != K_DIR_KEY_CERTIFICATE_VERSION || strcmp(tok->args[0], "3")) {
1579 log_warn(LD_DIR,
1580 "Key certificate does not begin with a recognized version (3).");
1581 goto err;
1584 cert = tor_malloc_zero(sizeof(authority_cert_t));
1585 memcpy(cert->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
1587 tok = find_first_by_keyword(tokens, K_DIR_SIGNING_KEY);
1588 tor_assert(tok && tok->key);
1589 cert->signing_key = tok->key;
1590 tok->key = NULL;
1591 if (crypto_pk_get_digest(cert->signing_key, cert->signing_key_digest))
1592 goto err;
1594 tok = find_first_by_keyword(tokens, K_DIR_IDENTITY_KEY);
1595 tor_assert(tok && tok->key);
1596 cert->identity_key = tok->key;
1597 tok->key = NULL;
1599 tok = find_first_by_keyword(tokens, K_FINGERPRINT);
1600 tor_assert(tok && tok->n_args);
1601 if (base16_decode(fp_declared, DIGEST_LEN, tok->args[0],
1602 strlen(tok->args[0]))) {
1603 log_warn(LD_DIR, "Couldn't decode key certificate fingerprint %s",
1604 escaped(tok->args[0]));
1605 goto err;
1608 if (crypto_pk_get_digest(cert->identity_key,
1609 cert->cache_info.identity_digest))
1610 goto err;
1612 if (memcmp(cert->cache_info.identity_digest, fp_declared, DIGEST_LEN)) {
1613 log_warn(LD_DIR, "Digest of certificate key didn't match declared "
1614 "fingerprint");
1615 goto err;
1618 tok = find_first_by_keyword(tokens, K_DIR_ADDRESS);
1619 if (tok) {
1620 tor_assert(tok->n_args != 0);
1621 if (parse_addr_port(LOG_WARN, tok->args[0], NULL, &cert->addr,
1622 &cert->dir_port)<0) {
1623 log_warn(LD_DIR, "Couldn't parse dir-address in certificate");
1624 goto err;
1628 tok = find_first_by_keyword(tokens, K_DIR_KEY_PUBLISHED);
1629 tor_assert(tok);
1630 if (parse_iso_time(tok->args[0], &cert->cache_info.published_on) < 0) {
1631 goto err;
1633 tok = find_first_by_keyword(tokens, K_DIR_KEY_EXPIRES);
1634 tor_assert(tok);
1635 if (parse_iso_time(tok->args[0], &cert->expires) < 0) {
1636 goto err;
1639 tok = smartlist_get(tokens, smartlist_len(tokens)-1);
1640 if (tok->tp != K_DIR_KEY_CERTIFICATION) {
1641 log_warn(LD_DIR, "Certificate didn't end with dir-key-certification.");
1642 goto err;
1645 /* If we already have this cert, don't bother checking the signature. */
1646 old_cert = authority_cert_get_by_digests(
1647 cert->cache_info.identity_digest,
1648 cert->signing_key_digest);
1649 found = 0;
1650 if (old_cert) {
1651 /* XXXX We could just compare signed_descriptor_digest, but that wouldn't
1652 * buy us much. */
1653 if (old_cert->cache_info.signed_descriptor_len == len &&
1654 old_cert->cache_info.signed_descriptor_body &&
1655 !memcmp(s, old_cert->cache_info.signed_descriptor_body, len)) {
1656 log_debug(LD_DIR, "We already checked the signature on this "
1657 "certificate; no need to do so again.");
1658 found = 1;
1661 if (!found) {
1662 if (check_signature_token(digest, tok, cert->identity_key, 0,
1663 "key certificate")) {
1664 goto err;
1668 cert->cache_info.signed_descriptor_len = len;
1669 cert->cache_info.signed_descriptor_body = tor_malloc(len+1);
1670 memcpy(cert->cache_info.signed_descriptor_body, s, len);
1671 cert->cache_info.signed_descriptor_body[len] = 0;
1672 cert->cache_info.saved_location = SAVED_NOWHERE;
1674 if (end_of_string) {
1675 *end_of_string = eat_whitespace(eos);
1677 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
1678 smartlist_free(tokens);
1679 if (area) {
1680 DUMP_AREA(area, "authority cert");
1681 memarea_drop_all(area);
1683 return cert;
1684 err:
1685 authority_cert_free(cert);
1686 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
1687 smartlist_free(tokens);
1688 if (area) {
1689 DUMP_AREA(area, "authority cert");
1690 memarea_drop_all(area);
1692 return NULL;
1695 /** Helper: given a string <b>s</b>, return the start of the next router-status
1696 * object (starting with "r " at the start of a line). If none is found,
1697 * return the start of the next directory signature. If none is found, return
1698 * the end of the string. */
1699 static INLINE const char *
1700 find_start_of_next_routerstatus(const char *s)
1702 const char *eos = strstr(s, "\nr ");
1703 if (eos) {
1704 const char *eos2 = tor_memstr(s, eos-s, "\ndirectory-signature");
1705 if (eos2 && eos2 < eos)
1706 return eos2;
1707 else
1708 return eos+1;
1709 } else {
1710 if ((eos = strstr(s, "\ndirectory-signature")))
1711 return eos+1;
1712 return s + strlen(s);
1716 /** Given a string at *<b>s</b>, containing a routerstatus object, and an
1717 * empty smartlist at <b>tokens</b>, parse and return the first router status
1718 * object in the string, and advance *<b>s</b> to just after the end of the
1719 * router status. Return NULL and advance *<b>s</b> on error.
1721 * If <b>vote</b> and <b>vote_rs</b> are provided, don't allocate a fresh
1722 * routerstatus but use <b>vote_rs</b> instead.
1724 * If <b>consensus_method</b> is nonzero, this routerstatus is part of a
1725 * consensus, and we should parse it according to the method used to
1726 * make that consensus.
1728 static routerstatus_t *
1729 routerstatus_parse_entry_from_string(memarea_t *area,
1730 const char **s, smartlist_t *tokens,
1731 networkstatus_t *vote,
1732 vote_routerstatus_t *vote_rs,
1733 int consensus_method)
1735 const char *eos;
1736 routerstatus_t *rs = NULL;
1737 directory_token_t *tok;
1738 char timebuf[ISO_TIME_LEN+1];
1739 struct in_addr in;
1740 tor_assert(tokens);
1741 tor_assert(bool_eq(vote, vote_rs));
1743 eos = find_start_of_next_routerstatus(*s);
1745 if (tokenize_string(area,*s, eos, tokens, rtrstatus_token_table,0)) {
1746 log_warn(LD_DIR, "Error tokenizing router status");
1747 goto err;
1749 if (smartlist_len(tokens) < 1) {
1750 log_warn(LD_DIR, "Impossibly short router status");
1751 goto err;
1753 tok = find_first_by_keyword(tokens, K_R);
1754 tor_assert(tok);
1755 tor_assert(tok->n_args >= 8);
1756 if (vote_rs) {
1757 rs = &vote_rs->status;
1758 } else {
1759 rs = tor_malloc_zero(sizeof(routerstatus_t));
1762 if (!is_legal_nickname(tok->args[0])) {
1763 log_warn(LD_DIR,
1764 "Invalid nickname %s in router status; skipping.",
1765 escaped(tok->args[0]));
1766 goto err;
1768 strlcpy(rs->nickname, tok->args[0], sizeof(rs->nickname));
1770 if (digest_from_base64(rs->identity_digest, tok->args[1])) {
1771 log_warn(LD_DIR, "Error decoding identity digest %s",
1772 escaped(tok->args[1]));
1773 goto err;
1776 if (digest_from_base64(rs->descriptor_digest, tok->args[2])) {
1777 log_warn(LD_DIR, "Error decoding descriptor digest %s",
1778 escaped(tok->args[2]));
1779 goto err;
1782 if (tor_snprintf(timebuf, sizeof(timebuf), "%s %s",
1783 tok->args[3], tok->args[4]) < 0 ||
1784 parse_iso_time(timebuf, &rs->published_on)<0) {
1785 log_warn(LD_DIR, "Error parsing time '%s %s'",
1786 tok->args[3], tok->args[4]);
1787 goto err;
1790 if (tor_inet_aton(tok->args[5], &in) == 0) {
1791 log_warn(LD_DIR, "Error parsing router address in network-status %s",
1792 escaped(tok->args[5]));
1793 goto err;
1795 rs->addr = ntohl(in.s_addr);
1797 rs->or_port =(uint16_t) tor_parse_long(tok->args[6],10,0,65535,NULL,NULL);
1798 rs->dir_port = (uint16_t) tor_parse_long(tok->args[7],10,0,65535,NULL,NULL);
1800 tok = find_first_by_keyword(tokens, K_S);
1801 if (tok && vote) {
1802 int i;
1803 vote_rs->flags = 0;
1804 for (i=0; i < tok->n_args; ++i) {
1805 int p = smartlist_string_pos(vote->known_flags, tok->args[i]);
1806 if (p >= 0) {
1807 vote_rs->flags |= (1<<p);
1808 } else {
1809 log_warn(LD_DIR, "Flags line had a flag %s not listed in known_flags.",
1810 escaped(tok->args[i]));
1811 goto err;
1814 } else if (tok) {
1815 int i;
1816 for (i=0; i < tok->n_args; ++i) {
1817 if (!strcmp(tok->args[i], "Exit"))
1818 rs->is_exit = 1;
1819 else if (!strcmp(tok->args[i], "Stable"))
1820 rs->is_stable = 1;
1821 else if (!strcmp(tok->args[i], "Fast"))
1822 rs->is_fast = 1;
1823 else if (!strcmp(tok->args[i], "Running"))
1824 rs->is_running = 1;
1825 else if (!strcmp(tok->args[i], "Named"))
1826 rs->is_named = 1;
1827 else if (!strcmp(tok->args[i], "Valid"))
1828 rs->is_valid = 1;
1829 else if (!strcmp(tok->args[i], "V2Dir"))
1830 rs->is_v2_dir = 1;
1831 else if (!strcmp(tok->args[i], "Guard"))
1832 rs->is_possible_guard = 1;
1833 else if (!strcmp(tok->args[i], "BadExit"))
1834 rs->is_bad_exit = 1;
1835 else if (!strcmp(tok->args[i], "BadDirectory"))
1836 rs->is_bad_directory = 1;
1837 else if (!strcmp(tok->args[i], "Authority"))
1838 rs->is_authority = 1;
1839 else if (!strcmp(tok->args[i], "Unnamed") &&
1840 consensus_method >= 2) {
1841 /* Unnamed is computed right by consensus method 2 and later. */
1842 rs->is_unnamed = 1;
1843 } else if (!strcmp(tok->args[i], "HSDir")) {
1844 rs->is_hs_dir = 1;
1848 if ((tok = find_first_by_keyword(tokens, K_V))) {
1849 tor_assert(tok->n_args == 1);
1850 rs->version_known = 1;
1851 if (strcmpstart(tok->args[0], "Tor ")) {
1852 rs->version_supports_begindir = 1;
1853 rs->version_supports_extrainfo_upload = 1;
1854 rs->version_supports_conditional_consensus = 1;
1855 } else {
1856 rs->version_supports_begindir =
1857 tor_version_as_new_as(tok->args[0], "0.2.0.1-alpha");
1858 rs->version_supports_extrainfo_upload =
1859 tor_version_as_new_as(tok->args[0], "0.2.0.0-alpha-dev (r10070)");
1860 rs->version_supports_v3_dir =
1861 tor_version_as_new_as(tok->args[0], "0.2.0.8-alpha");
1862 rs->version_supports_conditional_consensus =
1863 tor_version_as_new_as(tok->args[0], "0.2.1.1-alpha");
1865 if (vote_rs) {
1866 vote_rs->version = tor_strdup(tok->args[0]);
1870 /* handle weighting/bandwidth info */
1871 if ((tok = find_first_by_keyword(tokens, K_W))) {
1872 int i;
1873 for (i=0; i < tok->n_args; ++i) {
1874 if (!strcmpstart(tok->args[i], "Bandwidth=")) {
1875 int ok;
1876 rs->bandwidth = tor_parse_ulong(strchr(tok->args[i], '=')+1, 10,
1877 0, UINT32_MAX, &ok, NULL);
1878 if (!ok) {
1879 log_warn(LD_DIR, "Invalid Bandwidth %s", escaped(tok->args[i]));
1880 goto err;
1882 rs->has_bandwidth = 1;
1887 /* parse exit policy summaries */
1888 if ((tok = find_first_by_keyword(tokens, K_P))) {
1889 tor_assert(tok->n_args == 2);
1890 if (!strcmp(tok->args[0], "accept"))
1891 rs->exitsummary_type = ADDR_POLICY_ACCEPT;
1892 else if (!strcmp(tok->args[0], "reject"))
1893 rs->exitsummary_type = ADDR_POLICY_REJECT;
1894 else {
1895 log_warn(LD_DIR, "Unknown exit policy summary type %s.",
1896 escaped(tok->args[0]));
1897 goto err;
1899 /* XXX weasel: parse this into ports and represent them somehow smart */
1900 rs->exitsummary = tor_strdup(tok->args[1]);
1901 rs->has_exitsummary = 1;
1904 if (!strcasecmp(rs->nickname, UNNAMED_ROUTER_NICKNAME))
1905 rs->is_named = 0;
1907 goto done;
1908 err:
1909 if (rs && !vote_rs)
1910 routerstatus_free(rs);
1911 rs = NULL;
1912 done:
1913 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
1914 smartlist_clear(tokens);
1915 if (area) {
1916 DUMP_AREA(area, "routerstatus entry");
1917 memarea_clear(area);
1919 *s = eos;
1921 return rs;
1924 /** Helper to sort a smartlist of pointers to routerstatus_t */
1925 static int
1926 _compare_routerstatus_entries(const void **_a, const void **_b)
1928 const routerstatus_t *a = *_a, *b = *_b;
1929 return memcmp(a->identity_digest, b->identity_digest, DIGEST_LEN);
1932 /** Helper: used in call to _smartlist_uniq to clear out duplicate entries. */
1933 static void
1934 _free_duplicate_routerstatus_entry(void *e)
1936 log_warn(LD_DIR,
1937 "Network-status has two entries for the same router. "
1938 "Dropping one.");
1939 routerstatus_free(e);
1942 /** Given a v2 network-status object in <b>s</b>, try to
1943 * parse it and return the result. Return NULL on failure. Check the
1944 * signature of the network status, but do not (yet) check the signing key for
1945 * authority.
1947 networkstatus_v2_t *
1948 networkstatus_v2_parse_from_string(const char *s)
1950 const char *eos;
1951 smartlist_t *tokens = smartlist_create();
1952 smartlist_t *footer_tokens = smartlist_create();
1953 networkstatus_v2_t *ns = NULL;
1954 char ns_digest[DIGEST_LEN];
1955 char tmp_digest[DIGEST_LEN];
1956 struct in_addr in;
1957 directory_token_t *tok;
1958 int i;
1959 memarea_t *area = NULL;
1961 if (router_get_networkstatus_v2_hash(s, ns_digest)) {
1962 log_warn(LD_DIR, "Unable to compute digest of network-status");
1963 goto err;
1966 area = memarea_new(8192);
1967 eos = find_start_of_next_routerstatus(s);
1968 if (tokenize_string(area, s, eos, tokens, netstatus_token_table,0)) {
1969 log_warn(LD_DIR, "Error tokenizing network-status header.");
1970 goto err;
1972 ns = tor_malloc_zero(sizeof(networkstatus_v2_t));
1973 memcpy(ns->networkstatus_digest, ns_digest, DIGEST_LEN);
1975 tok = find_first_by_keyword(tokens, K_NETWORK_STATUS_VERSION);
1976 tor_assert(tok && tok->n_args >= 1);
1977 if (strcmp(tok->args[0], "2")) {
1978 log_warn(LD_BUG, "Got a non-v2 networkstatus. Version was "
1979 "%s", escaped(tok->args[0]));
1980 goto err;
1983 tok = find_first_by_keyword(tokens, K_DIR_SOURCE);
1984 tor_assert(tok);
1985 tor_assert(tok->n_args >= 3);
1986 ns->source_address = tor_strdup(tok->args[0]);
1987 if (tor_inet_aton(tok->args[1], &in) == 0) {
1988 log_warn(LD_DIR, "Error parsing network-status source address %s",
1989 escaped(tok->args[1]));
1990 goto err;
1992 ns->source_addr = ntohl(in.s_addr);
1993 ns->source_dirport =
1994 (uint16_t) tor_parse_long(tok->args[2],10,0,65535,NULL,NULL);
1995 if (ns->source_dirport == 0) {
1996 log_warn(LD_DIR, "Directory source without dirport; skipping.");
1997 goto err;
2000 tok = find_first_by_keyword(tokens, K_FINGERPRINT);
2001 tor_assert(tok);
2002 tor_assert(tok->n_args != 0);
2003 if (base16_decode(ns->identity_digest, DIGEST_LEN, tok->args[0],
2004 strlen(tok->args[0]))) {
2005 log_warn(LD_DIR, "Couldn't decode networkstatus fingerprint %s",
2006 escaped(tok->args[0]));
2007 goto err;
2010 if ((tok = find_first_by_keyword(tokens, K_CONTACT))) {
2011 tor_assert(tok->n_args != 0);
2012 ns->contact = tor_strdup(tok->args[0]);
2015 tok = find_first_by_keyword(tokens, K_DIR_SIGNING_KEY);
2016 tor_assert(tok && tok->key);
2017 ns->signing_key = tok->key;
2018 tok->key = NULL;
2020 if (crypto_pk_get_digest(ns->signing_key, tmp_digest)<0) {
2021 log_warn(LD_DIR, "Couldn't compute signing key digest");
2022 goto err;
2024 if (memcmp(tmp_digest, ns->identity_digest, DIGEST_LEN)) {
2025 log_warn(LD_DIR,
2026 "network-status fingerprint did not match dir-signing-key");
2027 goto err;
2030 if ((tok = find_first_by_keyword(tokens, K_DIR_OPTIONS))) {
2031 for (i=0; i < tok->n_args; ++i) {
2032 if (!strcmp(tok->args[i], "Names"))
2033 ns->binds_names = 1;
2034 if (!strcmp(tok->args[i], "Versions"))
2035 ns->recommends_versions = 1;
2036 if (!strcmp(tok->args[i], "BadExits"))
2037 ns->lists_bad_exits = 1;
2038 if (!strcmp(tok->args[i], "BadDirectories"))
2039 ns->lists_bad_directories = 1;
2043 if (ns->recommends_versions) {
2044 if (!(tok = find_first_by_keyword(tokens, K_CLIENT_VERSIONS))) {
2045 log_warn(LD_DIR, "Missing client-versions on versioning directory");
2046 goto err;
2048 ns->client_versions = tor_strdup(tok->args[0]);
2050 if (!(tok = find_first_by_keyword(tokens, K_SERVER_VERSIONS)) ||
2051 tok->n_args<1) {
2052 log_warn(LD_DIR, "Missing server-versions on versioning directory");
2053 goto err;
2055 ns->server_versions = tor_strdup(tok->args[0]);
2058 tok = find_first_by_keyword(tokens, K_PUBLISHED);
2059 tor_assert(tok);
2060 tor_assert(tok->n_args == 1);
2061 if (parse_iso_time(tok->args[0], &ns->published_on) < 0) {
2062 goto err;
2065 ns->entries = smartlist_create();
2066 s = eos;
2067 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
2068 smartlist_clear(tokens);
2069 memarea_clear(area);
2070 while (!strcmpstart(s, "r ")) {
2071 routerstatus_t *rs;
2072 if ((rs = routerstatus_parse_entry_from_string(area, &s, tokens,
2073 NULL, NULL, 0)))
2074 smartlist_add(ns->entries, rs);
2076 smartlist_sort(ns->entries, _compare_routerstatus_entries);
2077 smartlist_uniq(ns->entries, _compare_routerstatus_entries,
2078 _free_duplicate_routerstatus_entry);
2080 if (tokenize_string(area,s, NULL, footer_tokens, dir_footer_token_table,0)) {
2081 log_warn(LD_DIR, "Error tokenizing network-status footer.");
2082 goto err;
2084 if (smartlist_len(footer_tokens) < 1) {
2085 log_warn(LD_DIR, "Too few items in network-status footer.");
2086 goto err;
2088 tok = smartlist_get(footer_tokens, smartlist_len(footer_tokens)-1);
2089 if (tok->tp != K_DIRECTORY_SIGNATURE) {
2090 log_warn(LD_DIR,
2091 "Expected network-status footer to end with a signature.");
2092 goto err;
2095 note_crypto_pk_op(VERIFY_DIR);
2096 if (check_signature_token(ns_digest, tok, ns->signing_key, 0,
2097 "network-status") < 0)
2098 goto err;
2100 goto done;
2101 err:
2102 if (ns)
2103 networkstatus_v2_free(ns);
2104 ns = NULL;
2105 done:
2106 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
2107 smartlist_free(tokens);
2108 SMARTLIST_FOREACH(footer_tokens, directory_token_t *, t, token_free(t));
2109 smartlist_free(footer_tokens);
2110 if (area) {
2111 DUMP_AREA(area, "v2 networkstatus");
2112 memarea_drop_all(area);
2114 return ns;
2117 /** Parse a v3 networkstatus vote, opinion, or consensus (depending on
2118 * ns_type), from <b>s</b>, and return the result. Return NULL on failure. */
2119 networkstatus_t *
2120 networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
2121 networkstatus_type_t ns_type)
2123 smartlist_t *tokens = smartlist_create();
2124 smartlist_t *rs_tokens = NULL, *footer_tokens = NULL;
2125 networkstatus_voter_info_t *voter = NULL;
2126 networkstatus_t *ns = NULL;
2127 char ns_digest[DIGEST_LEN];
2128 const char *cert, *end_of_header, *end_of_footer;
2129 directory_token_t *tok;
2130 int ok;
2131 struct in_addr in;
2132 int i, inorder, n_signatures = 0;
2133 memarea_t *area = NULL, *rs_area = NULL;
2134 tor_assert(s);
2136 if (router_get_networkstatus_v3_hash(s, ns_digest)) {
2137 log_warn(LD_DIR, "Unable to compute digest of network-status");
2138 goto err;
2141 area = memarea_new(8192);
2142 end_of_header = find_start_of_next_routerstatus(s);
2143 if (tokenize_string(area, s, end_of_header, tokens,
2144 (ns_type == NS_TYPE_CONSENSUS) ?
2145 networkstatus_consensus_token_table :
2146 networkstatus_token_table, 0)) {
2147 log_warn(LD_DIR, "Error tokenizing network-status vote header");
2148 goto err;
2151 ns = tor_malloc_zero(sizeof(networkstatus_t));
2152 memcpy(ns->networkstatus_digest, ns_digest, DIGEST_LEN);
2154 if (ns_type != NS_TYPE_CONSENSUS) {
2155 const char *end_of_cert = NULL;
2156 if (!(cert = strstr(s, "\ndir-key-certificate-version")))
2157 goto err;
2158 ++cert;
2159 ns->cert = authority_cert_parse_from_string(cert, &end_of_cert);
2160 if (!ns->cert || !end_of_cert || end_of_cert > end_of_header)
2161 goto err;
2164 tok = find_first_by_keyword(tokens, K_VOTE_STATUS);
2165 tor_assert(tok);
2166 tor_assert(tok->n_args != 0);
2167 if (!strcmp(tok->args[0], "vote")) {
2168 ns->type = NS_TYPE_VOTE;
2169 } else if (!strcmp(tok->args[0], "consensus")) {
2170 ns->type = NS_TYPE_CONSENSUS;
2171 } else if (!strcmp(tok->args[0], "opinion")) {
2172 ns->type = NS_TYPE_OPINION;
2173 } else {
2174 log_warn(LD_DIR, "Unrecognized vote status %s in network-status",
2175 escaped(tok->args[0]));
2176 goto err;
2178 if (ns_type != ns->type) {
2179 log_warn(LD_DIR, "Got the wrong kind of v3 networkstatus.");
2180 goto err;
2183 if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_OPINION) {
2184 tok = find_first_by_keyword(tokens, K_PUBLISHED);
2185 if (parse_iso_time(tok->args[0], &ns->published))
2186 goto err;
2188 ns->supported_methods = smartlist_create();
2189 tok = find_first_by_keyword(tokens, K_CONSENSUS_METHODS);
2190 if (tok) {
2191 for (i=0; i < tok->n_args; ++i)
2192 smartlist_add(ns->supported_methods, tor_strdup(tok->args[i]));
2193 } else {
2194 smartlist_add(ns->supported_methods, tor_strdup("1"));
2196 } else {
2197 tok = find_first_by_keyword(tokens, K_CONSENSUS_METHOD);
2198 if (tok) {
2199 ns->consensus_method = (int)tor_parse_long(tok->args[0], 10, 1, INT_MAX,
2200 &ok, NULL);
2201 if (!ok)
2202 goto err;
2203 } else {
2204 ns->consensus_method = 1;
2208 tok = find_first_by_keyword(tokens, K_VALID_AFTER);
2209 if (parse_iso_time(tok->args[0], &ns->valid_after))
2210 goto err;
2212 tok = find_first_by_keyword(tokens, K_FRESH_UNTIL);
2213 if (parse_iso_time(tok->args[0], &ns->fresh_until))
2214 goto err;
2216 tok = find_first_by_keyword(tokens, K_VALID_UNTIL);
2217 if (parse_iso_time(tok->args[0], &ns->valid_until))
2218 goto err;
2220 tok = find_first_by_keyword(tokens, K_VOTING_DELAY);
2221 tor_assert(tok->n_args >= 2);
2222 ns->vote_seconds =
2223 (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &ok, NULL);
2224 if (!ok)
2225 goto err;
2226 ns->dist_seconds =
2227 (int) tor_parse_long(tok->args[1], 10, 0, INT_MAX, &ok, NULL);
2228 if (!ok)
2229 goto err;
2230 if (ns->valid_after + MIN_VOTE_INTERVAL > ns->fresh_until) {
2231 log_warn(LD_DIR, "Vote/consensus freshness interval is too short");
2232 goto err;
2234 if (ns->valid_after + MIN_VOTE_INTERVAL*2 > ns->valid_until) {
2235 log_warn(LD_DIR, "Vote/consensus liveness interval is too short");
2236 goto err;
2238 if (ns->vote_seconds < MIN_VOTE_SECONDS) {
2239 log_warn(LD_DIR, "Vote seconds is too short");
2240 goto err;
2242 if (ns->dist_seconds < MIN_DIST_SECONDS) {
2243 log_warn(LD_DIR, "Dist seconds is too short");
2244 goto err;
2247 if ((tok = find_first_by_keyword(tokens, K_CLIENT_VERSIONS))) {
2248 ns->client_versions = tor_strdup(tok->args[0]);
2250 if ((tok = find_first_by_keyword(tokens, K_SERVER_VERSIONS))) {
2251 ns->server_versions = tor_strdup(tok->args[0]);
2254 tok = find_first_by_keyword(tokens, K_KNOWN_FLAGS);
2255 ns->known_flags = smartlist_create();
2256 inorder = 1;
2257 for (i = 0; i < tok->n_args; ++i) {
2258 smartlist_add(ns->known_flags, tor_strdup(tok->args[i]));
2259 if (i>0 && strcmp(tok->args[i-1], tok->args[i])>= 0) {
2260 log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]);
2261 inorder = 0;
2264 if (!inorder) {
2265 log_warn(LD_DIR, "known-flags not in order");
2266 goto err;
2269 ns->voters = smartlist_create();
2271 SMARTLIST_FOREACH(tokens, directory_token_t *, _tok,
2273 tok = _tok;
2274 if (tok->tp == K_DIR_SOURCE) {
2275 tor_assert(tok->n_args >= 6);
2277 if (voter)
2278 smartlist_add(ns->voters, voter);
2279 voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
2280 if (ns->type != NS_TYPE_CONSENSUS)
2281 memcpy(voter->vote_digest, ns_digest, DIGEST_LEN);
2283 voter->nickname = tor_strdup(tok->args[0]);
2284 if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
2285 base16_decode(voter->identity_digest, sizeof(voter->identity_digest),
2286 tok->args[1], HEX_DIGEST_LEN) < 0) {
2287 log_warn(LD_DIR, "Error decoding identity digest %s in "
2288 "network-status vote.", escaped(tok->args[1]));
2289 goto err;
2291 if (ns->type != NS_TYPE_CONSENSUS &&
2292 memcmp(ns->cert->cache_info.identity_digest,
2293 voter->identity_digest, DIGEST_LEN)) {
2294 log_warn(LD_DIR,"Mismatch between identities in certificate and vote");
2295 goto err;
2297 voter->address = tor_strdup(tok->args[2]);
2298 if (!tor_inet_aton(tok->args[3], &in)) {
2299 log_warn(LD_DIR, "Error decoding IP address %s in network-status.",
2300 escaped(tok->args[3]));
2301 goto err;
2303 voter->addr = ntohl(in.s_addr);
2304 voter->dir_port = (uint16_t)
2305 tor_parse_long(tok->args[4], 10, 0, 65535, &ok, NULL);
2306 if (!ok)
2307 goto err;
2308 voter->or_port = (uint16_t)
2309 tor_parse_long(tok->args[5], 10, 0, 65535, &ok, NULL);
2310 if (!ok)
2311 goto err;
2312 } else if (tok->tp == K_CONTACT) {
2313 if (!voter || voter->contact) {
2314 log_warn(LD_DIR, "contact element is out of place.");
2315 goto err;
2317 voter->contact = tor_strdup(tok->args[0]);
2318 } else if (tok->tp == K_VOTE_DIGEST) {
2319 tor_assert(ns->type == NS_TYPE_CONSENSUS);
2320 tor_assert(tok->n_args >= 1);
2321 if (!voter || ! tor_digest_is_zero(voter->vote_digest)) {
2322 log_warn(LD_DIR, "vote-digest element is out of place.");
2323 goto err;
2325 if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
2326 base16_decode(voter->vote_digest, sizeof(voter->vote_digest),
2327 tok->args[0], HEX_DIGEST_LEN) < 0) {
2328 log_warn(LD_DIR, "Error decoding vote digest %s in "
2329 "network-status consensus.", escaped(tok->args[1]));
2330 goto err;
2334 if (voter) {
2335 smartlist_add(ns->voters, voter);
2336 voter = NULL;
2338 if (smartlist_len(ns->voters) == 0) {
2339 log_warn(LD_DIR, "Missing dir-source elements in a vote networkstatus.");
2340 goto err;
2341 } else if (ns->type != NS_TYPE_CONSENSUS && smartlist_len(ns->voters) != 1) {
2342 log_warn(LD_DIR, "Too many dir-source elements in a vote networkstatus.");
2343 goto err;
2346 if (ns->type != NS_TYPE_CONSENSUS &&
2347 (tok = find_first_by_keyword(tokens, K_LEGACY_DIR_KEY))) {
2348 int bad = 1;
2349 if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {
2350 networkstatus_voter_info_t *voter = smartlist_get(ns->voters, 0);
2351 if (base16_decode(voter->legacy_id_digest, DIGEST_LEN,
2352 tok->args[0], HEX_DIGEST_LEN)<0)
2353 bad = 1;
2354 else
2355 bad = 0;
2357 if (bad) {
2358 log_warn(LD_DIR, "Invalid legacy key digest %s on vote.",
2359 escaped(tok->args[0]));
2363 /* Parse routerstatus lines. */
2364 rs_tokens = smartlist_create();
2365 rs_area = memarea_new(512);
2366 s = end_of_header;
2367 ns->routerstatus_list = smartlist_create();
2369 while (!strcmpstart(s, "r ")) {
2370 if (ns->type != NS_TYPE_CONSENSUS) {
2371 vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t));
2372 if (routerstatus_parse_entry_from_string(rs_area, &s, rs_tokens, ns,
2373 rs, 0))
2374 smartlist_add(ns->routerstatus_list, rs);
2375 else {
2376 tor_free(rs->version);
2377 tor_free(rs);
2379 } else {
2380 routerstatus_t *rs;
2381 if ((rs = routerstatus_parse_entry_from_string(rs_area, &s, rs_tokens,
2382 NULL, NULL,
2383 ns->consensus_method)))
2384 smartlist_add(ns->routerstatus_list, rs);
2387 for (i = 1; i < smartlist_len(ns->routerstatus_list); ++i) {
2388 routerstatus_t *rs1, *rs2;
2389 if (ns->type != NS_TYPE_CONSENSUS) {
2390 vote_routerstatus_t *a = smartlist_get(ns->routerstatus_list, i-1);
2391 vote_routerstatus_t *b = smartlist_get(ns->routerstatus_list, i);
2392 rs1 = &a->status; rs2 = &b->status;
2393 } else {
2394 rs1 = smartlist_get(ns->routerstatus_list, i-1);
2395 rs2 = smartlist_get(ns->routerstatus_list, i);
2397 if (memcmp(rs1->identity_digest, rs2->identity_digest, DIGEST_LEN) >= 0) {
2398 log_warn(LD_DIR, "Vote networkstatus entries not sorted by identity "
2399 "digest");
2400 goto err;
2404 /* Parse footer; check signature. */
2405 footer_tokens = smartlist_create();
2406 if ((end_of_footer = strstr(s, "\nnetwork-status-version ")))
2407 ++end_of_footer;
2408 else
2409 end_of_footer = s + strlen(s);
2410 if (tokenize_string(area,s, end_of_footer, footer_tokens,
2411 networkstatus_vote_footer_token_table, 0)) {
2412 log_warn(LD_DIR, "Error tokenizing network-status vote footer.");
2413 goto err;
2416 SMARTLIST_FOREACH(footer_tokens, directory_token_t *, _tok,
2418 char declared_identity[DIGEST_LEN];
2419 networkstatus_voter_info_t *v;
2420 tok = _tok;
2421 if (tok->tp != K_DIRECTORY_SIGNATURE)
2422 continue;
2423 tor_assert(tok->n_args >= 2);
2425 if (!tok->object_type ||
2426 strcmp(tok->object_type, "SIGNATURE") ||
2427 tok->object_size < 128 || tok->object_size > 512) {
2428 log_warn(LD_DIR, "Bad object type or length on directory-signature");
2429 goto err;
2432 if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
2433 base16_decode(declared_identity, sizeof(declared_identity),
2434 tok->args[0], HEX_DIGEST_LEN) < 0) {
2435 log_warn(LD_DIR, "Error decoding declared identity %s in "
2436 "network-status vote.", escaped(tok->args[0]));
2437 goto err;
2439 if (!(v = networkstatus_get_voter_by_id(ns, declared_identity))) {
2440 log_warn(LD_DIR, "ID on signature on network-status vote does not match "
2441 "any declared directory source.");
2442 goto err;
2444 if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
2445 base16_decode(v->signing_key_digest, sizeof(v->signing_key_digest),
2446 tok->args[1], HEX_DIGEST_LEN) < 0) {
2447 log_warn(LD_DIR, "Error decoding declared digest %s in "
2448 "network-status vote.", escaped(tok->args[1]));
2449 goto err;
2452 if (ns->type != NS_TYPE_CONSENSUS) {
2453 if (memcmp(declared_identity, ns->cert->cache_info.identity_digest,
2454 DIGEST_LEN)) {
2455 log_warn(LD_DIR, "Digest mismatch between declared and actual on "
2456 "network-status vote.");
2457 goto err;
2461 if (ns->type != NS_TYPE_CONSENSUS) {
2462 if (check_signature_token(ns_digest, tok, ns->cert->signing_key, 0,
2463 "network-status vote"))
2464 goto err;
2465 v->good_signature = 1;
2466 } else {
2467 if (tok->object_size >= INT_MAX)
2468 goto err;
2469 v->signature = tor_memdup(tok->object_body, tok->object_size);
2470 v->signature_len = (int) tok->object_size;
2472 ++n_signatures;
2475 if (! n_signatures) {
2476 log_warn(LD_DIR, "No signatures on networkstatus vote.");
2477 goto err;
2480 if (eos_out)
2481 *eos_out = end_of_footer;
2483 goto done;
2484 err:
2485 if (ns)
2486 networkstatus_vote_free(ns);
2487 ns = NULL;
2488 done:
2489 if (tokens) {
2490 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
2491 smartlist_free(tokens);
2493 if (voter) {
2494 tor_free(voter->nickname);
2495 tor_free(voter->address);
2496 tor_free(voter->contact);
2497 tor_free(voter->signature);
2498 tor_free(voter);
2500 if (rs_tokens) {
2501 SMARTLIST_FOREACH(rs_tokens, directory_token_t *, t, token_free(t));
2502 smartlist_free(rs_tokens);
2504 if (footer_tokens) {
2505 SMARTLIST_FOREACH(footer_tokens, directory_token_t *, t, token_free(t));
2506 smartlist_free(footer_tokens);
2508 if (area) {
2509 DUMP_AREA(area, "v3 networkstatus");
2510 memarea_drop_all(area);
2512 if (rs_area)
2513 memarea_drop_all(rs_area);
2515 return ns;
2518 /** Parse a detached v3 networkstatus signature document between <b>s</b> and
2519 * <b>eos</b> and return the result. Return -1 on failure. */
2520 ns_detached_signatures_t *
2521 networkstatus_parse_detached_signatures(const char *s, const char *eos)
2523 /* XXXX021 there is too much duplicate code here. */
2524 directory_token_t *tok;
2525 memarea_t *area = NULL;
2527 smartlist_t *tokens = smartlist_create();
2528 ns_detached_signatures_t *sigs =
2529 tor_malloc_zero(sizeof(ns_detached_signatures_t));
2531 if (!eos)
2532 eos = s + strlen(s);
2534 area = memarea_new(8192);
2535 if (tokenize_string(area,s, eos, tokens,
2536 networkstatus_detached_signature_token_table, 0)) {
2537 log_warn(LD_DIR, "Error tokenizing detached networkstatus signatures");
2538 goto err;
2541 tok = find_first_by_keyword(tokens, K_CONSENSUS_DIGEST);
2542 if (strlen(tok->args[0]) != HEX_DIGEST_LEN) {
2543 log_warn(LD_DIR, "Wrong length on consensus-digest in detached "
2544 "networkstatus signatures");
2545 goto err;
2547 if (base16_decode(sigs->networkstatus_digest, DIGEST_LEN,
2548 tok->args[0], strlen(tok->args[0])) < 0) {
2549 log_warn(LD_DIR, "Bad encoding on on consensus-digest in detached "
2550 "networkstatus signatures");
2551 goto err;
2554 tok = find_first_by_keyword(tokens, K_VALID_AFTER);
2555 if (parse_iso_time(tok->args[0], &sigs->valid_after)) {
2556 log_warn(LD_DIR, "Bad valid-after in detached networkstatus signatures");
2557 goto err;
2560 tok = find_first_by_keyword(tokens, K_FRESH_UNTIL);
2561 if (parse_iso_time(tok->args[0], &sigs->fresh_until)) {
2562 log_warn(LD_DIR, "Bad fresh-until in detached networkstatus signatures");
2563 goto err;
2566 tok = find_first_by_keyword(tokens, K_VALID_UNTIL);
2567 if (parse_iso_time(tok->args[0], &sigs->valid_until)) {
2568 log_warn(LD_DIR, "Bad valid-until in detached networkstatus signatures");
2569 goto err;
2572 sigs->signatures = smartlist_create();
2573 SMARTLIST_FOREACH(tokens, directory_token_t *, _tok,
2575 char id_digest[DIGEST_LEN];
2576 char sk_digest[DIGEST_LEN];
2577 networkstatus_voter_info_t *voter;
2579 tok = _tok;
2580 if (tok->tp != K_DIRECTORY_SIGNATURE)
2581 continue;
2582 tor_assert(tok->n_args >= 2);
2584 if (!tok->object_type ||
2585 strcmp(tok->object_type, "SIGNATURE") ||
2586 tok->object_size < 128 || tok->object_size > 512) {
2587 log_warn(LD_DIR, "Bad object type or length on directory-signature");
2588 goto err;
2591 if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
2592 base16_decode(id_digest, sizeof(id_digest),
2593 tok->args[0], HEX_DIGEST_LEN) < 0) {
2594 log_warn(LD_DIR, "Error decoding declared identity %s in "
2595 "network-status vote.", escaped(tok->args[0]));
2596 goto err;
2598 if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
2599 base16_decode(sk_digest, sizeof(sk_digest),
2600 tok->args[1], HEX_DIGEST_LEN) < 0) {
2601 log_warn(LD_DIR, "Error decoding declared digest %s in "
2602 "network-status vote.", escaped(tok->args[1]));
2603 goto err;
2606 voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
2607 memcpy(voter->identity_digest, id_digest, DIGEST_LEN);
2608 memcpy(voter->signing_key_digest, sk_digest, DIGEST_LEN);
2609 if (tok->object_size >= INT_MAX)
2610 goto err;
2611 voter->signature = tor_memdup(tok->object_body, tok->object_size);
2612 voter->signature_len = (int) tok->object_size;
2614 smartlist_add(sigs->signatures, voter);
2617 goto done;
2618 err:
2619 ns_detached_signatures_free(sigs);
2620 sigs = NULL;
2621 done:
2622 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
2623 smartlist_free(tokens);
2624 if (area) {
2625 DUMP_AREA(area, "detached signatures");
2626 memarea_drop_all(area);
2628 return sigs;
2631 /** Parse the addr policy in the string <b>s</b> and return it. If
2632 * assume_action is nonnegative, then insert its action (ADDR_POLICY_ACCEPT or
2633 * ADDR_POLICY_REJECT) for items that specify no action.
2635 addr_policy_t *
2636 router_parse_addr_policy_item_from_string(const char *s, int assume_action)
2638 directory_token_t *tok = NULL;
2639 const char *cp, *eos;
2640 /* Longest possible policy is "accept ffff:ffff:..255/ffff:...255:0-65535".
2641 * But note that there can be an arbitrary amount of space between the
2642 * accept and the address:mask/port element. */
2643 char line[TOR_ADDR_BUF_LEN*2 + 32];
2644 addr_policy_t *r;
2645 memarea_t *area = NULL;
2647 s = eat_whitespace(s);
2648 if ((*s == '*' || TOR_ISDIGIT(*s)) && assume_action >= 0) {
2649 if (tor_snprintf(line, sizeof(line), "%s %s",
2650 assume_action == ADDR_POLICY_ACCEPT?"accept":"reject", s)<0) {
2651 log_warn(LD_DIR, "Policy %s is too long.", escaped(s));
2652 return NULL;
2654 cp = line;
2655 tor_strlower(line);
2656 } else { /* assume an already well-formed address policy line */
2657 cp = s;
2660 eos = cp + strlen(cp);
2661 area = memarea_new(128);
2662 tok = get_next_token(area, &cp, eos, routerdesc_token_table);
2663 if (tok->tp == _ERR) {
2664 log_warn(LD_DIR, "Error reading address policy: %s", tok->error);
2665 goto err;
2667 if (tok->tp != K_ACCEPT && tok->tp != K_ACCEPT6 &&
2668 tok->tp != K_REJECT && tok->tp != K_REJECT6) {
2669 log_warn(LD_DIR, "Expected 'accept' or 'reject'.");
2670 goto err;
2673 r = router_parse_addr_policy(tok);
2674 goto done;
2675 err:
2676 r = NULL;
2677 done:
2678 token_free(tok);
2679 if (area) {
2680 DUMP_AREA(area, "policy item");
2681 memarea_drop_all(area);
2683 return r;
2686 /** Add an exit policy stored in the token <b>tok</b> to the router info in
2687 * <b>router</b>. Return 0 on success, -1 on failure. */
2688 static int
2689 router_add_exit_policy(routerinfo_t *router, directory_token_t *tok)
2691 addr_policy_t *newe;
2692 newe = router_parse_addr_policy(tok);
2693 if (!newe)
2694 return -1;
2695 if (! router->exit_policy)
2696 router->exit_policy = smartlist_create();
2698 if (((tok->tp == K_ACCEPT6 || tok->tp == K_REJECT6) &&
2699 tor_addr_family(&newe->addr) == AF_INET)
2701 ((tok->tp == K_ACCEPT || tok->tp == K_REJECT) &&
2702 tor_addr_family(&newe->addr) == AF_INET6)) {
2703 log_warn(LD_DIR, "Mismatch between field type and address type in exit "
2704 "policy");
2705 addr_policy_free(newe);
2706 return -1;
2709 smartlist_add(router->exit_policy, newe);
2711 return 0;
2714 /** Given a K_ACCEPT or K_REJECT token and a router, create and return
2715 * a new exit_policy_t corresponding to the token. */
2716 static addr_policy_t *
2717 router_parse_addr_policy(directory_token_t *tok)
2719 addr_policy_t newe;
2720 char *arg;
2722 tor_assert(tok->tp == K_REJECT || tok->tp == K_REJECT6 ||
2723 tok->tp == K_ACCEPT || tok->tp == K_ACCEPT6);
2725 if (tok->n_args != 1)
2726 return NULL;
2727 arg = tok->args[0];
2729 if (!strcmpstart(arg,"private"))
2730 return router_parse_addr_policy_private(tok);
2732 memset(&newe, 0, sizeof(newe));
2734 if (tok->tp == K_REJECT || tok->tp == K_REJECT6)
2735 newe.policy_type = ADDR_POLICY_REJECT;
2736 else
2737 newe.policy_type = ADDR_POLICY_ACCEPT;
2739 if (tor_addr_parse_mask_ports(arg, &newe.addr, &newe.maskbits,
2740 &newe.prt_min, &newe.prt_max) < 0) {
2741 log_warn(LD_DIR,"Couldn't parse line %s. Dropping", escaped(arg));
2742 return NULL;
2745 return addr_policy_get_canonical_entry(&newe);
2748 /** Parse an exit policy line of the format "accept/reject private:...".
2749 * This didn't exist until Tor 0.1.1.15, so nobody should generate it in
2750 * router descriptors until earlier versions are obsolete.
2752 static addr_policy_t *
2753 router_parse_addr_policy_private(directory_token_t *tok)
2755 const char *arg;
2756 uint16_t port_min, port_max;
2757 addr_policy_t result;
2759 arg = tok->args[0];
2760 if (strcmpstart(arg, "private"))
2761 return NULL;
2763 arg += strlen("private");
2764 arg = (char*) eat_whitespace(arg);
2765 if (!arg || *arg != ':')
2766 return NULL;
2768 if (parse_port_range(arg+1, &port_min, &port_max)<0)
2769 return NULL;
2771 memset(&result, 0, sizeof(result));
2772 if (tok->tp == K_REJECT || tok->tp == K_REJECT6)
2773 result.policy_type = ADDR_POLICY_REJECT;
2774 else
2775 result.policy_type = ADDR_POLICY_ACCEPT;
2776 result.is_private = 1;
2777 result.prt_min = port_min;
2778 result.prt_max = port_max;
2780 return addr_policy_get_canonical_entry(&result);
2783 /** Log and exit if <b>t</b> is malformed */
2784 void
2785 assert_addr_policy_ok(smartlist_t *lst)
2787 if (!lst) return;
2788 SMARTLIST_FOREACH(lst, addr_policy_t *, t, {
2789 tor_assert(t->policy_type == ADDR_POLICY_REJECT ||
2790 t->policy_type == ADDR_POLICY_ACCEPT);
2791 tor_assert(t->prt_min <= t->prt_max);
2796 * Low-level tokenizer for router descriptors and directories.
2799 /** Free all resources allocated for <b>tok</b> */
2800 static void
2801 token_free(directory_token_t *tok)
2803 tor_assert(tok);
2804 if (tok->key)
2805 crypto_free_pk_env(tok->key);
2808 #define ALLOC_ZERO(sz) memarea_alloc_zero(area,sz)
2809 #define ALLOC(sz) memarea_alloc(area,sz)
2810 #define STRDUP(str) memarea_strdup(area,str)
2811 #define STRNDUP(str,n) memarea_strndup(area,(str),(n))
2813 #define RET_ERR(msg) \
2814 STMT_BEGIN \
2815 if (tok) token_free(tok); \
2816 tok = ALLOC_ZERO(sizeof(directory_token_t)); \
2817 tok->tp = _ERR; \
2818 tok->error = STRDUP(msg); \
2819 goto done_tokenizing; \
2820 STMT_END
2822 static INLINE directory_token_t *
2823 token_check_object(memarea_t *area, const char *kwd,
2824 directory_token_t *tok, obj_syntax o_syn)
2826 char ebuf[128];
2827 switch (o_syn) {
2828 case NO_OBJ:
2829 if (tok->object_body) {
2830 tor_snprintf(ebuf, sizeof(ebuf), "Unexpected object for %s", kwd);
2831 RET_ERR(ebuf);
2833 if (tok->key) {
2834 tor_snprintf(ebuf, sizeof(ebuf), "Unexpected public key for %s", kwd);
2835 RET_ERR(ebuf);
2837 break;
2838 case NEED_OBJ:
2839 if (!tok->object_body) {
2840 tor_snprintf(ebuf, sizeof(ebuf), "Missing object for %s", kwd);
2841 RET_ERR(ebuf);
2843 break;
2844 case NEED_KEY_1024:
2845 case NEED_SKEY_1024:
2846 if (tok->key && crypto_pk_keysize(tok->key) != PK_BYTES) {
2847 tor_snprintf(ebuf, sizeof(ebuf), "Wrong size on key for %s: %d bits",
2848 kwd, (int)crypto_pk_keysize(tok->key));
2849 RET_ERR(ebuf);
2851 /* fall through */
2852 case NEED_KEY:
2853 if (!tok->key) {
2854 tor_snprintf(ebuf, sizeof(ebuf), "Missing public key for %s", kwd);
2856 if (o_syn != NEED_SKEY_1024) {
2857 if (crypto_pk_key_is_private(tok->key)) {
2858 tor_snprintf(ebuf, sizeof(ebuf),
2859 "Private key given for %s, which wants a public key", kwd);
2860 RET_ERR(ebuf);
2862 } else { /* o_syn == NEED_SKEY_1024 */
2863 if (!crypto_pk_key_is_private(tok->key)) {
2864 tor_snprintf(ebuf, sizeof(ebuf),
2865 "Public key given for %s, which wants a private key", kwd);
2866 RET_ERR(ebuf);
2869 break;
2870 case OBJ_OK:
2871 break;
2874 done_tokenizing:
2875 return tok;
2878 /** Helper function: read the next token from *s, advance *s to the end of the
2879 * token, and return the parsed token. Parse *<b>s</b> according to the list
2880 * of tokens in <b>table</b>.
2882 static directory_token_t *
2883 get_next_token(memarea_t *area,
2884 const char **s, const char *eos, token_rule_t *table)
2886 const char *next, *eol, *obstart;
2887 size_t obname_len;
2888 int i;
2889 directory_token_t *tok;
2890 obj_syntax o_syn = NO_OBJ;
2891 char ebuf[128];
2892 const char *kwd = "";
2894 tor_assert(area);
2895 tok = ALLOC_ZERO(sizeof(directory_token_t));
2896 tok->tp = _ERR;
2898 /* Set *s to first token, eol to end-of-line, next to after first token */
2899 *s = eat_whitespace_eos(*s, eos); /* eat multi-line whitespace */
2900 tor_assert(eos >= *s);
2901 eol = memchr(*s, '\n', eos-*s);
2902 if (!eol)
2903 eol = eos;
2904 next = find_whitespace_eos(*s, eol);
2906 if (!strcmp_len(*s, "opt", next-*s)) {
2907 /* Skip past an "opt" at the start of the line. */
2908 *s = eat_whitespace_eos_no_nl(next, eol);
2909 next = find_whitespace_eos(*s, eol);
2910 } else if (*s == eos) { /* If no "opt", and end-of-line, line is invalid */
2911 RET_ERR("Unexpected EOF");
2914 /* Search the table for the appropriate entry. (I tried a binary search
2915 * instead, but it wasn't any faster.) */
2916 for (i = 0; table[i].t ; ++i) {
2917 if (!strcmp_len(*s, table[i].t, next-*s)) {
2918 /* We've found the keyword. */
2919 kwd = table[i].t;
2920 tok->tp = table[i].v;
2921 o_syn = table[i].os;
2922 *s = eat_whitespace_eos_no_nl(next, eol);
2923 next = find_whitespace_eos(*s, eol); /* XXXX021 lower this. */
2924 /* We go ahead whether there are arguments or not, so that tok->args is
2925 * always set if we want arguments. */
2926 if (table[i].concat_args) {
2927 /* The keyword takes the line as a single argument */
2928 tok->args = ALLOC(sizeof(char*));
2929 tok->args[0] = STRNDUP(*s,eol-*s); /* Grab everything on line */
2930 tok->n_args = 1;
2931 } else {
2932 /* This keyword takes multiple arguments. */
2933 /* XXXX021 this code is still too complicated. */
2934 char *mem = memarea_strndup(area, *s, eol-*s);
2935 char *cp = mem;
2936 int j = 0;
2937 while (*cp) {
2938 j++;
2939 cp = (char*)find_whitespace(cp);
2940 if (!cp || !*cp)
2941 break;
2942 cp = (char*)eat_whitespace(cp);
2944 tok->n_args = j;
2945 if (tok->n_args) {
2946 tok->args = memarea_alloc(area, sizeof(char*)*tok->n_args);
2947 cp = mem;
2948 j = 0;
2949 while (*cp) {
2950 tok->args[j++] = cp;
2951 cp = (char*)find_whitespace(cp);
2952 if (!cp || !*cp)
2953 break;
2954 *cp++ = '\0';
2955 cp = (char*)eat_whitespace(cp);
2958 *s = eol;
2960 if (tok->n_args < table[i].min_args) {
2961 tor_snprintf(ebuf, sizeof(ebuf), "Too few arguments to %s", kwd);
2962 RET_ERR(ebuf);
2963 } else if (tok->n_args > table[i].max_args) {
2964 tor_snprintf(ebuf, sizeof(ebuf), "Too many arguments to %s", kwd);
2965 RET_ERR(ebuf);
2967 break;
2971 if (tok->tp == _ERR) {
2972 /* No keyword matched; call it an "K_opt" or "A_unrecognized" */
2973 if (**s == '@')
2974 tok->tp = _A_UNKNOWN;
2975 else
2976 tok->tp = K_OPT;
2977 tok->args = ALLOC(sizeof(char*));
2978 tok->args[0] = STRNDUP(*s, eol-*s);
2979 tok->n_args = 1;
2980 o_syn = OBJ_OK;
2983 /* Check whether there's an object present */
2984 *s = eat_whitespace_eos(eol, eos); /* Scan from end of first line */
2985 tor_assert(eos >= *s);
2986 eol = memchr(*s, '\n', eos-*s);
2987 if (!eol || eol-*s<11 || strcmpstart(*s, "-----BEGIN ")) /* No object. */
2988 goto check_object;
2990 obstart = *s; /* Set obstart to start of object spec */
2991 tor_assert(eol >= (*s+16));
2992 if (*s+11 >= eol-5 || memchr(*s+11,'\0',eol-*s-16) || /* no short lines, */
2993 strcmp_len(eol-5, "-----", 5)) { /* nuls or invalid endings */
2994 RET_ERR("Malformed object: bad begin line");
2996 tok->object_type = STRNDUP(*s+11, eol-*s-16);
2997 obname_len = eol-*s-16; /* store objname length here to avoid a strlen() */
2998 *s = eol+1; /* Set *s to possible start of object data (could be eos) */
3000 /* Go to the end of the object */
3001 next = tor_memstr(*s, eos-*s, "-----END ");
3002 if (!next) {
3003 RET_ERR("Malformed object: missing object end line");
3005 tor_assert(eos >= next);
3006 eol = memchr(next, '\n', eos-next);
3007 if (!eol) /* end-of-line marker, or eos if there's no '\n' */
3008 eol = eos;
3009 /* Validate the ending tag, which should be 9 + NAME + 5 + eol */
3010 if ((size_t)(eol-next) != 9+obname_len+5 ||
3011 strcmp_len(next+9, tok->object_type, obname_len) ||
3012 strcmp_len(eol-5, "-----", 5)) {
3013 snprintf(ebuf, sizeof(ebuf), "Malformed object: mismatched end tag %s",
3014 tok->object_type);
3015 ebuf[sizeof(ebuf)-1] = '\0';
3016 RET_ERR(ebuf);
3018 if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) { /* If it's a public key */
3019 tok->key = crypto_new_pk_env();
3020 if (crypto_pk_read_public_key_from_string(tok->key, obstart, eol-obstart))
3021 RET_ERR("Couldn't parse public key.");
3022 } else if (!strcmp(tok->object_type, "RSA PRIVATE KEY")) { /* private key */
3023 tok->key = crypto_new_pk_env();
3024 if (crypto_pk_read_private_key_from_string(tok->key, obstart))
3025 RET_ERR("Couldn't parse private key.");
3026 } else { /* If it's something else, try to base64-decode it */
3027 int r;
3028 tok->object_body = ALLOC(next-*s); /* really, this is too much RAM. */
3029 r = base64_decode(tok->object_body, next-*s, *s, next-*s);
3030 if (r<0)
3031 RET_ERR("Malformed object: bad base64-encoded data");
3032 tok->object_size = r;
3034 *s = eol;
3036 check_object:
3037 tok = token_check_object(area, kwd, tok, o_syn);
3039 done_tokenizing:
3040 return tok;
3042 #undef RET_ERR
3043 #undef ALLOC
3044 #undef ALLOC_ZERO
3045 #undef STRDUP
3046 #undef STRNDUP
3049 /** Read all tokens from a string between <b>start</b> and <b>end</b>, and add
3050 * them to <b>out</b>. Parse according to the token rules in <b>table</b>.
3051 * Caller must free tokens in <b>out</b>. If <b>end</b> is NULL, use the
3052 * entire string.
3054 static int
3055 tokenize_string(memarea_t *area,
3056 const char *start, const char *end, smartlist_t *out,
3057 token_rule_t *table, int flags)
3059 const char **s;
3060 directory_token_t *tok = NULL;
3061 int counts[_NIL];
3062 int i;
3063 int first_nonannotation;
3064 int prev_len = smartlist_len(out);
3065 tor_assert(area);
3067 s = &start;
3068 if (!end)
3069 end = start+strlen(start);
3070 for (i = 0; i < _NIL; ++i)
3071 counts[i] = 0;
3072 while (*s < end && (!tok || tok->tp != _EOF)) {
3073 tok = get_next_token(area, s, end, table);
3074 if (tok->tp == _ERR) {
3075 log_warn(LD_DIR, "parse error: %s", tok->error);
3076 token_free(tok);
3077 return -1;
3079 ++counts[tok->tp];
3080 smartlist_add(out, tok);
3081 *s = eat_whitespace_eos(*s, end);
3084 if (flags & TS_NOCHECK)
3085 return 0;
3087 if ((flags & TS_ANNOTATIONS_OK)) {
3088 first_nonannotation = -1;
3089 for (i = 0; i < smartlist_len(out); ++i) {
3090 tok = smartlist_get(out, i);
3091 if (tok->tp < MIN_ANNOTATION || tok->tp > MAX_ANNOTATION) {
3092 first_nonannotation = i;
3093 break;
3096 if (first_nonannotation < 0) {
3097 log_warn(LD_DIR, "parse error: item contains only annotations");
3098 return -1;
3100 for (i=first_nonannotation; i < smartlist_len(out); ++i) {
3101 tok = smartlist_get(out, i);
3102 if (tok->tp >= MIN_ANNOTATION && tok->tp <= MAX_ANNOTATION) {
3103 log_warn(LD_DIR, "parse error: Annotations mixed with keywords");
3104 return -1;
3107 if ((flags & TS_NO_NEW_ANNOTATIONS)) {
3108 if (first_nonannotation != prev_len) {
3109 log_warn(LD_DIR, "parse error: Unexpectd annotations.");
3110 return -1;
3113 } else {
3114 for (i=0; i < smartlist_len(out); ++i) {
3115 tok = smartlist_get(out, i);
3116 if (tok->tp >= MIN_ANNOTATION && tok->tp <= MAX_ANNOTATION) {
3117 log_warn(LD_DIR, "parse error: no annotations allowed.");
3118 return -1;
3121 first_nonannotation = 0;
3123 for (i = 0; table[i].t; ++i) {
3124 if (counts[table[i].v] < table[i].min_cnt) {
3125 log_warn(LD_DIR, "Parse error: missing %s element.", table[i].t);
3126 return -1;
3128 if (counts[table[i].v] > table[i].max_cnt) {
3129 log_warn(LD_DIR, "Parse error: too many %s elements.", table[i].t);
3130 return -1;
3132 if (table[i].pos & AT_START) {
3133 if (smartlist_len(out) < 1 ||
3134 (tok = smartlist_get(out, first_nonannotation))->tp != table[i].v) {
3135 log_warn(LD_DIR, "Parse error: first item is not %s.", table[i].t);
3136 return -1;
3139 if (table[i].pos & AT_END) {
3140 if (smartlist_len(out) < 1 ||
3141 (tok = smartlist_get(out, smartlist_len(out)-1))->tp != table[i].v) {
3142 log_warn(LD_DIR, "Parse error: last item is not %s.", table[i].t);
3143 return -1;
3147 return 0;
3150 /** Find the first token in <b>s</b> whose keyword is <b>keyword</b>; return
3151 * NULL if no such keyword is found.
3153 static directory_token_t *
3154 find_first_by_keyword(smartlist_t *s, directory_keyword keyword)
3156 SMARTLIST_FOREACH(s, directory_token_t *, t, if (t->tp == keyword) return t);
3157 return NULL;
3160 /** Return a newly allocated smartlist of all accept or reject tokens in
3161 * <b>s</b>.
3163 static smartlist_t *
3164 find_all_exitpolicy(smartlist_t *s)
3166 smartlist_t *out = smartlist_create();
3167 SMARTLIST_FOREACH(s, directory_token_t *, t,
3168 if (t->tp == K_ACCEPT || t->tp == K_ACCEPT6 ||
3169 t->tp == K_REJECT || t->tp == K_REJECT6)
3170 smartlist_add(out,t));
3171 return out;
3174 /** Compute the SHA-1 digest of the substring of <b>s</b> taken from the first
3175 * occurrence of <b>start_str</b> through the first instance of c after the
3176 * first subsequent occurrence of <b>end_str</b>; store the 20-byte result in
3177 * <b>digest</b>; return 0 on success.
3179 * If no such substring exists, return -1.
3181 static int
3182 router_get_hash_impl(const char *s, char *digest,
3183 const char *start_str,
3184 const char *end_str, char end_c)
3186 char *start, *end;
3187 start = strstr(s, start_str);
3188 if (!start) {
3189 log_warn(LD_DIR,"couldn't find start of hashed material \"%s\"",start_str);
3190 return -1;
3192 if (start != s && *(start-1) != '\n') {
3193 log_warn(LD_DIR,
3194 "first occurrence of \"%s\" is not at the start of a line",
3195 start_str);
3196 return -1;
3198 end = strstr(start+strlen(start_str), end_str);
3199 if (!end) {
3200 log_warn(LD_DIR,"couldn't find end of hashed material \"%s\"",end_str);
3201 return -1;
3203 end = strchr(end+strlen(end_str), end_c);
3204 if (!end) {
3205 log_warn(LD_DIR,"couldn't find EOL");
3206 return -1;
3208 ++end;
3210 if (crypto_digest(digest, start, end-start)) {
3211 log_warn(LD_BUG,"couldn't compute digest");
3212 return -1;
3215 return 0;
3218 /** Parse the Tor version of the platform string <b>platform</b>,
3219 * and compare it to the version in <b>cutoff</b>. Return 1 if
3220 * the router is at least as new as the cutoff, else return 0.
3223 tor_version_as_new_as(const char *platform, const char *cutoff)
3225 tor_version_t cutoff_version, router_version;
3226 char *s, *s2, *start;
3227 char tmp[128];
3229 tor_assert(platform);
3231 if (tor_version_parse(cutoff, &cutoff_version)<0) {
3232 log_warn(LD_BUG,"cutoff version '%s' unparseable.",cutoff);
3233 return 0;
3235 if (strcmpstart(platform,"Tor ")) /* nonstandard Tor; be safe and say yes */
3236 return 1;
3238 start = (char *)eat_whitespace(platform+3);
3239 if (!*start) return 0;
3240 s = (char *)find_whitespace(start); /* also finds '\0', which is fine */
3241 s2 = (char*)eat_whitespace(s);
3242 if (!strcmpstart(s2, "(r"))
3243 s = (char*)find_whitespace(s2);
3245 if ((size_t)(s-start+1) >= sizeof(tmp)) /* too big, no */
3246 return 0;
3247 strlcpy(tmp, start, s-start+1);
3249 if (tor_version_parse(tmp, &router_version)<0) {
3250 log_info(LD_DIR,"Router version '%s' unparseable.",tmp);
3251 return 1; /* be safe and say yes */
3254 /* Here's why we don't need to do any special handling for svn revisions:
3255 * - If neither has an svn revision, we're fine.
3256 * - If the router doesn't have an svn revision, we can't assume that it
3257 * is "at least" any svn revision, so we need to return 0.
3258 * - If the target version doesn't have an svn revision, any svn revision
3259 * (or none at all) is good enough, so return 1.
3260 * - If both target and router have an svn revision, we compare them.
3263 return tor_version_compare(&router_version, &cutoff_version) >= 0;
3266 /** Parse a tor version from <b>s</b>, and store the result in <b>out</b>.
3267 * Return 0 on success, -1 on failure. */
3269 tor_version_parse(const char *s, tor_version_t *out)
3271 char *eos=NULL;
3272 const char *cp=NULL;
3273 /* Format is:
3274 * "Tor " ? NUM dot NUM dot NUM [ ( pre | rc | dot ) NUM [ - tag ] ]
3276 tor_assert(s);
3277 tor_assert(out);
3279 memset(out, 0, sizeof(tor_version_t));
3281 if (!strcasecmpstart(s, "Tor "))
3282 s += 4;
3284 /* Get major. */
3285 out->major = (int)strtol(s,&eos,10);
3286 if (!eos || eos==s || *eos != '.') return -1;
3287 cp = eos+1;
3289 /* Get minor */
3290 out->minor = (int) strtol(cp,&eos,10);
3291 if (!eos || eos==cp || *eos != '.') return -1;
3292 cp = eos+1;
3294 /* Get micro */
3295 out->micro = (int) strtol(cp,&eos,10);
3296 if (!eos || eos==cp) return -1;
3297 if (!*eos) {
3298 out->status = VER_RELEASE;
3299 out->patchlevel = 0;
3300 return 0;
3302 cp = eos;
3304 /* Get status */
3305 if (*cp == '.') {
3306 out->status = VER_RELEASE;
3307 ++cp;
3308 } else if (0==strncmp(cp, "pre", 3)) {
3309 out->status = VER_PRE;
3310 cp += 3;
3311 } else if (0==strncmp(cp, "rc", 2)) {
3312 out->status = VER_RC;
3313 cp += 2;
3314 } else {
3315 return -1;
3318 /* Get patchlevel */
3319 out->patchlevel = (int) strtol(cp,&eos,10);
3320 if (!eos || eos==cp) return -1;
3321 cp = eos;
3323 /* Get status tag. */
3324 if (*cp == '-' || *cp == '.')
3325 ++cp;
3326 eos = (char*) find_whitespace(cp);
3327 if (eos-cp >= (int)sizeof(out->status_tag))
3328 strlcpy(out->status_tag, cp, sizeof(out->status_tag));
3329 else {
3330 memcpy(out->status_tag, cp, eos-cp);
3331 out->status_tag[eos-cp] = 0;
3333 cp = eat_whitespace(eos);
3335 if (!strcmpstart(cp, "(r")) {
3336 cp += 2;
3337 out->svn_revision = (int) strtol(cp,&eos,10);
3340 return 0;
3343 /** Compare two tor versions; Return <0 if a < b; 0 if a ==b, >0 if a >
3344 * b. */
3346 tor_version_compare(tor_version_t *a, tor_version_t *b)
3348 int i;
3349 tor_assert(a);
3350 tor_assert(b);
3351 if ((i = a->major - b->major))
3352 return i;
3353 else if ((i = a->minor - b->minor))
3354 return i;
3355 else if ((i = a->micro - b->micro))
3356 return i;
3357 else if ((i = a->status - b->status))
3358 return i;
3359 else if ((i = a->patchlevel - b->patchlevel))
3360 return i;
3361 else if ((i = strcmp(a->status_tag, b->status_tag)))
3362 return i;
3363 else
3364 return a->svn_revision - b->svn_revision;
3367 /** Return true iff versions <b>a</b> and <b>b</b> belong to the same series.
3369 static int
3370 tor_version_same_series(tor_version_t *a, tor_version_t *b)
3372 tor_assert(a);
3373 tor_assert(b);
3374 return ((a->major == b->major) &&
3375 (a->minor == b->minor) &&
3376 (a->micro == b->micro));
3379 /** Helper: Given pointers to two strings describing tor versions, return -1
3380 * if _a precedes _b, 1 if _b preceeds _a, and 0 if they are equivalent.
3381 * Used to sort a list of versions. */
3382 static int
3383 _compare_tor_version_str_ptr(const void **_a, const void **_b)
3385 const char *a = *_a, *b = *_b;
3386 int ca, cb;
3387 tor_version_t va, vb;
3388 ca = tor_version_parse(a, &va);
3389 cb = tor_version_parse(b, &vb);
3390 /* If they both parse, compare them. */
3391 if (!ca && !cb)
3392 return tor_version_compare(&va,&vb);
3393 /* If one parses, it comes first. */
3394 if (!ca && cb)
3395 return -1;
3396 if (ca && !cb)
3397 return 1;
3398 /* If neither parses, compare strings. Also, the directory server admin
3399 ** needs to be smacked upside the head. But Tor is tolerant and gentle. */
3400 return strcmp(a,b);
3403 /** Sort a list of string-representations of versions in ascending order. */
3404 void
3405 sort_version_list(smartlist_t *versions, int remove_duplicates)
3407 smartlist_sort(versions, _compare_tor_version_str_ptr);
3409 if (remove_duplicates)
3410 smartlist_uniq(versions, _compare_tor_version_str_ptr, _tor_free);
3413 /** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>,
3414 * write the parsed descriptor to the newly allocated *<b>parsed_out</b>, the
3415 * binary descriptor ID of length DIGEST_LEN to <b>desc_id_out</b>, the
3416 * encrypted introduction points to the newly allocated
3417 * *<b>intro_points_encrypted_out</b>, their encrypted size to
3418 * *<b>intro_points_encrypted_size_out</b>, the size of the encoded descriptor
3419 * to *<b>encoded_size_out</b>, and a pointer to the possibly next
3420 * descriptor to *<b>next_out</b>; return 0 for success (including validation)
3421 * and -1 for failure.
3424 rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
3425 char *desc_id_out,
3426 char **intro_points_encrypted_out,
3427 size_t *intro_points_encrypted_size_out,
3428 size_t *encoded_size_out,
3429 const char **next_out, const char *desc)
3431 rend_service_descriptor_t *result =
3432 tor_malloc_zero(sizeof(rend_service_descriptor_t));
3433 char desc_hash[DIGEST_LEN];
3434 const char *eos;
3435 smartlist_t *tokens = smartlist_create();
3436 directory_token_t *tok;
3437 char secret_id_part[DIGEST_LEN];
3438 int i, version, num_ok=1;
3439 smartlist_t *versions;
3440 char public_key_hash[DIGEST_LEN];
3441 char test_desc_id[DIGEST_LEN];
3442 memarea_t *area = NULL;
3443 tor_assert(desc);
3444 /* Check if desc starts correctly. */
3445 if (strncmp(desc, "rendezvous-service-descriptor ",
3446 strlen("rendezvous-service-descriptor "))) {
3447 log_info(LD_REND, "Descriptor does not start correctly.");
3448 goto err;
3450 /* Compute descriptor hash for later validation. */
3451 if (router_get_hash_impl(desc, desc_hash,
3452 "rendezvous-service-descriptor ",
3453 "\nsignature", '\n') < 0) {
3454 log_warn(LD_REND, "Couldn't compute descriptor hash.");
3455 goto err;
3457 /* Determine end of string. */
3458 eos = strstr(desc, "\nrendezvous-service-descriptor ");
3459 if (!eos)
3460 eos = desc + strlen(desc);
3461 else
3462 eos = eos + 1;
3463 /* Tokenize descriptor. */
3464 area = memarea_new(4096);
3465 if (tokenize_string(area, desc, eos, tokens, desc_token_table, 0)) {
3466 log_warn(LD_REND, "Error tokenizing descriptor.");
3467 goto err;
3469 /* Set next to next descriptor, if available. */
3470 *next_out = eos;
3471 /* Set length of encoded descriptor. */
3472 *encoded_size_out = eos - desc;
3473 /* Check min allowed length of token list. */
3474 if (smartlist_len(tokens) < 7) {
3475 log_warn(LD_REND, "Impossibly short descriptor.");
3476 goto err;
3478 /* Parse base32-encoded descriptor ID. */
3479 tok = find_first_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR);
3480 tor_assert(tok);
3481 tor_assert(tok == smartlist_get(tokens, 0));
3482 tor_assert(tok->n_args == 1);
3483 if (strlen(tok->args[0]) != REND_DESC_ID_V2_LEN_BASE32 ||
3484 strspn(tok->args[0], BASE32_CHARS) != REND_DESC_ID_V2_LEN_BASE32) {
3485 log_warn(LD_REND, "Invalid descriptor ID: '%s'", tok->args[0]);
3486 goto err;
3488 if (base32_decode(desc_id_out, DIGEST_LEN,
3489 tok->args[0], REND_DESC_ID_V2_LEN_BASE32) < 0) {
3490 log_warn(LD_REND, "Descriptor ID contains illegal characters: %s",
3491 tok->args[0]);
3492 goto err;
3494 /* Parse descriptor version. */
3495 tok = find_first_by_keyword(tokens, R_VERSION);
3496 tor_assert(tok);
3497 tor_assert(tok->n_args == 1);
3498 result->version =
3499 (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL);
3500 if (result->version != 2 || !num_ok) {
3501 /* If it's <2, it shouldn't be under this format. If the number
3502 * is greater than 2, we bumped it because we broke backward
3503 * compatibility. See how version numbers in our other formats
3504 * work. */
3505 log_warn(LD_REND, "Unrecognized descriptor version: %s",
3506 escaped(tok->args[0]));
3507 goto err;
3509 /* Parse public key. */
3510 tok = find_first_by_keyword(tokens, R_PERMANENT_KEY);
3511 tor_assert(tok);
3512 result->pk = tok->key;
3513 tok->key = NULL; /* Prevent free */
3514 /* Parse secret ID part. */
3515 tok = find_first_by_keyword(tokens, R_SECRET_ID_PART);
3516 tor_assert(tok);
3517 tor_assert(tok->n_args == 1);
3518 if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 ||
3519 strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) {
3520 log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]);
3521 goto err;
3523 if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) < 0) {
3524 log_warn(LD_REND, "Secret ID part contains illegal characters: %s",
3525 tok->args[0]);
3526 goto err;
3528 /* Parse publication time -- up-to-date check is done when storing the
3529 * descriptor. */
3530 tok = find_first_by_keyword(tokens, R_PUBLICATION_TIME);
3531 tor_assert(tok);
3532 tor_assert(tok->n_args == 1);
3533 if (parse_iso_time(tok->args[0], &result->timestamp) < 0) {
3534 log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]);
3535 goto err;
3537 /* Parse protocol versions. */
3538 tok = find_first_by_keyword(tokens, R_PROTOCOL_VERSIONS);
3539 tor_assert(tok);
3540 tor_assert(tok->n_args == 1);
3541 versions = smartlist_create();
3542 smartlist_split_string(versions, tok->args[0], ",",
3543 SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
3544 for (i = 0; i < smartlist_len(versions); i++) {
3545 version = (int) tor_parse_long(smartlist_get(versions, i),
3546 10, 0, INT_MAX, &num_ok, NULL);
3547 if (!num_ok) /* It's a string; let's ignore it. */
3548 continue;
3549 result->protocols |= 1 << version;
3551 SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp));
3552 smartlist_free(versions);
3553 /* Parse encrypted introduction points. Don't verify. */
3554 tok = find_first_by_keyword(tokens, R_INTRODUCTION_POINTS);
3555 if (tok) {
3556 if (strcmp(tok->object_type, "MESSAGE")) {
3557 log_warn(LD_DIR, "Bad object type: introduction points should be of "
3558 "type MESSAGE");
3559 goto err;
3561 *intro_points_encrypted_out = tor_memdup(tok->object_body,
3562 tok->object_size);
3563 *intro_points_encrypted_size_out = tok->object_size;
3564 } else {
3565 *intro_points_encrypted_out = NULL;
3566 *intro_points_encrypted_size_out = 0;
3568 /* Parse and verify signature. */
3569 tok = find_first_by_keyword(tokens, R_SIGNATURE);
3570 tor_assert(tok);
3571 note_crypto_pk_op(VERIFY_RTR);
3572 if (check_signature_token(desc_hash, tok, result->pk, 0,
3573 "v2 rendezvous service descriptor") < 0)
3574 goto err;
3575 /* Verify that descriptor ID belongs to public key and secret ID part. */
3576 crypto_pk_get_digest(result->pk, public_key_hash);
3577 rend_get_descriptor_id_bytes(test_desc_id, public_key_hash,
3578 secret_id_part);
3579 if (memcmp(desc_id_out, test_desc_id, DIGEST_LEN)) {
3580 log_warn(LD_REND, "Parsed descriptor ID does not match "
3581 "computed descriptor ID.");
3582 goto err;
3584 goto done;
3585 err:
3586 if (result)
3587 rend_service_descriptor_free(result);
3588 result = NULL;
3589 done:
3590 if (tokens) {
3591 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
3592 smartlist_free(tokens);
3594 if (area)
3595 memarea_drop_all(area);
3596 *parsed_out = result;
3597 if (result)
3598 return 0;
3599 return -1;
3602 /** Decrypt and decode the introduction points in
3603 * <b>intro_points_encrypted</b> of length
3604 * <b>intro_points_encrypted_size</b> using <b>descriptor_cookie</b>
3605 * (which may also be <b>NULL</b> if no decryption, but only parsing is
3606 * required), parse the introduction points, and write the result to
3607 * <b>parsed</b>; return the number of successfully parsed introduction
3608 * points or -1 in case of a failure.
3611 rend_decrypt_introduction_points(rend_service_descriptor_t *parsed,
3612 const char *descriptor_cookie,
3613 const char *intro_points_encrypted,
3614 size_t intro_points_encrypted_size)
3616 char *ipos_decrypted = NULL;
3617 const char **current_ipo;
3618 smartlist_t *tokens;
3619 directory_token_t *tok;
3620 rend_intro_point_t *intro;
3621 extend_info_t *info;
3622 int result, num_ok=1;
3623 memarea_t *area = NULL;
3624 tor_assert(parsed);
3625 /** Function may only be invoked once. */
3626 tor_assert(!parsed->intro_nodes);
3627 tor_assert(intro_points_encrypted);
3628 tor_assert(intro_points_encrypted_size > 0);
3629 /* Decrypt introduction points, if required. */
3630 if (descriptor_cookie) {
3631 crypto_cipher_env_t *cipher;
3632 int unenclen;
3633 ipos_decrypted = tor_malloc_zero(intro_points_encrypted_size - 16);
3634 cipher = crypto_create_init_cipher(descriptor_cookie, 0);
3635 unenclen = crypto_cipher_decrypt_with_iv(cipher, ipos_decrypted,
3636 intro_points_encrypted_size - 16,
3637 intro_points_encrypted,
3638 intro_points_encrypted_size);
3639 crypto_free_cipher_env(cipher);
3640 if (unenclen < 0) {
3641 tor_free(ipos_decrypted);
3642 return -1;
3644 intro_points_encrypted = ipos_decrypted;
3645 intro_points_encrypted_size = unenclen;
3647 /* Consider one intro point after the other. */
3648 current_ipo = &intro_points_encrypted;
3649 tokens = smartlist_create();
3650 parsed->intro_nodes = smartlist_create();
3651 area = memarea_new(4096);
3652 while (!strcmpstart(*current_ipo, "introduction-point ")) {
3653 /* Determine end of string. */
3654 const char *eos = strstr(*current_ipo, "\nintroduction-point ");
3655 if (!eos)
3656 eos = *current_ipo+strlen(*current_ipo);
3657 else
3658 eos = eos+1;
3659 /* Free tokens and clear token list. */
3660 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
3661 smartlist_clear(tokens);
3662 memarea_clear(area);
3663 /* Tokenize string. */
3664 if (tokenize_string(area, *current_ipo, eos, tokens, ipo_token_table, 0)) {
3665 log_warn(LD_REND, "Error tokenizing introduction point.");
3666 goto err;
3668 /* Advance to next introduction point, if available. */
3669 *current_ipo = eos;
3670 /* Check minimum allowed length of introduction point. */
3671 if (smartlist_len(tokens) < 5) {
3672 log_warn(LD_REND, "Impossibly short introduction point.");
3673 goto err;
3675 /* Allocate new intro point and extend info. */
3676 intro = tor_malloc_zero(sizeof(rend_intro_point_t));
3677 info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
3678 /* Parse identifier. */
3679 tok = find_first_by_keyword(tokens, R_IPO_IDENTIFIER);
3680 tor_assert(tok);
3681 if (base32_decode(info->identity_digest, DIGEST_LEN,
3682 tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) {
3683 log_warn(LD_REND, "Identity digest contains illegal characters: %s",
3684 tok->args[0]);
3685 rend_intro_point_free(intro);
3686 goto err;
3688 /* Write identifier to nickname. */
3689 info->nickname[0] = '$';
3690 base16_encode(info->nickname + 1, sizeof(info->nickname) - 1,
3691 info->identity_digest, DIGEST_LEN);
3692 /* Parse IP address. */
3693 tok = find_first_by_keyword(tokens, R_IPO_IP_ADDRESS);
3694 if (tor_addr_from_str(&info->addr, tok->args[0])<0) {
3695 log_warn(LD_REND, "Could not parse introduction point address.");
3696 rend_intro_point_free(intro);
3697 goto err;
3699 if (tor_addr_family(&info->addr) != AF_INET) {
3700 log_warn(LD_REND, "Introduction point address was not ipv4.");
3701 rend_intro_point_free(intro);
3702 goto err;
3705 /* Parse onion port. */
3706 tok = find_first_by_keyword(tokens, R_IPO_ONION_PORT);
3707 info->port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535,
3708 &num_ok,NULL);
3709 if (!info->port || !num_ok) {
3710 log_warn(LD_REND, "Introduction point onion port %s is invalid",
3711 escaped(tok->args[0]));
3712 rend_intro_point_free(intro);
3713 goto err;
3715 /* Parse onion key. */
3716 tok = find_first_by_keyword(tokens, R_IPO_ONION_KEY);
3717 info->onion_key = tok->key;
3718 tok->key = NULL; /* Prevent free */
3719 /* Parse service key. */
3720 tok = find_first_by_keyword(tokens, R_IPO_SERVICE_KEY);
3721 intro->intro_key = tok->key;
3722 tok->key = NULL; /* Prevent free */
3723 /* Add extend info to list of introduction points. */
3724 smartlist_add(parsed->intro_nodes, intro);
3726 result = smartlist_len(parsed->intro_nodes);
3727 goto done;
3729 err:
3730 result = -1;
3732 done:
3733 /* Free tokens and clear token list. */
3734 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
3735 smartlist_free(tokens);
3736 if (area)
3737 memarea_drop_all(area);
3739 return result;
3742 /** Parse the content of a client_key file in <b>ckstr</b> and add
3743 * rend_authorized_client_t's for each parsed client to
3744 * <b>parsed_clients</b>. Return the number of parsed clients as result
3745 * or -1 for failure. */
3747 rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr)
3749 int result = -1;
3750 smartlist_t *tokens;
3751 directory_token_t *tok;
3752 const char *current_entry = NULL;
3753 memarea_t *area = NULL;
3754 if (!ckstr || strlen(ckstr) == 0)
3755 return -1;
3756 tokens = smartlist_create();
3757 /* Begin parsing with first entry, skipping comments or whitespace at the
3758 * beginning. */
3759 area = memarea_new(4096);
3760 current_entry = eat_whitespace(ckstr);
3761 while (!strcmpstart(current_entry, "client-name ")) {
3762 rend_authorized_client_t *parsed_entry;
3763 size_t len;
3764 char descriptor_cookie_base64[REND_DESC_COOKIE_LEN_BASE64+2+1];
3765 char descriptor_cookie_tmp[REND_DESC_COOKIE_LEN+2];
3766 /* Determine end of string. */
3767 const char *eos = strstr(current_entry, "\nclient-name ");
3768 if (!eos)
3769 eos = current_entry + strlen(current_entry);
3770 else
3771 eos = eos + 1;
3772 /* Free tokens and clear token list. */
3773 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
3774 smartlist_clear(tokens);
3775 memarea_clear(area);
3776 /* Tokenize string. */
3777 if (tokenize_string(area, current_entry, eos, tokens,
3778 client_keys_token_table, 0)) {
3779 log_warn(LD_REND, "Error tokenizing client keys file.");
3780 goto err;
3782 /* Advance to next entry, if available. */
3783 current_entry = eos;
3784 /* Check minimum allowed length of token list. */
3785 if (smartlist_len(tokens) < 2) {
3786 log_warn(LD_REND, "Impossibly short client key entry.");
3787 goto err;
3789 /* Parse client name. */
3790 tok = find_first_by_keyword(tokens, C_CLIENT_NAME);
3791 tor_assert(tok);
3792 tor_assert(tok == smartlist_get(tokens, 0));
3793 tor_assert(tok->n_args == 1);
3795 len = strlen(tok->args[0]);
3796 if (len < 1 || len > 19 ||
3797 strspn(tok->args[0], REND_LEGAL_CLIENTNAME_CHARACTERS) != len) {
3798 log_warn(LD_CONFIG, "Illegal client name: %s. (Length must be "
3799 "between 1 and 19, and valid characters are "
3800 "[A-Za-z0-9+-_].)", tok->args[0]);
3801 goto err;
3803 /* Check if client name is duplicate. */
3804 if (strmap_get(parsed_clients, tok->args[0])) {
3805 log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains a "
3806 "duplicate client name: '%s'. Ignoring.", tok->args[0]);
3807 goto err;
3809 parsed_entry = tor_malloc_zero(sizeof(rend_authorized_client_t));
3810 parsed_entry->client_name = tor_strdup(tok->args[0]);
3811 strmap_set(parsed_clients, parsed_entry->client_name, parsed_entry);
3812 /* Parse client key. */
3813 tok = find_first_by_keyword(tokens, C_CLIENT_KEY);
3814 if (tok) {
3815 parsed_entry->client_key = tok->key;
3816 tok->key = NULL; /* Prevent free */
3819 /* Parse descriptor cookie. */
3820 tok = find_first_by_keyword(tokens, C_DESCRIPTOR_COOKIE);
3821 tor_assert(tok);
3822 tor_assert(tok->n_args == 1);
3823 if (strlen(tok->args[0]) != REND_DESC_COOKIE_LEN_BASE64 + 2) {
3824 log_warn(LD_REND, "Descriptor cookie has illegal length: %s",
3825 escaped(tok->args[0]));
3826 goto err;
3828 /* The size of descriptor_cookie_tmp needs to be REND_DESC_COOKIE_LEN+2,
3829 * because a base64 encoding of length 24 does not fit into 16 bytes in all
3830 * cases. */
3831 if ((base64_decode(descriptor_cookie_tmp, REND_DESC_COOKIE_LEN+2,
3832 tok->args[0], REND_DESC_COOKIE_LEN_BASE64+2+1)
3833 != REND_DESC_COOKIE_LEN)) {
3834 log_warn(LD_REND, "Descriptor cookie contains illegal characters: "
3835 "%s", descriptor_cookie_base64);
3836 goto err;
3838 memcpy(parsed_entry->descriptor_cookie, descriptor_cookie_tmp,
3839 REND_DESC_COOKIE_LEN);
3841 result = strmap_size(parsed_clients);
3842 goto done;
3843 err:
3844 result = -1;
3845 done:
3846 /* Free tokens and clear token list. */
3847 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
3848 smartlist_free(tokens);
3849 if (area)
3850 memarea_drop_all(area);
3851 return result;