routerparse.c 115 KB
Newer Older
1
/* Copyright (c) 2001 Matej Pfajfar.
Roger Dingledine's avatar
Roger Dingledine committed
2
 * Copyright (c) 2001-2004, Roger Dingledine.
3
4
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
 * Copyright (c) 2007, 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
16
17
18

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

#include "or.h"

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

19
20
21
/** 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.
22
23
 */
typedef enum {
24
  K_ACCEPT = 0,
25
26
27
28
29
30
31
32
33
34
  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,
35
  K_ROUTER_STATUS,
36
37
38
39
  K_PLATFORM,
  K_OPT,
  K_BANDWIDTH,
  K_PORTS,
40
  K_CONTACT,
41
  K_NETWORK_STATUS,
Nick Mathewson's avatar
Nick Mathewson committed
42
  K_UPTIME,
43
  K_DIR_SIGNING_KEY,
44
  K_FAMILY,
45
46
47
48
  K_FINGERPRINT,
  K_HIBERNATING,
  K_READ_HISTORY,
  K_WRITE_HISTORY,
49
50
51
52
53
54
55
  K_NETWORK_STATUS_VERSION,
  K_DIR_SOURCE,
  K_DIR_OPTIONS,
  K_CLIENT_VERSIONS,
  K_SERVER_VERSIONS,
  K_R,
  K_S,
56
  K_V,
57
  K_EVENTDNS,
58
59
60
  K_EXTRA_INFO,
  K_EXTRA_INFO_DIGEST,
  K_CACHES_EXTRA_INFO,
61
  K_HIDDEN_SERVICE_DIR,
62
63
64
65
66
67

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

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

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

82
83
84
  A_PURPOSE,
  _A_UNKNOWN,

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  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,

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

106
107
108
#define MIN_ANNOTATION A_PURPOSE
#define MAX_ANNOTATION _A_UNKNOWN

109
110
111
112
113
114
115
116
117
118
119
120
/** 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.
 */
typedef struct directory_token_t {
  directory_keyword tp;        /**< Type of the token. */
  int n_args;                  /**< Number of elements in args */
  char **args;                 /**< Array of arguments from keyword line. */
  char *object_type;           /**< -----BEGIN [object_type]-----*/
121
  size_t object_size;          /**< Bytes in object_body */
122
123
  char *object_body;           /**< Contents of object, base64-decoded. */
  crypto_pk_env_t *key;        /**< For public keys only. */
124
  char *error;                 /**< For _ERR tokens only. */
125
126
127
128
129
130
131
132
} 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 {
133
134
135
136
137
  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. */
138
139
} obj_syntax;

140
#define AT_START 1
141
#define AT_END 2
142
143

/** Determines the parsing rules for a single token type. */
144
typedef struct token_rule_t {
145
146
147
148
149
150
151
152
153
154
155
156
  /** 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. */
157
  obj_syntax os;
158
159
160
161
162
163
164
  /** 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;
165
  /** True iff this token is an annotation. */
166
  int is_annotation;
167
168
} token_rule_t;

169
170
171
172
173
174
/*
 * 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.
 *
 */
175

176
/** Appears to indicate the end of a table. */
177
#define END_OF_TABLE { NULL, _NIL, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 }
178
/** An item with no restrictions: used for obsolete document types */
179
#define T(s,t,a,o)    { s, t, a, o, 0, INT_MAX, 0, 0 }
180
/** An item with no restrictions on multiplicity or location. */
181
#define T0N(s,t,a,o)  { s, t, a, o, 0, INT_MAX, 0, 0 }
182
/** An item that must appear exactly once */
183
#define T1(s,t,a,o)   { s, t, a, o, 1, 1, 0, 0 }
184
/** An item that must appear exactly once, at the start of the document */
185
#define T1_START(s,t,a,o)   { s, t, a, o, 1, 1, AT_START, 0 }
186
/** An item that must appear exactly once, at the end of the document */
187
#define T1_END(s,t,a,o)   { s, t, a, o, 1, 1, AT_END, 0 }
188
/** An item that must appear one or more times */
189
#define T1N(s,t,a,o)  { s, t, a, o, 1, INT_MAX, 0, 0 }
190
/** An item that must appear no more than once */
191
192
193
#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 }
194
195

/* Argument multiplicity: any number of arguments. */
196
#define ARGS        0,INT_MAX,0
197
/* Argument multiplicity: no arguments. */
198
#define NO_ARGS     0,0,0
199
/* Argument multiplicity: concatenate all arguments. */
200
#define CONCAT_ARGS 1,1,1
201
/* Argument multiplicity: at least <b>n</b> arguments. */
202
#define GE(n)       n,INT_MAX,0
203
/* Argument multiplicity: exactly <b>n</b> arguments. */
204
205
#define EQ(n)       n,n,0

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

  T01("family",              K_FAMILY,              ARGS,    NO_OBJ ),
226
  T01("caches-extra-info",   K_CACHES_EXTRA_INFO,   NO_ARGS, NO_OBJ ),
227
228
229
  T01("eventdns",            K_EVENTDNS,            ARGS,    NO_OBJ ),

  T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
230
  T1( "bandwidth",           K_BANDWIDTH,           GE(3),   NO_OBJ ),
231
  A01("@purpose",            A_PURPOSE,             GE(1),   NO_OBJ ),
232
233
234
235

  END_OF_TABLE
};

236
/** List of tokens allowable in extra-info documents. */
237
static token_rule_t extrainfo_token_table[] = {
238
  T1_END( "router-signature",    K_ROUTER_SIGNATURE,    NO_ARGS, NEED_OBJ ),
239
240
241
242
  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 ),
243
  T1_START( "extra-info",          K_EXTRA_INFO,          GE(2),   NO_OBJ ),
244
245
246
247

  END_OF_TABLE
};

248
249
/** List of tokens allowable in the body part of v2 and v3 networkstatus
 * documents. */
250
static token_rule_t rtrstatus_token_table[] = {
Roger Dingledine's avatar
Roger Dingledine committed
251
  T1( "r",                   K_R,                   GE(8),   NO_OBJ ),
252
253
254
255
256
257
  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
};

258
259
/** List of tokens allowable in the header part of v2 networkstatus documents.
 */
260
261
262
263
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 ),
264
  T1( "dir-signing-key",     K_DIR_SIGNING_KEY,  NO_ARGS,    NEED_KEY_1024 ),
265
  T1( "fingerprint",         K_FINGERPRINT,     CONCAT_ARGS, NO_OBJ ),
266
  T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
267
268
                                                    GE(1),   NO_OBJ ),
  T1( "dir-source",          K_DIR_SOURCE,          GE(3),   NO_OBJ ),
269
  T01("dir-options",         K_DIR_OPTIONS,         ARGS,    NO_OBJ ),
270
  T01("client-versions",     K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
Roger Dingledine's avatar
Roger Dingledine committed
271
  T01("server-versions",     K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
272
273
274
275

  END_OF_TABLE
};

276
277
/** List of tokens allowable in the footer of v1/v2 directory/networkstatus
 * footers. */
278
static token_rule_t dir_footer_token_table[] = {
279
  T1("directory-signature", K_DIRECTORY_SIGNATURE, EQ(1), NEED_OBJ ),
280
281
282
  END_OF_TABLE
};

283
/** List of tokens allowable in v1 diectory headers/footers. */
284
285
286
287
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 ),
288
  T( "recommended-software",K_RECOMMENDED_SOFTWARE,CONCAT_ARGS, NO_OBJ ),
289
290
291
292
  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 ),
293
  T( "published",           K_PUBLISHED,       CONCAT_ARGS, NO_OBJ ),
294
295
296
297
298
299
  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
300
301
};

302
303
#define CERTIFICATE_MEMBERS                                                  \
  T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION,           \
Roger Dingledine's avatar
Roger Dingledine committed
304
                                                     GE(1),       NO_OBJ ),  \
305
306
307
308
309
  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,                       \
310
311
                                                     NO_ARGS,     NEED_OBJ), \
  T01("dir-address",     K_DIR_ADDRESS,              GE(1),       NO_OBJ),
312
313
314
315
316
317
318

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

319
320
/** List of tokens allowable in rendezvous service descriptors */
static token_rule_t desc_token_table[] = {
321
322
  T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR,
           EQ(1), NO_OBJ),
323
324
325
326
327
  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),
328
  T01("introduction-points", R_INTRODUCTION_POINTS, NO_ARGS, NEED_OBJ),
329
  T1_END("signature", R_SIGNATURE, NO_ARGS, NEED_OBJ),
330
331
332
333
334
335
  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[] = {
336
  T1_START("introduction-point", R_IPO_IDENTIFIER, EQ(1), NO_OBJ),
337
338
339
340
341
342
343
  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
};

344
static token_rule_t networkstatus_vote_token_table[] = {
345
346
347
348
  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 ),
349
350
  T1("valid-after",            K_VALID_AFTER,      CONCAT_ARGS, NO_OBJ ),
  T1("fresh-until",            K_FRESH_UNTIL,      CONCAT_ARGS, NO_OBJ ),
351
  T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
352
  T1("voting-delay",           K_VOTING_DELAY,     GE(2),       NO_OBJ ),
353
  T1("known-flags",            K_KNOWN_FLAGS,      ARGS,        NO_OBJ ),
354
355
356
357
358
359
  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 ),
360
  T1( "dir-source",          K_DIR_SOURCE,      GE(6),       NO_OBJ ),
361
362
363
  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 ),
364
  T1( "consensus-methods",   K_CONSENSUS_METHODS, GE(1),     NO_OBJ ),
365
366
367

  END_OF_TABLE
};
368
static token_rule_t networkstatus_consensus_token_table[] = {
369
370
371
  T1("network-status-version", K_NETWORK_STATUS_VERSION,
                                                   GE(1),       NO_OBJ ),
  T1("vote-status",            K_VOTE_STATUS,      GE(1),       NO_OBJ ),
372
373
  T1("valid-after",            K_VALID_AFTER,      CONCAT_ARGS, NO_OBJ ),
  T1("fresh-until",            K_FRESH_UNTIL,      CONCAT_ARGS, NO_OBJ ),
374
  T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
375
  T1("voting-delay",           K_VOTING_DELAY,     GE(2),       NO_OBJ ),
376
377
378
379
380
381
382
383
384
385

  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 ),
386
387
  T01("server-versions",     K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
  T01("consensus-method",    K_CONSENSUS_METHOD,    EQ(1),   NO_OBJ),
388
389
390
391

  END_OF_TABLE
};

392
393
/** List of tokens allowable in the footer of v1/v2 directory/networkstatus
 * footers. */
394
static token_rule_t networkstatus_vote_footer_token_table[] = {
395
396
397
  T(  "directory-signature", K_DIRECTORY_SIGNATURE, GE(2),   NEED_OBJ ),
  END_OF_TABLE
};
398

399
400
401
402
403
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 ),
404
  T1N("directory-signature", K_DIRECTORY_SIGNATURE, GE(2),   NEED_OBJ ),
405
406
407
  END_OF_TABLE
};

408
409
#undef T

410
411
/* static function prototypes */
static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok);
412
static addr_policy_t *router_parse_addr_policy(directory_token_t *tok);
413
414
static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok);

415
static int router_get_hash_impl(const char *s, char *digest,
416
417
                                const char *start_str, const char *end_str,
                                char end_char);
418
419
420
421
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);
422
423
424
#define TS_ANNOTATIONS_OK 1
#define TS_NOCHECK 2
#define TS_NO_NEW_ANNOTATIONS 4
425
static int tokenize_string(const char *start, const char *end,
426
                           smartlist_t *out,
427
                           token_rule_t *table,
428
                           int flags);
429
static directory_token_t *get_next_token(const char **s,
430
                                         const char *eos,
431
432
433
434
435
436
                                         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);
437
static crypto_pk_env_t *find_dir_signing_key(const char *str, const char *eos);
438
static int tor_version_same_series(tor_version_t *a, tor_version_t *b);
439
440

/** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
441
 * <b>s</b>.  Return 0 on success, -1 on failure.
442
 */
443
444
int
router_get_dir_hash(const char *s, char *digest)
445
446
{
  return router_get_hash_impl(s,digest,
447
                              "signed-directory","\ndirectory-signature",'\n');
448
449
450
}

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

Nick Mathewson's avatar
Nick Mathewson committed
460
/** Set <b>digest</b> to the SHA-1 digest of the hash of the running-routers
461
 * string in <b>s</b>. Return 0 on success, -1 on failure.
Nick Mathewson's avatar
Nick Mathewson committed
462
 */
463
464
int
router_get_runningrouters_hash(const char *s, char *digest)
465
466
{
  return router_get_hash_impl(s,digest,
467
                              "network-status","\ndirectory-signature", '\n');
468
469
}

470
471
/** 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. */
472
473
474
475
int
router_get_networkstatus_v2_hash(const char *s, char *digest)
{
  return router_get_hash_impl(s,digest,
476
477
478
479
480
481
482
483
484
485
486
487
                              "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",
                              ' ');
488
489
}

490
491
/** 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. */
492
493
494
int
router_get_extrainfo_hash(const char *s, char *digest)
{
495
  return router_get_hash_impl(s,digest,"extra-info","\nrouter-signature",'\n');
496
497
}

498
499
500
501
502
503
504
505
506
507
508
/** 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)
{
509
  char *signature;
510
511
  int i;

512
  signature = tor_malloc(crypto_pk_keysize(private_key));
513
514
  if (crypto_pk_private_sign(private_key, signature, digest, DIGEST_LEN) < 0) {

515
    log_warn(LD_BUG,"Couldn't sign digest.");
516
    goto err;
517
518
519
520
521
522
  }
  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) {
523
    log_warn(LD_BUG,"couldn't base64-encode signature");
524
    tor_free(buf);
525
    goto err;
526
527
528
529
530
  }

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

531
  tor_free(signature);
532
  return 0;
533

534
 truncated:
535
  log_warn(LD_BUG,"tried to exceed string length.");
536
537
 err:
  tor_free(signature);
538
539
540
  return -1;
}

541
542
543
544
545
546
547
548
/** Return VS_RECOMMENDED if <b>myversion</b> is contained in
 * <b>versionlist</b>.  Else, return VS_OLD if every member of
 * <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.
549
 *
550
551
 * (versionlist is a comma-separated list of version strings,
 * optionally prefixed with "Tor".  Versions that can't be parsed are
552
 * ignored.)
553
 */
554
555
556
version_status_t
tor_version_is_obsolete(const char *myversion, const char *versionlist)
{
557
  tor_version_t mine, other;
558
559
560
  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;
561
  smartlist_t *version_sl;
562

563
564
  log_debug(LD_CONFIG,"Checking whether version '%s' is in '%s'",
            myversion, versionlist);
565

566
  if (tor_version_parse(myversion, &mine)) {
567
    log_err(LD_BUG,"I couldn't parse my own version (%s)", myversion);
568
569
    tor_assert(0);
  }
570
571
  version_sl = smartlist_create();
  smartlist_split_string(version_sl, versionlist, ",", SPLIT_SKIP_SPACE, 0);
572

573
574
  SMARTLIST_FOREACH(version_sl, const char *, cp, {
    if (!strcmpstart(cp, "Tor "))
575
576
577
578
579
      cp += 4;

    if (tor_version_parse(cp, &other)) {
      /* Couldn't parse other; it can't be a match. */
    } else {
580
581
582
      same = tor_version_same_series(&mine, &other);
      if (same)
        found_any_in_series = 1;
583
584
      r = tor_version_compare(&mine, &other);
      if (r==0) {
585
        ret = VS_RECOMMENDED;
586
        goto done;
587
588
      } else if (r<0) {
        found_newer = 1;
589
590
        if (same)
          found_newer_in_series = 1;
591
592
      } else if (r>0) {
        found_older = 1;
593
594
      }
    }
595
596
  });

597
  /* We didn't find the listed version. Is it new or old? */
598
  if (found_any_in_series && !found_newer_in_series && found_newer) {
599
600
601
602
603
    ret = VS_NEW_IN_SERIES;
  } else if (found_newer && !found_older) {
    ret = VS_OLD;
  } else if (found_older && !found_newer) {
    ret = VS_NEW;
604
  } else {
605
    ret = VS_UNRECOMMENDED;
606
  }
607
608
609
610
611

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

614
615
/** 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.
616
 */
617
618
int
router_parse_directory(const char *str)
619
620
{
  directory_token_t *tok;
621
622
  char digest[DIGEST_LEN];
  time_t published_on;
623
  int r;
624
  const char *end, *cp;
625
  smartlist_t *tokens = NULL;
626
  crypto_pk_env_t *declared_key = NULL;
627

628
629
  /* 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
630
   * touch it. */
631

632
  if (router_get_dir_hash(str, digest)) {
633
    log_warn(LD_DIR, "Unable to compute digest of directory");
634
635
    goto err;
  }
636
  log_debug(LD_DIR,"Received directory hashes to %s",hex_str(digest,4));
637

638
639
640
641
642
  /* Check signature first, before we try to tokenize. */
  cp = str;
  while (cp && (end = strstr(cp+1, "\ndirectory-signature")))
    cp = end;
  if (cp == str || !cp) {
643
    log_warn(LD_DIR, "No signature found on directory."); goto err;
644
645
646
  }
  ++cp;
  tokens = smartlist_create();
647
  if (tokenize_string(cp,strchr(cp,'\0'),tokens,dir_token_table,0)) {
648
    log_warn(LD_DIR, "Error tokenizing directory signature"); goto err;
649
650
  }
  if (smartlist_len(tokens) != 1) {
651
    log_warn(LD_DIR, "Unexpected number of tokens in signature"); goto err;
652
  }
653
  tok=smartlist_get(tokens,0);
654
  if (tok->tp != K_DIRECTORY_SIGNATURE) {
655
    log_warn(LD_DIR,"Expected a single directory signature"); goto err;
656
  }
657
  declared_key = find_dir_signing_key(str, str+strlen(str));
658
  note_crypto_pk_op(VERIFY_DIR);
659
  if (check_signature_token(digest, tok, declared_key, 1, "directory")<0)
660
    goto err;
661

662
  SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
663
664
665
666
  smartlist_free(tokens);
  tokens = NULL;

  /* Now try to parse the first part of the directory. */
667
668
669
670
671
672
673
674
675
  if ((end = strstr(str,"\nrouter "))) {
    ++end;
  } else if ((end = strstr(str, "\ndirectory-signature"))) {
    ++end;
  } else {
    end = str + strlen(str);
  }

  tokens = smartlist_create();
676
  if (tokenize_string(str,end,tokens,dir_token_table,0)) {
677
    log_warn(LD_DIR, "Error tokenizing directory"); goto err;
678
679
  }

680
681
  tok = find_first_by_keyword(tokens, K_PUBLISHED);
  tor_assert(tok);
682
683
  tor_assert(tok->n_args == 1);

684
  if (parse_iso_time(tok->args[0], &published_on) < 0) {
685
686
687
     goto err;
  }

688
689
  /* Now that we know the signature is okay, and we have a
   * publication time, cache the directory. */
690
691
  if (directory_caches_dir_info(get_options()) &&
      !authdir_mode_v1(get_options()))
692
    dirserv_set_cached_directory(str, published_on, 0);
693

694
695
696
697
698
  r = 0;
  goto done;
 err:
  r = -1;
 done:
699
  if (declared_key) crypto_free_pk_env(declared_key);
700
  if (tokens) {
701
    SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
702
703
704
705
706
    smartlist_free(tokens);
  }
  return r;
}

707
708
709
/** 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.*/
710
711
int
router_parse_runningrouters(const char *str)
712
713
714
715
{
  char digest[DIGEST_LEN];
  directory_token_t *tok;
  time_t published_on;
716
  int r = -1;
717
  crypto_pk_env_t *declared_key = NULL;
718
  smartlist_t *tokens = NULL;
719
  const char *eos = str + strlen(str);
720
721

  if (router_get_runningrouters_hash(str, digest)) {
722
    log_warn(LD_DIR, "Unable to compute digest of running-routers");
723
724
725
    goto err;
  }
  tokens = smartlist_create();
726
  if (tokenize_string(str,eos,tokens,dir_token_table,0)) {
727
    log_warn(LD_DIR, "Error tokenizing running-routers"); goto err;
728
729
730
  }
  tok = smartlist_get(tokens,0);
  if (tok->tp != K_NETWORK_STATUS) {
731
    log_warn(LD_DIR, "Network-status starts with wrong token");
732
733
734
    goto err;
  }

735
736
  tok = find_first_by_keyword(tokens, K_PUBLISHED);
  tor_assert(tok);
737
  tor_assert(tok->n_args == 1);
738
  if (parse_iso_time(tok->args[0], &published_on) < 0) {
739
740
741
     goto err;
  }
  if (!(tok = find_first_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) {
742
    log_warn(LD_DIR, "Missing signature on running-routers");
743
744
    goto err;
  }
745
  declared_key = find_dir_signing_key(str, eos);
746
  note_crypto_pk_op(VERIFY_DIR);
747
748
  if (check_signature_token(digest, tok, declared_key, 1, "running-routers")
      < 0)
749
750
    goto err;

751
752
  /* Now that we know the signature is okay, and we have a
   * publication time, cache the list. */
753
  if (get_options()->DirPort && !authdir_mode_v1(get_options()))
754
755
756
    dirserv_set_cached_directory(str, published_on, 1);

  r = 0;
757
 err:
758
  if (declared_key) crypto_free_pk_env(declared_key);
759
  if (tokens) {
760
    SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
761
762
    smartlist_free(tokens);
  }
763
  return r;
764
765
}

766
767
768
/** 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. */
769
static crypto_pk_env_t *
770
find_dir_signing_key(const char *str, const char *eos)
771
772
773
774
{
  const char *cp;
  directory_token_t *tok;
  crypto_pk_env_t *key = NULL;
775
776
  tor_assert(str);
  tor_assert(eos);
777
778

  /* Is there a dir-signing-key in the directory? */
779
  cp = tor_memstr(str, eos-str, "\nopt dir-signing-key");
780
  if (!cp)
781
    cp = tor_memstr(str, eos-str, "\ndir-signing-key");
782
783
784
785
  if (!cp)
    return NULL;
  ++cp; /* Now cp points to the start of the token. */

786
  tok = get_next_token(&cp, eos, dir_token_table);
787
  if (!tok) {
788
    log_warn(LD_DIR, "Unparseable dir-signing-key token");
789
790
791
    return NULL;
  }
  if (tok->tp != K_DIR_SIGNING_KEY) {
792
    log_warn(LD_DIR, "Dir-signing-key token did not parse as expected");
793
794
795
796
797
798
799
    return NULL;
  }

  if (tok->key) {
    key = tok->key;
    tok->key = NULL; /* steal reference. */
  } else {
800
    log_warn(LD_DIR, "Dir-signing-key token contained no key");
801
802
803
804
805
806
807
808
809
    return NULL;
  }

  token_free(tok);
  return key;
}

/** Return true iff <b>key</b> is allowed to sign directories.
 */
810
811
static int
dir_signing_key_is_trusted(crypto_pk_env_t *key)
812
813
814
815
{
  char digest[DIGEST_LEN];
  if (!key) return 0;
  if (crypto_pk_get_digest(key, digest) < 0) {
816
    log_warn(LD_DIR, "Error computing dir-signing-key digest");
817
818
    return 0;
  }
819
  if (!router_digest_is_trusted_dir(digest)) {
820
    log_warn(LD_DIR, "Listed dir-signing-key is not trusted");
821
822
823
824
825
    return 0;
  }
  return 1;
}

826
827
828
829
830
/** 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.
831
 */
832
static int
833
834
835
836
837
check_signature_token(const char *digest,
                      directory_token_t *tok,
                      crypto_pk_env_t *pkey,
                      int check_authority,
                      const char *doctype)
838
{
839
  char *signed_digest;
840

841
842
843
844
845
846
847
848
  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);
849
    return -1;
850
  }
851

852
  if (strcmp(tok->object_type, "SIGNATURE")) {
853
    log_warn(LD_DIR, "Bad object type on %s signature", doctype);
854
    return -1;
855
  }
856

857
  signed_digest = tor_malloc(tok->object_size);
858
  if (crypto_pk_public_checksig(pkey, signed_digest, tok->object_body,
859
                                tok->object_size)
860
861
      != DIGEST_LEN) {
    log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype);
862
    tor_free(signed_digest);
863
864
    return -1;
  }
865
  log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
866
            hex_str(signed_digest,4));
867
  if (memcmp(digest, signed_digest, DIGEST_LEN)) {
868
    log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
869
    tor_free(signed_digest);
870
    return -1;
871
  }
872
  tor_free(signed_digest);
873
  return 0;
874
875
}

876
877
878
879
880
/** 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. */
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
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;
}

914
/** Given a string *<b>s</b> containing a concatenated sequence of router
915
916
917
918
 * 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.
919
920
921
922
923
924
 *
 * 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.
925
926
 */
int
927
928
router_parse_list_from_string(const char **s, const char *eos,
                              smartlist_t *dest,
929
                              saved_location_t saved_location,
930
                              int want_extrainfo,
931
932
                              int allow_annotations,
                              const char *prepend_annotations)
933
934
{
  routerinfo_t *router;
935
936
937
  extrainfo_t *extrainfo;
  signed_descriptor_t *signed_desc;
  void *elt;
938
939
  const char *end, *start;
  int have_extrainfo;
940

941
942
  tor_assert(s);
  tor_assert(*s);
943
  tor_assert(dest);
944

945
  start = *s;
946
947
948
949
950
  if (!eos)
    eos = *s + strlen(*s);

  tor_assert(eos >= *s);

951
  while (1) {
952
    if (find_start_of_next_router_or_extrainfo(s, eos, &have_extrainfo) < 0)
953
954
955
      break;

    end = tor_memstr(*s, eos-*s, "\nrouter-signature");
956
    if (end)
957
      end = tor_memstr(end, eos-end, "\n-----END SIGNATURE-----\n");
958
959
    if (end)
      end += strlen("\n-----END SIGNATURE-----\n");
960

961
962
    if (!end)
      break;
963

964
965
    elt = NULL;

966
    if (have_extrainfo && want_extrainfo) {
967
968
969
      routerlist_t *rl = router_get_routerlist();
      extrainfo = extrainfo_parse_entry_from_string(*s, end,
                                       saved_location != SAVED_IN_CACHE,
970
                                       rl->identity_map);
971
972
973
974
      if (extrainfo) {
        signed_desc = &extrainfo->cache_info;
        elt = extrainfo;
      }