routerparse.c 116 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

/** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
450
 * <b>s</b>.  Return 0 on success, -1 on failure.
451
 */
452
453
int
router_get_dir_hash(const char *s, char *digest)
454
455
{
  return router_get_hash_impl(s,digest,
456
                              "signed-directory","\ndirectory-signature",'\n');
457
458
459
}

/** Set <b>digest</b> to the SHA-1 digest of the hash of the first router in
460
 * <b>s</b>. Return 0 on success, -1 on failure.
461
 */
462
463
int
router_get_router_hash(const char *s, char *digest)
464
465
{
  return router_get_hash_impl(s,digest,
466
                              "router ","\nrouter-signature", '\n');
467
468
}

Nick Mathewson's avatar
Nick Mathewson committed
469
/** Set <b>digest</b> to the SHA-1 digest of the hash of the running-routers
470
 * string in <b>s</b>. Return 0 on success, -1 on failure.
Nick Mathewson's avatar
Nick Mathewson committed
471
 */
472
473
int
router_get_runningrouters_hash(const char *s, char *digest)
474
475
{
  return router_get_hash_impl(s,digest,
476
                              "network-status","\ndirectory-signature", '\n');
477
478
}

479
480
/** 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. */
481
482
483
484
int
router_get_networkstatus_v2_hash(const char *s, char *digest)
{
  return router_get_hash_impl(s,digest,
485
486
487
488
489
490
491
492
493
494
495
496
                              "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",
                              ' ');
497
498
}

499
500
/** 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. */
501
502
503
int
router_get_extrainfo_hash(const char *s, char *digest)
{
504
  return router_get_hash_impl(s,digest,"extra-info","\nrouter-signature",'\n');
505
506
}

507
508
509
510
511
512
513
514
515
516
517
/** 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)
{
518
  char *signature;
519
  size_t i;
520

521
  signature = tor_malloc(crypto_pk_keysize(private_key));
522
523
  if (crypto_pk_private_sign(private_key, signature, digest, DIGEST_LEN) < 0) {

524
    log_warn(LD_BUG,"Couldn't sign digest.");
525
    goto err;
526
527
528
529
530
531
  }
  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) {
532
    log_warn(LD_BUG,"couldn't base64-encode signature");
533
    goto err;
534
535
536
537
538
  }

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

539
  tor_free(signature);
540
  return 0;
541

542
 truncated:
543
  log_warn(LD_BUG,"tried to exceed string length.");
544
545
 err:
  tor_free(signature);
546
547
548
  return -1;
}

549
/** Return VS_RECOMMENDED if <b>myversion</b> is contained in
550
551
 * <b>versionlist</b>.  Else, return VS_EMPTY if versionlist has no
 * entries. Else, return VS_OLD if every member of
552
553
554
555
556
557
 * <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.
558
 *
559
560
 * (versionlist is a comma-separated list of version strings,
 * optionally prefixed with "Tor".  Versions that can't be parsed are
561
 * ignored.)
562
 */
563
564
565
version_status_t
tor_version_is_obsolete(const char *myversion, const char *versionlist)
{
566
  tor_version_t mine, other;
567
568
569
  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;
570
  smartlist_t *version_sl;
571

572
573
  log_debug(LD_CONFIG,"Checking whether version '%s' is in '%s'",
            myversion, versionlist);
574

575
  if (tor_version_parse(myversion, &mine)) {
576
    log_err(LD_BUG,"I couldn't parse my own version (%s)", myversion);
577
578
    tor_assert(0);
  }
579
580
  version_sl = smartlist_create();
  smartlist_split_string(version_sl, versionlist, ",", SPLIT_SKIP_SPACE, 0);
581

582
583
584
585
586
  if (!strlen(versionlist)) { /* no authorities cared or agreed */
    ret = VS_EMPTY;
    goto done;
  }

587
588
  SMARTLIST_FOREACH(version_sl, const char *, cp, {
    if (!strcmpstart(cp, "Tor "))
589
590
591
592
593
      cp += 4;

    if (tor_version_parse(cp, &other)) {
      /* Couldn't parse other; it can't be a match. */
    } else {
594
595
596
      same = tor_version_same_series(&mine, &other);
      if (same)
        found_any_in_series = 1;
597
598
      r = tor_version_compare(&mine, &other);
      if (r==0) {
599
        ret = VS_RECOMMENDED;
600
        goto done;
601
602
      } else if (r<0) {
        found_newer = 1;
603
604
        if (same)
          found_newer_in_series = 1;
605
606
      } else if (r>0) {
        found_older = 1;
607
608
      }
    }
609
610
  });

611
  /* We didn't find the listed version. Is it new or old? */
612
  if (found_any_in_series && !found_newer_in_series && found_newer) {
613
614
615
616
617
    ret = VS_NEW_IN_SERIES;
  } else if (found_newer && !found_older) {
    ret = VS_OLD;
  } else if (found_older && !found_newer) {
    ret = VS_NEW;
618
  } else {
619
    ret = VS_UNRECOMMENDED;
620
  }
621
622
623
624
625

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

628
629
/** 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.
630
 */
631
632
int
router_parse_directory(const char *str)
633
634
{
  directory_token_t *tok;
635
636
  char digest[DIGEST_LEN];
  time_t published_on;
637
  int r;
638
  const char *end, *cp;
639
  smartlist_t *tokens = NULL;
640
  crypto_pk_env_t *declared_key = NULL;
641
  memarea_t *area = memarea_new(8192);
642

643
644
  /* 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
645
   * touch it. */
646

647
  if (router_get_dir_hash(str, digest)) {
648
    log_warn(LD_DIR, "Unable to compute digest of directory");
649
650
    goto err;
  }
651
  log_debug(LD_DIR,"Received directory hashes to %s",hex_str(digest,4));
652

653
654
655
656
657
  /* Check signature first, before we try to tokenize. */
  cp = str;
  while (cp && (end = strstr(cp+1, "\ndirectory-signature")))
    cp = end;
  if (cp == str || !cp) {
658
    log_warn(LD_DIR, "No signature found on directory."); goto err;
659
660
661
  }
  ++cp;
  tokens = smartlist_create();
662
  if (tokenize_string(area,cp,strchr(cp,'\0'),tokens,dir_token_table,0)) {
663
    log_warn(LD_DIR, "Error tokenizing directory signature"); goto err;
664
665
  }
  if (smartlist_len(tokens) != 1) {
666
    log_warn(LD_DIR, "Unexpected number of tokens in signature"); goto err;
667
  }
668
  tok=smartlist_get(tokens,0);
669
  if (tok->tp != K_DIRECTORY_SIGNATURE) {
670
    log_warn(LD_DIR,"Expected a single directory signature"); goto err;
671
  }
672
  declared_key = find_dir_signing_key(str, str+strlen(str));
673
  note_crypto_pk_op(VERIFY_DIR);
674
  if (check_signature_token(digest, tok, declared_key, 1, "directory")<0)
675
    goto err;
676

677
  SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
678
679
  smartlist_clear(tokens);
  memarea_clear(area);
680
681

  /* Now try to parse the first part of the directory. */
682
683
684
685
686
687
688
689
  if ((end = strstr(str,"\nrouter "))) {
    ++end;
  } else if ((end = strstr(str, "\ndirectory-signature"))) {
    ++end;
  } else {
    end = str + strlen(str);
  }

690
  if (tokenize_string(area,str,end,tokens,dir_token_table,0)) {
691
    log_warn(LD_DIR, "Error tokenizing directory"); goto err;
692
693
  }

694
695
  tok = find_first_by_keyword(tokens, K_PUBLISHED);
  tor_assert(tok);
696
697
  tor_assert(tok->n_args == 1);

698
  if (parse_iso_time(tok->args[0], &published_on) < 0) {
699
700
701
     goto err;
  }

702
703
  /* Now that we know the signature is okay, and we have a
   * publication time, cache the directory. */
704
  if (directory_caches_v1_dir_info(get_options()) &&
705
      !authdir_mode_v1(get_options()))
706
    dirserv_set_cached_directory(str, published_on, 0);
707

708
709
710
711
712
  r = 0;
  goto done;
 err:
  r = -1;
 done:
713
  if (declared_key) crypto_free_pk_env(declared_key);
714
  if (tokens) {
715
    SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
716
717
    smartlist_free(tokens);
  }
718
719
  if (area)
    memarea_drop_all(area);
720
721
722
  return r;
}

723
724
725
/** 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.*/
726
727
int
router_parse_runningrouters(const char *str)
728
729
730
731
{
  char digest[DIGEST_LEN];
  directory_token_t *tok;
  time_t published_on;
732
  int r = -1;
733
  crypto_pk_env_t *declared_key = NULL;
734
  smartlist_t *tokens = NULL;
735
  const char *eos = str + strlen(str);
736
  memarea_t *area = NULL;
737
738

  if (router_get_runningrouters_hash(str, digest)) {
739
    log_warn(LD_DIR, "Unable to compute digest of running-routers");
740
741
    goto err;
  }
742
  area = memarea_new(8192);
743
  tokens = smartlist_create();
744
  if (tokenize_string(area,str,eos,tokens,dir_token_table,0)) {
745
    log_warn(LD_DIR, "Error tokenizing running-routers"); goto err;
746
747
748
  }
  tok = smartlist_get(tokens,0);
  if (tok->tp != K_NETWORK_STATUS) {
749
    log_warn(LD_DIR, "Network-status starts with wrong token");
750
751
752
    goto err;
  }

753
754
  tok = find_first_by_keyword(tokens, K_PUBLISHED);
  tor_assert(tok);
755
  tor_assert(tok->n_args == 1);
756
  if (parse_iso_time(tok->args[0], &published_on) < 0) {
757
758
759
     goto err;
  }
  if (!(tok = find_first_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) {
760
    log_warn(LD_DIR, "Missing signature on running-routers");
761
762
    goto err;
  }
763
  declared_key = find_dir_signing_key(str, eos);
764
  note_crypto_pk_op(VERIFY_DIR);
765
766
  if (check_signature_token(digest, tok, declared_key, 1, "running-routers")
      < 0)
767
768
    goto err;

769
770
  /* Now that we know the signature is okay, and we have a
   * publication time, cache the list. */
771
  if (get_options()->DirPort && !authdir_mode_v1(get_options()))
772
773
774
    dirserv_set_cached_directory(str, published_on, 1);

  r = 0;
775
 err:
776
  if (declared_key) crypto_free_pk_env(declared_key);
777
  if (tokens) {
778
    SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
779
780
    smartlist_free(tokens);
  }
781
782
  if (area)
    memarea_drop_all(area);
783
  return r;
784
785
}

786
787
788
/** 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. */
789
static crypto_pk_env_t *
790
find_dir_signing_key(const char *str, const char *eos)
791
792
793
794
{
  const char *cp;
  directory_token_t *tok;
  crypto_pk_env_t *key = NULL;
795
  memarea_t *area = NULL;
796
797
  tor_assert(str);
  tor_assert(eos);
798
799

  /* Is there a dir-signing-key in the directory? */
800
  cp = tor_memstr(str, eos-str, "\nopt dir-signing-key");
801
  if (!cp)
802
    cp = tor_memstr(str, eos-str, "\ndir-signing-key");
803
804
805
806
  if (!cp)
    return NULL;
  ++cp; /* Now cp points to the start of the token. */

807
808
  area = memarea_new(1024);
  tok = get_next_token(area, &cp, eos, dir_token_table);
809
  if (!tok) {
810
    log_warn(LD_DIR, "Unparseable dir-signing-key token");
811
    goto done;
812
813
  }
  if (tok->tp != K_DIR_SIGNING_KEY) {
814
    log_warn(LD_DIR, "Dir-signing-key token did not parse as expected");
815
    goto done;
816
817
818
819
820
821
  }

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

825
826
 done:
  if (tok) token_free(tok);
827
  if (area) memarea_drop_all(area);
828
829
830
831
832
  return key;
}

/** Return true iff <b>key</b> is allowed to sign directories.
 */
833
834
static int
dir_signing_key_is_trusted(crypto_pk_env_t *key)
835
836
837
838
{
  char digest[DIGEST_LEN];
  if (!key) return 0;
  if (crypto_pk_get_digest(key, digest) < 0) {
839
    log_warn(LD_DIR, "Error computing dir-signing-key digest");
840
841
    return 0;
  }
842
  if (!router_digest_is_trusted_dir(digest)) {
843
    log_warn(LD_DIR, "Listed dir-signing-key is not trusted");
844
845
846
847
848
    return 0;
  }
  return 1;
}

849
850
851
852
853
/** 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.
854
 */
855
static int
856
857
858
859
860
check_signature_token(const char *digest,
                      directory_token_t *tok,
                      crypto_pk_env_t *pkey,
                      int check_authority,
                      const char *doctype)
861
{
862
  char *signed_digest;
863

864
865
866
867
868
869
870
871
  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);
872
    return -1;
873
  }
874

875
  if (strcmp(tok->object_type, "SIGNATURE")) {
876
    log_warn(LD_DIR, "Bad object type on %s signature", doctype);
877
    return -1;
878
  }
879

880
  signed_digest = tor_malloc(tok->object_size);
881
  if (crypto_pk_public_checksig(pkey, signed_digest, tok->object_body,
882
                                tok->object_size)
883
884
      != DIGEST_LEN) {
    log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype);
885
    tor_free(signed_digest);
886
887
    return -1;
  }
888
889
//  log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
//            hex_str(signed_digest,4));
890
  if (memcmp(digest, signed_digest, DIGEST_LEN)) {
891
    log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
892
    tor_free(signed_digest);
893
    return -1;
894
  }
895
  tor_free(signed_digest);
896
  return 0;
897
898
}

899
900
901
902
903
/** 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. */
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
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;
      *is_extrainfo_out = 0;
      return 0;
    } else if (*s == 'e' && !strcmpstart(s, "extra-info ")) {
      *s_ptr = annotations ? annotations : s;
      *is_extrainfo_out = 1;
      return 0;
    }

    if (!(s = memchr(s+1, '\n', eos-(s+1))))
      break;
    s = eat_whitespace_eos(s, eos);
  }
  return -1;
}

937
/** Given a string *<b>s</b> containing a concatenated sequence of router
938
939
940
941
 * descriptors (or extra-info documents if <b>is_extrainfo</b> is set), parses
 * them and stores the result in <b>dest</b>.  All routers are marked running
 * and valid.  Advances *s to a point immediately following the last router
 * entry.  Ignore any trailing router entries that are not complete.
942
943
944
945
946
947
 *
 * If <b>saved_location</b> isn't SAVED_IN_CACHE, make a local copy of each
 * descriptor in the signed_descriptor_body field of each routerinfo_t.  If it
 * isn't SAVED_NOWHERE, remember the offset of each descriptor.
 *
 * Returns 0 on success and -1 on failure.
948
949
 */
int
950
951
router_parse_list_from_string(const char **s, const char *eos,
                              smartlist_t *dest,
952
                              saved_location_t saved_location,
953
                              int want_extrainfo,
954
955
                              int allow_annotations,
                              const char *prepend_annotations)