routerparse.c 118 KB
Newer Older
1
/* Copyright (c) 2001 Matej Pfajfar.
Roger Dingledine's avatar
Roger Dingledine committed
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
6
/* See LICENSE for licensing information */
/* $Id$ */
7
8
const char routerparse_c_id[] =
  "$Id$";
9
10
11
12
13
14
15

/**
 * \file routerparse.c
 * \brief Code to parse and validate router descriptors and directories.
 **/

#include "or.h"
16
#include "memarea.h"
17
18
19

/****************************************************************************/

20
21
22
/** Enumeration of possible token types.  The ones starting with K_ correspond
 * to directory 'keywords'. _ERR is an error in the tokenizing process, _EOF
 * is an end-of-file marker, and _NIL is used to encode not-a-token.
23
24
 */
typedef enum {
25
  K_ACCEPT = 0,
26
27
28
29
30
31
32
33
34
35
  K_DIRECTORY_SIGNATURE,
  K_RECOMMENDED_SOFTWARE,
  K_REJECT,
  K_ROUTER,
  K_SIGNED_DIRECTORY,
  K_SIGNING_KEY,
  K_ONION_KEY,
  K_ROUTER_SIGNATURE,
  K_PUBLISHED,
  K_RUNNING_ROUTERS,
36
  K_ROUTER_STATUS,
37
38
39
40
  K_PLATFORM,
  K_OPT,
  K_BANDWIDTH,
  K_PORTS,
41
  K_CONTACT,
42
  K_NETWORK_STATUS,
Nick Mathewson's avatar
Nick Mathewson committed
43
  K_UPTIME,
44
  K_DIR_SIGNING_KEY,
45
  K_FAMILY,
46
47
48
49
  K_FINGERPRINT,
  K_HIBERNATING,
  K_READ_HISTORY,
  K_WRITE_HISTORY,
50
51
52
53
54
55
56
  K_NETWORK_STATUS_VERSION,
  K_DIR_SOURCE,
  K_DIR_OPTIONS,
  K_CLIENT_VERSIONS,
  K_SERVER_VERSIONS,
  K_R,
  K_S,
57
  K_V,
58
  K_EVENTDNS,
59
60
61
  K_EXTRA_INFO,
  K_EXTRA_INFO_DIGEST,
  K_CACHES_EXTRA_INFO,
62
  K_HIDDEN_SERVICE_DIR,
63
64
65
66
67
68

  K_DIR_KEY_CERTIFICATE_VERSION,
  K_DIR_IDENTITY_KEY,
  K_DIR_KEY_PUBLISHED,
  K_DIR_KEY_EXPIRES,
  K_DIR_KEY_CERTIFICATION,
69
  K_DIR_ADDRESS,
70
71

  K_VOTE_STATUS,
72
73
  K_VALID_AFTER,
  K_FRESH_UNTIL,
74
  K_VALID_UNTIL,
75
76
  K_VOTING_DELAY,

77
78
79
  K_KNOWN_FLAGS,
  K_VOTE_DIGEST,
  K_CONSENSUS_DIGEST,
80
  K_CONSENSUS_METHODS,
81
  K_CONSENSUS_METHOD,
82

83
84
85
  A_PURPOSE,
  _A_UNKNOWN,

86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  R_RENDEZVOUS_SERVICE_DESCRIPTOR,
  R_VERSION,
  R_PERMANENT_KEY,
  R_SECRET_ID_PART,
  R_PUBLICATION_TIME,
  R_PROTOCOL_VERSIONS,
  R_INTRODUCTION_POINTS,
  R_SIGNATURE,

  R_IPO_IDENTIFIER,
  R_IPO_IP_ADDRESS,
  R_IPO_ONION_PORT,
  R_IPO_ONION_KEY,
  R_IPO_SERVICE_KEY,

101
102
103
104
105
106
  _UNRECOGNIZED,
  _ERR,
  _EOF,
  _NIL
} directory_keyword;

107
108
109
#define MIN_ANNOTATION A_PURPOSE
#define MAX_ANNOTATION _A_UNKNOWN

110
111
112
113
114
115
/** Structure to hold a single directory token.
 *
 * We parse a directory by breaking it into "tokens", each consisting
 * of a keyword, a line full of arguments, and a binary object.  The
 * arguments and object are both optional, depending on the keyword
 * type.
116
117
118
 *
 * This structure is only allocated in memareas; do not allocate it on
 * the heap, or token_free() won't work.
119
120
121
 */
typedef struct directory_token_t {
  directory_keyword tp;        /**< Type of the token. */
122
  int n_args:30;               /**< Number of elements in args */
123
  char **args;                 /**< Array of arguments from keyword line. */
124

125
  char *object_type;           /**< -----BEGIN [object_type]-----*/
126
  size_t object_size;          /**< Bytes in object_body */
127
  char *object_body;           /**< Contents of object, base64-decoded. */
128
129
130

  crypto_pk_env_t *key;        /**< For public keys only.  Heap-allocated. */

131
  char *error;                 /**< For _ERR tokens only. */
132
133
134
135
136
137
138
139
} directory_token_t;

/* ********************************************************************** */

/** We use a table of rules to decide how to parse each token type. */

/** Rules for whether the keyword needs an object. */
typedef enum {
140
141
142
143
144
  NO_OBJ,        /**< No object, ever. */
  NEED_OBJ,      /**< Object is required. */
  NEED_KEY_1024, /**< Object is required, and must be a 1024 bit public key */
  NEED_KEY,      /**< Object is required, and must be a public key. */
  OBJ_OK,        /**< Object is optional. */
145
146
} obj_syntax;

147
#define AT_START 1
148
#define AT_END 2
149
150

/** Determines the parsing rules for a single token type. */
151
typedef struct token_rule_t {
152
153
154
155
156
157
158
159
160
161
162
163
  /** The string value of the keyword identifying the type of item. */
  const char *t;
  /** The corresponding directory_keyword enum. */
  directory_keyword v;
  /** Minimum number of arguments for this item */
  int min_args;
  /** Maximum number of arguments for this item */
  int max_args;
  /** If true, we concatenate all arguments for this item into a single
   * string. */
  int concat_args;
  /** Requirments on object syntax for this item. */
164
  obj_syntax os;
165
166
167
168
169
170
171
  /** Lowest number of times this item may appear in a document. */
  int min_cnt;
  /** Highest number of times this item may appear in a document. */
  int max_cnt;
  /** One or more of AT_START/AT_END to limit where the item may appear in a
   * document. */
  int pos;
172
  /** True iff this token is an annotation. */
173
  int is_annotation;
174
175
} token_rule_t;

176
177
178
179
180
181
/*
 * Helper macros to define token tables.  's' is a string, 't' is a
 * directory_keyword, 'a' is a trio of argument multiplicities, and 'o' is an
 * object syntax.
 *
 */
182

183
/** Appears to indicate the end of a table. */
184
#define END_OF_TABLE { NULL, _NIL, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 }
185
/** An item with no restrictions: used for obsolete document types */
186
#define T(s,t,a,o)    { s, t, a, o, 0, INT_MAX, 0, 0 }
187
/** An item with no restrictions on multiplicity or location. */
188
#define T0N(s,t,a,o)  { s, t, a, o, 0, INT_MAX, 0, 0 }
189
/** An item that must appear exactly once */
190
#define T1(s,t,a,o)   { s, t, a, o, 1, 1, 0, 0 }
191
/** An item that must appear exactly once, at the start of the document */
192
#define T1_START(s,t,a,o)   { s, t, a, o, 1, 1, AT_START, 0 }
193
/** An item that must appear exactly once, at the end of the document */
194
#define T1_END(s,t,a,o)   { s, t, a, o, 1, 1, AT_END, 0 }
195
/** An item that must appear one or more times */
196
#define T1N(s,t,a,o)  { s, t, a, o, 1, INT_MAX, 0, 0 }
197
/** An item that must appear no more than once */
198
199
200
#define T01(s,t,a,o)  { s, t, a, o, 0, 1, 0, 0 }
/** An annotation that must appear no more than once */
#define A01(s,t,a,o)  { s, t, a, o, 0, 1, 0, 0 }
201
202

/* Argument multiplicity: any number of arguments. */
203
#define ARGS        0,INT_MAX,0
204
/* Argument multiplicity: no arguments. */
205
#define NO_ARGS     0,0,0
206
/* Argument multiplicity: concatenate all arguments. */
207
#define CONCAT_ARGS 1,1,1
208
/* Argument multiplicity: at least <b>n</b> arguments. */
209
#define GE(n)       n,INT_MAX,0
210
/* Argument multiplicity: exactly <b>n</b> arguments. */
211
212
#define EQ(n)       n,n,0

213
/** List of tokens allowable in router derscriptors */
214
215
static token_rule_t routerdesc_token_table[] = {
  T0N("reject",              K_REJECT,              ARGS,    NO_OBJ ),
216
  T0N("accept",              K_ACCEPT,              ARGS,    NO_OBJ ),
217
  T1_START( "router",              K_ROUTER,              GE(5),   NO_OBJ ),
218
219
  T1( "signing-key",         K_SIGNING_KEY,         NO_ARGS, NEED_KEY_1024 ),
  T1( "onion-key",           K_ONION_KEY,           NO_ARGS, NEED_KEY_1024 ),
220
  T1_END( "router-signature",    K_ROUTER_SIGNATURE,    NO_ARGS, NEED_OBJ ),
221
  T1( "published",           K_PUBLISHED,       CONCAT_ARGS, NO_OBJ ),
222
  T01("uptime",              K_UPTIME,              GE(1),   NO_OBJ ),
223
  T01("fingerprint",         K_FINGERPRINT,     CONCAT_ARGS, NO_OBJ ),
224
  T01("hibernating",         K_HIBERNATING,         GE(1),   NO_OBJ ),
225
226
  T01("platform",            K_PLATFORM,        CONCAT_ARGS, NO_OBJ ),
  T01("contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ ),
227
228
  T01("read-history",        K_READ_HISTORY,        ARGS,    NO_OBJ ),
  T01("write-history",       K_WRITE_HISTORY,       ARGS,    NO_OBJ ),
229
  T01("extra-info-digest",   K_EXTRA_INFO_DIGEST,   GE(1),   NO_OBJ ),
230
  T01("hidden-service-dir",  K_HIDDEN_SERVICE_DIR,  NO_ARGS, NO_OBJ ),
231
232

  T01("family",              K_FAMILY,              ARGS,    NO_OBJ ),
233
  T01("caches-extra-info",   K_CACHES_EXTRA_INFO,   NO_ARGS, NO_OBJ ),
234
235
236
  T01("eventdns",            K_EVENTDNS,            ARGS,    NO_OBJ ),

  T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
237
  T1( "bandwidth",           K_BANDWIDTH,           GE(3),   NO_OBJ ),
238
  A01("@purpose",            A_PURPOSE,             GE(1),   NO_OBJ ),
239
240
241
242

  END_OF_TABLE
};

243
/** List of tokens allowable in extra-info documents. */
244
static token_rule_t extrainfo_token_table[] = {
245
  T1_END( "router-signature",    K_ROUTER_SIGNATURE,    NO_ARGS, NEED_OBJ ),
246
247
248
249
  T1( "published",           K_PUBLISHED,       CONCAT_ARGS, NO_OBJ ),
  T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
  T01("read-history",        K_READ_HISTORY,        ARGS,    NO_OBJ ),
  T01("write-history",       K_WRITE_HISTORY,       ARGS,    NO_OBJ ),
250
  T1_START( "extra-info",          K_EXTRA_INFO,          GE(2),   NO_OBJ ),
251
252
253
254

  END_OF_TABLE
};

255
256
/** List of tokens allowable in the body part of v2 and v3 networkstatus
 * documents. */
257
static token_rule_t rtrstatus_token_table[] = {
Roger Dingledine's avatar
Roger Dingledine committed
258
  T1( "r",                   K_R,                   GE(8),   NO_OBJ ),
259
260
261
262
263
264
  T1( "s",                   K_S,                   ARGS,    NO_OBJ ),
  T01("v",                   K_V,               CONCAT_ARGS, NO_OBJ ),
  T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
  END_OF_TABLE
};

265
266
/** List of tokens allowable in the header part of v2 networkstatus documents.
 */
267
268
269
270
static token_rule_t netstatus_token_table[] = {
  T1( "published",           K_PUBLISHED,       CONCAT_ARGS, NO_OBJ ),
  T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
  T1( "contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ ),
271
  T1( "dir-signing-key",     K_DIR_SIGNING_KEY,  NO_ARGS,    NEED_KEY_1024 ),
272
  T1( "fingerprint",         K_FINGERPRINT,     CONCAT_ARGS, NO_OBJ ),
273
  T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
274
275
                                                    GE(1),   NO_OBJ ),
  T1( "dir-source",          K_DIR_SOURCE,          GE(3),   NO_OBJ ),
276
  T01("dir-options",         K_DIR_OPTIONS,         ARGS,    NO_OBJ ),
277
  T01("client-versions",     K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
Roger Dingledine's avatar
Roger Dingledine committed
278
  T01("server-versions",     K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
279
280
281
282

  END_OF_TABLE
};

283
284
/** List of tokens allowable in the footer of v1/v2 directory/networkstatus
 * footers. */
285
static token_rule_t dir_footer_token_table[] = {
286
  T1("directory-signature", K_DIRECTORY_SIGNATURE, EQ(1), NEED_OBJ ),
287
288
289
  END_OF_TABLE
};

290
/** List of tokens allowable in v1 directory headers/footers. */
291
292
293
294
static token_rule_t dir_token_table[] = {
  /* don't enforce counts; this is obsolete. */
  T( "network-status",      K_NETWORK_STATUS,      NO_ARGS, NO_OBJ ),
  T( "directory-signature", K_DIRECTORY_SIGNATURE, ARGS,    NEED_OBJ ),
295
  T( "recommended-software",K_RECOMMENDED_SOFTWARE,CONCAT_ARGS, NO_OBJ ),
296
297
298
299
  T( "signed-directory",    K_SIGNED_DIRECTORY,    NO_ARGS, NO_OBJ ),

  T( "running-routers",     K_RUNNING_ROUTERS,     ARGS,    NO_OBJ ),
  T( "router-status",       K_ROUTER_STATUS,       ARGS,    NO_OBJ ),
300
  T( "published",           K_PUBLISHED,       CONCAT_ARGS, NO_OBJ ),
301
302
303
304
305
306
  T( "opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
  T( "contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ ),
  T( "dir-signing-key",     K_DIR_SIGNING_KEY,     ARGS,    OBJ_OK ),
  T( "fingerprint",         K_FINGERPRINT,     CONCAT_ARGS, NO_OBJ ),

  END_OF_TABLE
307
308
};

309
310
#define CERTIFICATE_MEMBERS                                                  \
  T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION,           \
Roger Dingledine's avatar
Roger Dingledine committed
311
                                                     GE(1),       NO_OBJ ),  \
312
313
314
315
316
  T1("dir-identity-key", K_DIR_IDENTITY_KEY,         NO_ARGS,     NEED_KEY ),\
  T1("dir-key-published",K_DIR_KEY_PUBLISHED,        CONCAT_ARGS, NO_OBJ),   \
  T1("dir-key-expires",  K_DIR_KEY_EXPIRES,          CONCAT_ARGS, NO_OBJ),   \
  T1("dir-signing-key",  K_DIR_SIGNING_KEY,          NO_ARGS,     NEED_KEY ),\
  T1("dir-key-certification", K_DIR_KEY_CERTIFICATION,                       \
317
318
                                                     NO_ARGS,     NEED_OBJ), \
  T01("dir-address",     K_DIR_ADDRESS,              GE(1),       NO_OBJ),
319
320
321
322
323
324
325

static token_rule_t dir_key_certificate_table[] = {
  CERTIFICATE_MEMBERS
  T1("fingerprint",      K_FINGERPRINT,              CONCAT_ARGS, NO_OBJ ),
  END_OF_TABLE
};

326
327
/** List of tokens allowable in rendezvous service descriptors */
static token_rule_t desc_token_table[] = {
328
329
  T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR,
           EQ(1), NO_OBJ),
330
331
332
333
334
  T1("version", R_VERSION, EQ(1), NO_OBJ),
  T1("permanent-key", R_PERMANENT_KEY, NO_ARGS, NEED_KEY_1024),
  T1("secret-id-part", R_SECRET_ID_PART, EQ(1), NO_OBJ),
  T1("publication-time", R_PUBLICATION_TIME, CONCAT_ARGS, NO_OBJ),
  T1("protocol-versions", R_PROTOCOL_VERSIONS, EQ(1), NO_OBJ),
335
  T01("introduction-points", R_INTRODUCTION_POINTS, NO_ARGS, NEED_OBJ),
336
  T1_END("signature", R_SIGNATURE, NO_ARGS, NEED_OBJ),
337
338
339
340
341
342
  END_OF_TABLE
};

/** List of tokens allowed in the (encrypted) list of introduction points of
 * rendezvous service descriptors */
static token_rule_t ipo_token_table[] = {
343
  T1_START("introduction-point", R_IPO_IDENTIFIER, EQ(1), NO_OBJ),
344
345
346
347
348
349
350
  T1("ip-address", R_IPO_IP_ADDRESS, EQ(1), NO_OBJ),
  T1("onion-port", R_IPO_ONION_PORT, EQ(1), NO_OBJ),
  T1("onion-key", R_IPO_ONION_KEY, NO_ARGS, NEED_KEY_1024),
  T1("service-key", R_IPO_SERVICE_KEY, NO_ARGS, NEED_KEY_1024),
  END_OF_TABLE
};

351
static token_rule_t networkstatus_token_table[] = {
352
353
354
355
  T1("network-status-version", K_NETWORK_STATUS_VERSION,
                                                   GE(1),       NO_OBJ ),
  T1("vote-status",            K_VOTE_STATUS,      GE(1),       NO_OBJ ),
  T1("published",              K_PUBLISHED,        CONCAT_ARGS, NO_OBJ ),
356
357
  T1("valid-after",            K_VALID_AFTER,      CONCAT_ARGS, NO_OBJ ),
  T1("fresh-until",            K_FRESH_UNTIL,      CONCAT_ARGS, NO_OBJ ),
358
  T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
359
  T1("voting-delay",           K_VOTING_DELAY,     GE(2),       NO_OBJ ),
360
  T1("known-flags",            K_KNOWN_FLAGS,      ARGS,        NO_OBJ ),
361
362
363
364
365
366
  T( "fingerprint",            K_FINGERPRINT,      CONCAT_ARGS, NO_OBJ ),

  CERTIFICATE_MEMBERS

  T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
  T1( "contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ ),
367
  T1( "dir-source",          K_DIR_SOURCE,      GE(6),       NO_OBJ ),
368
369
370
  T1( "known-flags",         K_KNOWN_FLAGS,     CONCAT_ARGS, NO_OBJ ),
  T01("client-versions",     K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
  T01("server-versions",     K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
371
  T1( "consensus-methods",   K_CONSENSUS_METHODS, GE(1),     NO_OBJ ),
372
373
374

  END_OF_TABLE
};
375
static token_rule_t networkstatus_consensus_token_table[] = {
376
377
378
  T1("network-status-version", K_NETWORK_STATUS_VERSION,
                                                   GE(1),       NO_OBJ ),
  T1("vote-status",            K_VOTE_STATUS,      GE(1),       NO_OBJ ),
379
380
  T1("valid-after",            K_VALID_AFTER,      CONCAT_ARGS, NO_OBJ ),
  T1("fresh-until",            K_FRESH_UNTIL,      CONCAT_ARGS, NO_OBJ ),
381
  T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
382
  T1("voting-delay",           K_VOTING_DELAY,     GE(2),       NO_OBJ ),
383
384
385
386
387
388
389
390
391
392

  T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),

  T1N("dir-source",          K_DIR_SOURCE,          GE(3),   NO_OBJ ),
  T1N("contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ ),
  T1N("vote-digest",         K_VOTE_DIGEST,         GE(1),   NO_OBJ ),

  T1( "known-flags",         K_KNOWN_FLAGS,     CONCAT_ARGS, NO_OBJ ),

  T01("client-versions",     K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
393
394
  T01("server-versions",     K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
  T01("consensus-method",    K_CONSENSUS_METHOD,    EQ(1),   NO_OBJ),
395
396
397
398

  END_OF_TABLE
};

399
400
/** List of tokens allowable in the footer of v1/v2 directory/networkstatus
 * footers. */
401
static token_rule_t networkstatus_vote_footer_token_table[] = {
402
403
404
  T(  "directory-signature", K_DIRECTORY_SIGNATURE, GE(2),   NEED_OBJ ),
  END_OF_TABLE
};
405

406
407
408
409
410
static token_rule_t networkstatus_detached_signature_token_table[] = {
  T1_START("consensus-digest", K_CONSENSUS_DIGEST, GE(1),       NO_OBJ ),
  T1("valid-after",            K_VALID_AFTER,      CONCAT_ARGS, NO_OBJ ),
  T1("fresh-until",            K_FRESH_UNTIL,      CONCAT_ARGS, NO_OBJ ),
  T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
411
  T1N("directory-signature", K_DIRECTORY_SIGNATURE, GE(2),   NEED_OBJ ),
412
413
414
  END_OF_TABLE
};

415
416
#undef T

417
418
/* static function prototypes */
static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok);
419
static addr_policy_t *router_parse_addr_policy(directory_token_t *tok);
420
421
static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok);

422
static int router_get_hash_impl(const char *s, char *digest,
423
424
                                const char *start_str, const char *end_str,
                                char end_char);
425
426
427
428
static void token_free(directory_token_t *tok);
static smartlist_t *find_all_exitpolicy(smartlist_t *s);
static directory_token_t *find_first_by_keyword(smartlist_t *s,
                                                directory_keyword keyword);
429
430
431
#define TS_ANNOTATIONS_OK 1
#define TS_NOCHECK 2
#define TS_NO_NEW_ANNOTATIONS 4
432
433
static int tokenize_string(memarea_t *area,
                           const char *start, const char *end,
434
                           smartlist_t *out,
435
                           token_rule_t *table,
436
                           int flags);
437
438
static directory_token_t *get_next_token(memarea_t *area,
                                         const char **s,
439
                                         const char *eos,
440
441
442
443
444
445
                                         token_rule_t *table);
static int check_signature_token(const char *digest,
                                 directory_token_t *tok,
                                 crypto_pk_env_t *pkey,
                                 int check_authority,
                                 const char *doctype);
446
static crypto_pk_env_t *find_dir_signing_key(const char *str, const char *eos);
447
static int tor_version_same_series(tor_version_t *a, tor_version_t *b);
448

449
450
451
452
453
454
455
456
457
458
459
460
461
#undef DEBUG_AREA_ALLOC

#ifdef DEBUG_AREA_ALLOC
#define DUMP_AREA(a,name) STMT_BEGIN                              \
  size_t alloc=0, used=0;                                         \
  memarea_get_stats((a),&alloc,&used);                            \
  log_debug(LD_MM, "Area for %s has %lu allocated; using %lu.",   \
            name, (unsigned long)alloc, (unsigned long)used);     \
  STMT_END
#else
#define DUMP_AREA(a,name) STMT_NIL
#endif

462
/** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
463
 * <b>s</b>.  Return 0 on success, -1 on failure.
464
 */
465
466
int
router_get_dir_hash(const char *s, char *digest)
467
468
{
  return router_get_hash_impl(s,digest,
469
                              "signed-directory","\ndirectory-signature",'\n');
470
471
472
}

/** Set <b>digest</b> to the SHA-1 digest of the hash of the first router in
473
 * <b>s</b>. Return 0 on success, -1 on failure.
474
 */
475
476
int
router_get_router_hash(const char *s, char *digest)
477
478
{
  return router_get_hash_impl(s,digest,
479
                              "router ","\nrouter-signature", '\n');
480
481
}

Nick Mathewson's avatar
Nick Mathewson committed
482
/** Set <b>digest</b> to the SHA-1 digest of the hash of the running-routers
483
 * string in <b>s</b>. Return 0 on success, -1 on failure.
Nick Mathewson's avatar
Nick Mathewson committed
484
 */
485
486
int
router_get_runningrouters_hash(const char *s, char *digest)
487
488
{
  return router_get_hash_impl(s,digest,
489
                              "network-status","\ndirectory-signature", '\n');
490
491
}

492
493
/** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status
 * string in <b>s</b>.  Return 0 on success, -1 on failure. */
494
495
496
497
int
router_get_networkstatus_v2_hash(const char *s, char *digest)
{
  return router_get_hash_impl(s,digest,
498
499
500
501
502
503
504
505
506
507
508
509
                              "network-status-version","\ndirectory-signature",
                              '\n');
}

/** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status
 * string in <b>s</b>.  Return 0 on success, -1 on failure. */
int
router_get_networkstatus_v3_hash(const char *s, char *digest)
{
  return router_get_hash_impl(s,digest,
                              "network-status-version","\ndirectory-signature",
                              ' ');
510
511
}

512
513
/** Set <b>digest</b> to the SHA-1 digest of the hash of the extrainfo
 * string in <b>s</b>.  Return 0 on success, -1 on failure. */
514
515
516
int
router_get_extrainfo_hash(const char *s, char *digest)
{
517
  return router_get_hash_impl(s,digest,"extra-info","\nrouter-signature",'\n');
518
519
}

520
521
522
523
524
525
526
527
528
529
530
/** Helper: used to generate signatures for routers, directories and
 * network-status objects.  Given a digest in <b>digest</b> and a secret
 * <b>private_key</b>, generate an PKCS1-padded signature, BASE64-encode it,
 * surround it with -----BEGIN/END----- pairs, and write it to the
 * <b>buf_len</b>-byte buffer at <b>buf</b>.  Return 0 on success, -1 on
 * failure.
 */
int
router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
                               crypto_pk_env_t *private_key)
{
531
  char *signature;
532
  size_t i;
533

534
  signature = tor_malloc(crypto_pk_keysize(private_key));
535
536
  if (crypto_pk_private_sign(private_key, signature, digest, DIGEST_LEN) < 0) {

537
    log_warn(LD_BUG,"Couldn't sign digest.");
538
    goto err;
539
540
541
542
543
544
  }
  if (strlcat(buf, "-----BEGIN SIGNATURE-----\n", buf_len) >= buf_len)
    goto truncated;

  i = strlen(buf);
  if (base64_encode(buf+i, buf_len-i, signature, 128) < 0) {
545
    log_warn(LD_BUG,"couldn't base64-encode signature");
546
    goto err;
547
548
549
550
551
  }

  if (strlcat(buf, "-----END SIGNATURE-----\n", buf_len) >= buf_len)
    goto truncated;

552
  tor_free(signature);
553
  return 0;
554

555
 truncated:
556
  log_warn(LD_BUG,"tried to exceed string length.");
557
558
 err:
  tor_free(signature);
559
560
561
  return -1;
}

562
/** Return VS_RECOMMENDED if <b>myversion</b> is contained in
563
564
 * <b>versionlist</b>.  Else, return VS_EMPTY if versionlist has no
 * entries. Else, return VS_OLD if every member of
565
566
567
568
569
570
 * <b>versionlist</b> is newer than <b>myversion</b>.  Else, return
 * VS_NEW_IN_SERIES if there is at least one member of <b>versionlist</b> in
 * the same series (major.minor.micro) as <b>myversion</b>, but no such member
 * is newer than <b>myversion.</b>.  Else, return VS_NEW if every memeber of
 * <b>versionlist</b> is older than <b>myversion</b>.  Else, return
 * VS_UNRECOMMENDED.
571
 *
572
573
 * (versionlist is a comma-separated list of version strings,
 * optionally prefixed with "Tor".  Versions that can't be parsed are
574
 * ignored.)
575
 */
576
577
578
version_status_t
tor_version_is_obsolete(const char *myversion, const char *versionlist)
{
579
  tor_version_t mine, other;
580
581
582
  int found_newer = 0, found_older = 0, found_newer_in_series = 0,
    found_any_in_series = 0, r, same;
  version_status_t ret = VS_UNRECOMMENDED;
583
  smartlist_t *version_sl;
584

585
586
  log_debug(LD_CONFIG,"Checking whether version '%s' is in '%s'",
            myversion, versionlist);
587

588
  if (tor_version_parse(myversion, &mine)) {
589
    log_err(LD_BUG,"I couldn't parse my own version (%s)", myversion);
590
591
    tor_assert(0);
  }
592
593
  version_sl = smartlist_create();
  smartlist_split_string(version_sl, versionlist, ",", SPLIT_SKIP_SPACE, 0);
594

595
596
597
598
599
  if (!strlen(versionlist)) { /* no authorities cared or agreed */
    ret = VS_EMPTY;
    goto done;
  }

600
601
  SMARTLIST_FOREACH(version_sl, const char *, cp, {
    if (!strcmpstart(cp, "Tor "))
602
603
604
605
606
      cp += 4;

    if (tor_version_parse(cp, &other)) {
      /* Couldn't parse other; it can't be a match. */
    } else {
607
608
609
      same = tor_version_same_series(&mine, &other);
      if (same)
        found_any_in_series = 1;
610
611
      r = tor_version_compare(&mine, &other);
      if (r==0) {
612
        ret = VS_RECOMMENDED;
613
        goto done;
614
615
      } else if (r<0) {
        found_newer = 1;
616
617
        if (same)
          found_newer_in_series = 1;
618
619
      } else if (r>0) {
        found_older = 1;
620
621
      }
    }
622
623
  });

624
  /* We didn't find the listed version. Is it new or old? */
625
  if (found_any_in_series && !found_newer_in_series && found_newer) {
626
627
628
629
630
    ret = VS_NEW_IN_SERIES;
  } else if (found_newer && !found_older) {
    ret = VS_OLD;
  } else if (found_older && !found_newer) {
    ret = VS_NEW;
631
  } else {
632
    ret = VS_UNRECOMMENDED;
633
  }
634
635
636
637
638

 done:
  SMARTLIST_FOREACH(version_sl, char *, version, tor_free(version));
  smartlist_free(version_sl);
  return ret;
639
640
}

641
642
/** Read a signed directory from <b>str</b>.  If it's well-formed, return 0.
 * Otherwise, return -1.  If we're a directory cache, cache it.
643
 */
644
645
int
router_parse_directory(const char *str)
646
647
{
  directory_token_t *tok;
648
649
  char digest[DIGEST_LEN];
  time_t published_on;
650
  int r;
651
  const char *end, *cp;
652
  smartlist_t *tokens = NULL;
653
  crypto_pk_env_t *declared_key = NULL;
654
  memarea_t *area = memarea_new(8192);
655

656
657
  /* XXXX This could be simplified a lot, but it will all go away
   * once pre-0.1.1.8 is obsolete, and for now it's better not to
Roger Dingledine's avatar
Roger Dingledine committed
658
   * touch it. */
659

660
  if (router_get_dir_hash(str, digest)) {
661
    log_warn(LD_DIR, "Unable to compute digest of directory");
662
663
    goto err;
  }
664
  log_debug(LD_DIR,"Received directory hashes to %s",hex_str(digest,4));
665

666
667
668
669
670
  /* Check signature first, before we try to tokenize. */
  cp = str;
  while (cp && (end = strstr(cp+1, "\ndirectory-signature")))
    cp = end;
  if (cp == str || !cp) {
671
    log_warn(LD_DIR, "No signature found on directory."); goto err;
672
673
674
  }
  ++cp;
  tokens = smartlist_create();
675
  if (tokenize_string(area,cp,strchr(cp,'\0'),tokens,dir_token_table,0)) {
676
    log_warn(LD_DIR, "Error tokenizing directory signature"); goto err;
677
678
  }
  if (smartlist_len(tokens) != 1) {
679
    log_warn(LD_DIR, "Unexpected number of tokens in signature"); goto err;
680
  }
681
  tok=smartlist_get(tokens,0);
682
  if (tok->tp != K_DIRECTORY_SIGNATURE) {
683
    log_warn(LD_DIR,"Expected a single directory signature"); goto err;
684
  }
685
  declared_key = find_dir_signing_key(str, str+strlen(str));
686
  note_crypto_pk_op(VERIFY_DIR);
687
  if (check_signature_token(digest, tok, declared_key, 1, "directory")<0)
688
    goto err;
689

690
  SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
691
692
  smartlist_clear(tokens);
  memarea_clear(area);
693
694

  /* Now try to parse the first part of the directory. */
695
696
697
698
699
700
701
702
  if ((end = strstr(str,"\nrouter "))) {
    ++end;
  } else if ((end = strstr(str, "\ndirectory-signature"))) {
    ++end;
  } else {
    end = str + strlen(str);
  }

703
  if (tokenize_string(area,str,end,tokens,dir_token_table,0)) {
704
    log_warn(LD_DIR, "Error tokenizing directory"); goto err;
705
706
  }

707
708
  tok = find_first_by_keyword(tokens, K_PUBLISHED);
  tor_assert(tok);
709
710
  tor_assert(tok->n_args == 1);

711
  if (parse_iso_time(tok->args[0], &published_on) < 0) {
712
713
714
     goto err;
  }

715
716
  /* Now that we know the signature is okay, and we have a
   * publication time, cache the directory. */
717
  if (directory_caches_v1_dir_info(get_options()) &&
718
      !authdir_mode_v1(get_options()))
719
    dirserv_set_cached_directory(str, published_on, 0);
720

721
722
723
724
725
  r = 0;
  goto done;
 err:
  r = -1;
 done:
726
  if (declared_key) crypto_free_pk_env(declared_key);
727
  if (tokens) {
728
    SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
729
730
    smartlist_free(tokens);
  }
731
732
  if (area) {
    DUMP_AREA(area, "v1 directory");
733
    memarea_drop_all(area);
734
  }
735
736
737
  return r;
}

738
739
740
/** Read a signed router status statement from <b>str</b>.  If it's
 * well-formed, return 0.  Otherwise, return -1.  If we're a directory cache,
 * cache it.*/
741
742
int
router_parse_runningrouters(const char *str)
743
744
745
746
{
  char digest[DIGEST_LEN];
  directory_token_t *tok;
  time_t published_on;
747
  int r = -1;
748
  crypto_pk_env_t *declared_key = NULL;
749
  smartlist_t *tokens = NULL;
750
  const char *eos = str + strlen(str);
751
  memarea_t *area = NULL;
752
753

  if (router_get_runningrouters_hash(str, digest)) {
754
    log_warn(LD_DIR, "Unable to compute digest of running-routers");
755
756
    goto err;
  }
757
  area = memarea_new(8192);
758
  tokens = smartlist_create();
759
  if (tokenize_string(area,str,eos,tokens,dir_token_table,0)) {
760
    log_warn(LD_DIR, "Error tokenizing running-routers"); goto err;
761
762
763
  }
  tok = smartlist_get(tokens,0);
  if (tok->tp != K_NETWORK_STATUS) {
764
    log_warn(LD_DIR, "Network-status starts with wrong token");
765
766
767
    goto err;
  }

768
769
  tok = find_first_by_keyword(tokens, K_PUBLISHED);
  tor_assert(tok);
770
  tor_assert(tok->n_args == 1);
771
  if (parse_iso_time(tok->args[0], &published_on) < 0) {
772
773
774
     goto err;
  }
  if (!(tok = find_first_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) {
775
    log_warn(LD_DIR, "Missing signature on running-routers");
776
777
    goto err;
  }
778
  declared_key = find_dir_signing_key(str, eos);
779
  note_crypto_pk_op(VERIFY_DIR);
780
781
  if (check_signature_token(digest, tok, declared_key, 1, "running-routers")
      < 0)
782
783
    goto err;

784
785
  /* Now that we know the signature is okay, and we have a
   * publication time, cache the list. */
786
  if (get_options()->DirPort && !authdir_mode_v1(get_options()))
787
788
789
    dirserv_set_cached_directory(str, published_on, 1);

  r = 0;
790
 err:
791
  if (declared_key) crypto_free_pk_env(declared_key);
792
  if (tokens) {
793
    SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
794
795
    smartlist_free(tokens);
  }
796
797
  if (area) {
    DUMP_AREA(area, "v1 running-routers");
798
    memarea_drop_all(area);
799
  }
800
  return r;
801
802
}

803
804
805
/** Given a directory or running-routers string in <b>str</b>, try to
 * find the its dir-signing-key token (if any).  If this token is
 * present, extract and return the key.  Return NULL on failure. */
806
static crypto_pk_env_t *
807
find_dir_signing_key(const char *str, const char *eos)
808
809
810
811
{
  const char *cp;
  directory_token_t *tok;
  crypto_pk_env_t *key = NULL;
812
  memarea_t *area = NULL;
813
814
  tor_assert(str);
  tor_assert(eos);
815
816

  /* Is there a dir-signing-key in the directory? */
817
  cp = tor_memstr(str, eos-str, "\nopt dir-signing-key");
818
  if (!cp)
819
    cp = tor_memstr(str, eos-str, "\ndir-signing-key");
820
821
822
823
  if (!cp)
    return NULL;
  ++cp; /* Now cp points to the start of the token. */

824
825
  area = memarea_new(1024);
  tok = get_next_token(area, &cp, eos, dir_token_table);
826
  if (!tok) {
827
    log_warn(LD_DIR, "Unparseable dir-signing-key token");
828
    goto done;
829
830
  }
  if (tok->tp != K_DIR_SIGNING_KEY) {
831
    log_warn(LD_DIR, "Dir-signing-key token did not parse as expected");
832
    goto done;
833
834
835
836
837
838
  }

  if (tok->key) {
    key = tok->key;
    tok->key = NULL; /* steal reference. */
  } else {
839
    log_warn(LD_DIR, "Dir-signing-key token contained no key");
840
841
  }

842
843
 done:
  if (tok) token_free(tok);
844
845
846
847
  if (area) {
    DUMP_AREA(area, "dir-signing-key token");
    memarea_drop_all(area);
  }
848
849
850
851
852
  return key;
}

/** Return true iff <b>key</b> is allowed to sign directories.
 */
853
854
static int
dir_signing_key_is_trusted(crypto_pk_env_t *key)
855
856
857
858
{
  char digest[DIGEST_LEN];
  if (!key) return 0;
  if (crypto_pk_get_digest(key, digest) < 0) {
859
    log_warn(LD_DIR, "Error computing dir-signing-key digest");
860
861
    return 0;
  }
862
  if (!router_digest_is_trusted_dir(digest)) {
863
    log_warn(LD_DIR, "Listed dir-signing-key is not trusted");
864
865
866
867
868
    return 0;
  }
  return 1;
}

869
870
871
872
873
/** Check whether the object body of the token in <b>tok</b> has a good
 * signature for <b>digest</b> using key <b>pkey</b>.  If
 * <b>check_authority</b> is set, make sure that <b>pkey</b> is the key of a
 * directory authority.  Use <b>doctype</b> as the type of the document when
 * generating log messages.  Return 0 on success, negative on failure.
874
 */
875
static int
876
877
878
879
880
check_signature_token(const char *digest,
                      directory_token_t *tok,
                      crypto_pk_env_t *pkey,
                      int check_authority,
                      const char *doctype)
881
{
882
  char *signed_digest;
883

884
885
886
887
888
889
890
891
  tor_assert(pkey);
  tor_assert(tok);
  tor_assert(digest);
  tor_assert(doctype);

  if (check_authority && !dir_signing_key_is_trusted(pkey)) {
    log_warn(LD_DIR, "Key on %s did not come from an authority; rejecting",
             doctype);
892
    return -1;
893
  }
894

895
  if (strcmp(tok->object_type, "SIGNATURE")) {
896
    log_warn(LD_DIR, "Bad object type on %s signature", doctype);
897
    return -1;
898
  }
899

900
  signed_digest = tor_malloc(tok->object_size);
901
  if (crypto_pk_public_checksig(pkey, signed_digest, tok->object_body,
902
                                tok->object_size)
903
904
      != DIGEST_LEN) {
    log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype);
905
    tor_free(signed_digest);
906
907
    return -1;
  }
908
909
//  log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
//            hex_str(signed_digest,4));
910
  if (memcmp(digest, signed_digest, DIGEST_LEN)) {
911
    log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
912
    tor_free(signed_digest);
913
    return -1;
914
  }
915
  tor_free(signed_digest);
916
  return 0;
917
918
}

919
920
921
922
923
/** Helper: move *<b>s_ptr</b> ahead to the next router, the next extra-info,
 * or to the first of the annotations proceeding the next router or
 * extra-info---whichever comes first.  Set <b>is_extrainfo_out</b> to true if
 * we found an extrainfo, or false if found a router. Do not scan beyond
 * <b>eos</b>.  Return -1 if we found nothing; 0 if we found something. */
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
static int
find_start_of_next_router_or_extrainfo(const char **s_ptr,
                                       const char *eos,
                                       int *is_extrainfo_out)
{
  const char *annotations = NULL;
  const char *s = *s_ptr;

  s = eat_whitespace_eos(s, eos);

  while (s < eos-32) {  /* 32 gives enough room for a the first keyword. */
    /* We're at the start of a line. */
    tor_assert(*s != '\n');

    if (*s == '@' && !annotations) {
      annotations = s;
    } else if (*s == 'r' && !strcmpstart(s, "router ")) {
      *s_ptr = annotations ? annotations : s