routerparse.c 217 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.
Nick Mathewson's avatar
Nick Mathewson committed
4
 * Copyright (c) 2007-2016, The Tor Project, Inc. */
5
6
7
8
/* See LICENSE for licensing information */

/**
 * \file routerparse.c
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
 * \brief Code to parse and validate router descriptors, consenus directories,
 *   and similar objects.
 *
 * The objects parsed by this module use a common text-based metaformat,
 * documented in dir-spec.txt in torspec.git.  This module is itself divided
 * into two major kinds of function: code to handle the metaformat, and code
 * to convert from particular instances of the metaformat into the
 * objects that Tor uses.
 *
 * The generic parsing code works by calling a table-based tokenizer on the
 * input string.  Each token corresponds to a single line with a token, plus
 * optional arguments on that line, plus an optional base-64 encoded object
 * after that line.  Each token has a definition in a table of token_rule_t
 * entries that describes how many arguments it can take, whether it takes an
 * object, how many times it may appear, whether it must appear first, and so
 * on.
 *
 * The tokenizer function tokenize_string() converts its string input into a
 * smartlist full of instances of directory_token_t, according to a provided
 * table of token_rule_t.
 *
 * The generic parts of this module additionally include functions for
 * finding the start and end of signed information inside a signed object, and
 * computing the digest that will be signed.
 *
 * There are also functions for saving objects to disk that have caused
 * parsing to fail.
 *
 * The specific parts of this module describe conversions between
 * particular lists of directory_token_t and particular objects.  The
 * kinds of objects that can be parsed here are:
 *  <ul>
 *  <li>router descriptors (managed from routerlist.c)
 *  <li>extra-info documents (managed from routerlist.c)
 *  <li>microdescriptors (managed from microdesc.c)
 *  <li>vote and consensus networkstatus documents, and the routerstatus_t
 *    objects that they comprise (managed from networkstatus.c)
 *  <li>detached-signature objects used by authorities for gathering
 *    signatures on the networkstatus consensus (managed from dirvote.c)
 *  <li>authority key certificates (managed from routerlist.c)
 *  <li>hidden service descriptors (managed from rendcommon.c and rendcache.c)
 * </ul>
 *
 * For no terribly good reason, the functions to <i>generate</i> signatures on
 * the above directory objects are also in this module.
54
55
 **/

56
57
#define ROUTERPARSE_PRIVATE

58
#include "or.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
59
#include "config.h"
60
#include "circuitstats.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
61
#include "dirserv.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
62
#include "dirvote.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
63
#include "policies.h"
64
#include "protover.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
65
#include "rendcommon.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
66
#include "router.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
67
#include "routerlist.h"
68
#include "memarea.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
69
#include "microdesc.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
70
#include "networkstatus.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
71
#include "rephist.h"
72
#include "routerkeys.h"
Sebastian Hahn's avatar
Sebastian Hahn committed
73
#include "routerparse.h"
74
#include "entrynodes.h"
75
#include "torcert.h"
76
#include "sandbox.h"
77
#include "shared_random.h"
78

79
80
#undef log
#include <math.h>
81
82
83

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

84
/** Enumeration of possible token types.  The ones starting with K_ correspond
85
86
87
 * to directory 'keywords'. A_ is for an annotation, R or C is related to
 * hidden services, ERR_ is an error in the tokenizing process, EOF_ is an
 * end-of-file marker, and NIL_ is used to encode not-a-token.
88
89
 */
typedef enum {
90
  K_ACCEPT = 0,
91
  K_ACCEPT6,
92
93
94
  K_DIRECTORY_SIGNATURE,
  K_RECOMMENDED_SOFTWARE,
  K_REJECT,
95
  K_REJECT6,
96
97
98
99
  K_ROUTER,
  K_SIGNED_DIRECTORY,
  K_SIGNING_KEY,
  K_ONION_KEY,
100
  K_ONION_KEY_NTOR,
101
102
103
  K_ROUTER_SIGNATURE,
  K_PUBLISHED,
  K_RUNNING_ROUTERS,
104
  K_ROUTER_STATUS,
105
  K_PLATFORM,
106
  K_PROTO,
107
108
  K_OPT,
  K_BANDWIDTH,
109
  K_CONTACT,
110
  K_NETWORK_STATUS,
Nick Mathewson's avatar
Nick Mathewson committed
111
  K_UPTIME,
112
  K_DIR_SIGNING_KEY,
113
  K_FAMILY,
114
115
116
117
  K_FINGERPRINT,
  K_HIBERNATING,
  K_READ_HISTORY,
  K_WRITE_HISTORY,
118
119
120
121
122
  K_NETWORK_STATUS_VERSION,
  K_DIR_SOURCE,
  K_DIR_OPTIONS,
  K_CLIENT_VERSIONS,
  K_SERVER_VERSIONS,
123
124
125
126
  K_RECOMMENDED_CLIENT_PROTOCOLS,
  K_RECOMMENDED_RELAY_PROTOCOLS,
  K_REQUIRED_CLIENT_PROTOCOLS,
  K_REQUIRED_RELAY_PROTOCOLS,
127
  K_OR_ADDRESS,
128
  K_ID,
129
  K_P,
130
  K_P6,
131
  K_R,
132
  K_A,
133
  K_S,
134
  K_V,
135
  K_W,
136
  K_M,
137
138
139
  K_EXTRA_INFO,
  K_EXTRA_INFO_DIGEST,
  K_CACHES_EXTRA_INFO,
140
  K_HIDDEN_SERVICE_DIR,
141
  K_ALLOW_SINGLE_HOP_EXITS,
142
  K_IPV6_POLICY,
143
144
  K_ROUTER_SIG_ED25519,
  K_IDENTITY_ED25519,
145
  K_MASTER_KEY_ED25519,
146
147
  K_ONION_KEY_CROSSCERT,
  K_NTOR_ONION_KEY_CROSSCERT,
148

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  K_DIRREQ_END,
  K_DIRREQ_V2_IPS,
  K_DIRREQ_V3_IPS,
  K_DIRREQ_V2_REQS,
  K_DIRREQ_V3_REQS,
  K_DIRREQ_V2_SHARE,
  K_DIRREQ_V3_SHARE,
  K_DIRREQ_V2_RESP,
  K_DIRREQ_V3_RESP,
  K_DIRREQ_V2_DIR,
  K_DIRREQ_V3_DIR,
  K_DIRREQ_V2_TUN,
  K_DIRREQ_V3_TUN,
  K_ENTRY_END,
  K_ENTRY_IPS,
  K_CELL_END,
  K_CELL_PROCESSED,
  K_CELL_QUEUED,
  K_CELL_TIME,
  K_CELL_CIRCS,
  K_EXIT_END,
  K_EXIT_WRITTEN,
  K_EXIT_READ,
  K_EXIT_OPENED,

174
175
176
177
178
  K_DIR_KEY_CERTIFICATE_VERSION,
  K_DIR_IDENTITY_KEY,
  K_DIR_KEY_PUBLISHED,
  K_DIR_KEY_EXPIRES,
  K_DIR_KEY_CERTIFICATION,
179
  K_DIR_KEY_CROSSCERT,
180
  K_DIR_ADDRESS,
181
  K_DIR_TUNNELLED,
182
183

  K_VOTE_STATUS,
184
185
  K_VALID_AFTER,
  K_FRESH_UNTIL,
186
  K_VALID_UNTIL,
187
188
  K_VOTING_DELAY,

189
  K_KNOWN_FLAGS,
190
  K_PARAMS,
191
  K_BW_WEIGHTS,
192
193
  K_VOTE_DIGEST,
  K_CONSENSUS_DIGEST,
194
195
  K_ADDITIONAL_DIGEST,
  K_ADDITIONAL_SIGNATURE,
196
  K_CONSENSUS_METHODS,
197
  K_CONSENSUS_METHOD,
198
  K_LEGACY_DIR_KEY,
199
  K_DIRECTORY_FOOTER,
200
201
202
203
204
  K_SIGNING_CERT_ED,
  K_SR_FLAG,
  K_COMMIT,
  K_PREVIOUS_SRV,
  K_CURRENT_SRV,
205
  K_PACKAGE,
206

207
  A_PURPOSE,
208
  A_LAST_LISTED,
209
  A_UNKNOWN_,
210

211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
  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,

226
227
228
229
  C_CLIENT_NAME,
  C_DESCRIPTOR_COOKIE,
  C_CLIENT_KEY,

230
231
232
  ERR_,
  EOF_,
  NIL_
233
234
} directory_keyword;

235
#define MIN_ANNOTATION A_PURPOSE
236
#define MAX_ANNOTATION A_UNKNOWN_
237

238
239
240
241
242
243
/** 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.
244
245
 *
 * This structure is only allocated in memareas; do not allocate it on
246
 * the heap, or token_clear() won't work.
247
248
249
 */
typedef struct directory_token_t {
  directory_keyword tp;        /**< Type of the token. */
250
  int n_args:30;               /**< Number of elements in args */
251
  char **args;                 /**< Array of arguments from keyword line. */
252

253
  char *object_type;           /**< -----BEGIN [object_type]-----*/
254
  size_t object_size;          /**< Bytes in object_body */
255
  char *object_body;           /**< Contents of object, base64-decoded. */
256

257
  crypto_pk_t *key;        /**< For public keys only.  Heap-allocated. */
258

259
  char *error;                 /**< For ERR_ tokens only. */
260
261
262
263
264
265
266
267
} 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 {
268
269
  NO_OBJ,        /**< No object, ever. */
  NEED_OBJ,      /**< Object is required. */
270
  NEED_SKEY_1024,/**< Object is required, and must be a 1024 bit private key */
271
272
273
  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. */
274
275
} obj_syntax;

276
#define AT_START 1
277
#define AT_END 2
278
279

/** Determines the parsing rules for a single token type. */
280
typedef struct token_rule_t {
281
282
283
284
285
286
287
288
289
290
291
  /** 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;
Nick Mathewson's avatar
Nick Mathewson committed
292
  /** Requirements on object syntax for this item. */
293
  obj_syntax os;
294
295
296
297
298
299
300
  /** 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;
301
  /** True iff this token is an annotation. */
302
  int is_annotation;
303
304
} token_rule_t;

305
306
307
/**
 * @name macros for defining token rules
 *
308
309
310
311
 * 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.
 */
312
/**@{*/
313

314
/** Appears to indicate the end of a table. */
315
#define END_OF_TABLE { NULL, NIL_, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 }
316
/** An item with no restrictions: used for obsolete document types */
317
#define T(s,t,a,o)    { s, t, a, o, 0, INT_MAX, 0, 0 }
318
/** An item with no restrictions on multiplicity or location. */
319
#define T0N(s,t,a,o)  { s, t, a, o, 0, INT_MAX, 0, 0 }
320
/** An item that must appear exactly once */
321
#define T1(s,t,a,o)   { s, t, a, o, 1, 1, 0, 0 }
322
/** An item that must appear exactly once, at the start of the document */
323
#define T1_START(s,t,a,o)   { s, t, a, o, 1, 1, AT_START, 0 }
324
/** An item that must appear exactly once, at the end of the document */
325
#define T1_END(s,t,a,o)   { s, t, a, o, 1, 1, AT_END, 0 }
326
/** An item that must appear one or more times */
327
#define T1N(s,t,a,o)  { s, t, a, o, 1, INT_MAX, 0, 0 }
328
/** An item that must appear no more than once */
329
330
#define T01(s,t,a,o)  { s, t, a, o, 0, 1, 0, 0 }
/** An annotation that must appear no more than once */
331
#define A01(s,t,a,o)  { s, t, a, o, 0, 1, 0, 1 }
332

333
/** Argument multiplicity: any number of arguments. */
334
#define ARGS        0,INT_MAX,0
335
/** Argument multiplicity: no arguments. */
336
#define NO_ARGS     0,0,0
337
/** Argument multiplicity: concatenate all arguments. */
338
#define CONCAT_ARGS 1,1,1
339
/** Argument multiplicity: at least <b>n</b> arguments. */
340
#define GE(n)       n,INT_MAX,0
341
/** Argument multiplicity: exactly <b>n</b> arguments. */
342
#define EQ(n)       n,n,0
343
/**@}*/
344

Nick Mathewson's avatar
Nick Mathewson committed
345
/** List of tokens recognized in router descriptors */
346
347
static token_rule_t routerdesc_token_table[] = {
  T0N("reject",              K_REJECT,              ARGS,    NO_OBJ ),
348
  T0N("accept",              K_ACCEPT,              ARGS,    NO_OBJ ),
349
350
  T0N("reject6",             K_REJECT6,             ARGS,    NO_OBJ ),
  T0N("accept6",             K_ACCEPT6,             ARGS,    NO_OBJ ),
351
  T1_START( "router",        K_ROUTER,              GE(5),   NO_OBJ ),
352
  T01("ipv6-policy",         K_IPV6_POLICY,         CONCAT_ARGS, NO_OBJ),
353
354
  T1( "signing-key",         K_SIGNING_KEY,         NO_ARGS, NEED_KEY_1024 ),
  T1( "onion-key",           K_ONION_KEY,           NO_ARGS, NEED_KEY_1024 ),
355
  T01("ntor-onion-key",      K_ONION_KEY_NTOR,      GE(1), NO_OBJ ),
356
  T1_END( "router-signature",    K_ROUTER_SIGNATURE,    NO_ARGS, NEED_OBJ ),
357
  T1( "published",           K_PUBLISHED,       CONCAT_ARGS, NO_OBJ ),
358
  T01("uptime",              K_UPTIME,              GE(1),   NO_OBJ ),
359
  T01("fingerprint",         K_FINGERPRINT,     CONCAT_ARGS, NO_OBJ ),
360
  T01("hibernating",         K_HIBERNATING,         GE(1),   NO_OBJ ),
361
  T01("platform",            K_PLATFORM,        CONCAT_ARGS, NO_OBJ ),
362
  T01("proto",               K_PROTO,           CONCAT_ARGS, NO_OBJ ),
363
  T01("contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ ),
364
365
  T01("read-history",        K_READ_HISTORY,        ARGS,    NO_OBJ ),
  T01("write-history",       K_WRITE_HISTORY,       ARGS,    NO_OBJ ),
366
  T01("extra-info-digest",   K_EXTRA_INFO_DIGEST,   GE(1),   NO_OBJ ),
367
  T01("hidden-service-dir",  K_HIDDEN_SERVICE_DIR,  NO_ARGS, NO_OBJ ),
368
  T01("identity-ed25519",    K_IDENTITY_ED25519,    NO_ARGS, NEED_OBJ ),
369
  T01("master-key-ed25519",  K_MASTER_KEY_ED25519,  GE(1),   NO_OBJ ),
370
  T01("router-sig-ed25519",  K_ROUTER_SIG_ED25519,  GE(1),   NO_OBJ ),
371
372
373
  T01("onion-key-crosscert", K_ONION_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ),
  T01("ntor-onion-key-crosscert", K_NTOR_ONION_KEY_CROSSCERT,
                                                    EQ(1),   NEED_OBJ ),
374

375
  T01("allow-single-hop-exits",K_ALLOW_SINGLE_HOP_EXITS,    NO_ARGS, NO_OBJ ),
376
377

  T01("family",              K_FAMILY,              ARGS,    NO_OBJ ),
378
  T01("caches-extra-info",   K_CACHES_EXTRA_INFO,   NO_ARGS, NO_OBJ ),
379
  T0N("or-address",          K_OR_ADDRESS,          GE(1),   NO_OBJ ),
380
381

  T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
382
  T1( "bandwidth",           K_BANDWIDTH,           GE(3),   NO_OBJ ),
383
  A01("@purpose",            A_PURPOSE,             GE(1),   NO_OBJ ),
384
  T01("tunnelled-dir-server",K_DIR_TUNNELLED,       NO_ARGS, NO_OBJ ),
385
386
387
388

  END_OF_TABLE
};

Nick Mathewson's avatar
Nick Mathewson committed
389
/** List of tokens recognized in extra-info documents. */
390
static token_rule_t extrainfo_token_table[] = {
391
  T1_END( "router-signature",    K_ROUTER_SIGNATURE,    NO_ARGS, NEED_OBJ ),
392
  T1( "published",           K_PUBLISHED,       CONCAT_ARGS, NO_OBJ ),
393
394
  T01("identity-ed25519",    K_IDENTITY_ED25519,    NO_ARGS, NEED_OBJ ),
  T01("router-sig-ed25519",  K_ROUTER_SIG_ED25519,  GE(1),   NO_OBJ ),
395
396
397
  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 ),
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
  T01("dirreq-stats-end",    K_DIRREQ_END,          ARGS,    NO_OBJ ),
  T01("dirreq-v2-ips",       K_DIRREQ_V2_IPS,       ARGS,    NO_OBJ ),
  T01("dirreq-v3-ips",       K_DIRREQ_V3_IPS,       ARGS,    NO_OBJ ),
  T01("dirreq-v2-reqs",      K_DIRREQ_V2_REQS,      ARGS,    NO_OBJ ),
  T01("dirreq-v3-reqs",      K_DIRREQ_V3_REQS,      ARGS,    NO_OBJ ),
  T01("dirreq-v2-share",     K_DIRREQ_V2_SHARE,     ARGS,    NO_OBJ ),
  T01("dirreq-v3-share",     K_DIRREQ_V3_SHARE,     ARGS,    NO_OBJ ),
  T01("dirreq-v2-resp",      K_DIRREQ_V2_RESP,      ARGS,    NO_OBJ ),
  T01("dirreq-v3-resp",      K_DIRREQ_V3_RESP,      ARGS,    NO_OBJ ),
  T01("dirreq-v2-direct-dl", K_DIRREQ_V2_DIR,       ARGS,    NO_OBJ ),
  T01("dirreq-v3-direct-dl", K_DIRREQ_V3_DIR,       ARGS,    NO_OBJ ),
  T01("dirreq-v2-tunneled-dl", K_DIRREQ_V2_TUN,     ARGS,    NO_OBJ ),
  T01("dirreq-v3-tunneled-dl", K_DIRREQ_V3_TUN,     ARGS,    NO_OBJ ),
  T01("entry-stats-end",     K_ENTRY_END,           ARGS,    NO_OBJ ),
  T01("entry-ips",           K_ENTRY_IPS,           ARGS,    NO_OBJ ),
  T01("cell-stats-end",      K_CELL_END,            ARGS,    NO_OBJ ),
  T01("cell-processed-cells", K_CELL_PROCESSED,     ARGS,    NO_OBJ ),
  T01("cell-queued-cells",   K_CELL_QUEUED,         ARGS,    NO_OBJ ),
  T01("cell-time-in-queue",  K_CELL_TIME,           ARGS,    NO_OBJ ),
  T01("cell-circuits-per-decile", K_CELL_CIRCS,     ARGS,    NO_OBJ ),
  T01("exit-stats-end",      K_EXIT_END,            ARGS,    NO_OBJ ),
  T01("exit-kibibytes-written", K_EXIT_WRITTEN,     ARGS,    NO_OBJ ),
  T01("exit-kibibytes-read", K_EXIT_READ,           ARGS,    NO_OBJ ),
  T01("exit-streams-opened", K_EXIT_OPENED,         ARGS,    NO_OBJ ),

423
  T1_START( "extra-info",          K_EXTRA_INFO,          GE(2),   NO_OBJ ),
424
425
426
427

  END_OF_TABLE
};

428
/** List of tokens recognized in the body part of v3 networkstatus
429
 * documents. */
430
static token_rule_t rtrstatus_token_table[] = {
431
  T01("p",                   K_P,               CONCAT_ARGS, NO_OBJ ),
432
  T1( "r",                   K_R,                   GE(7),   NO_OBJ ),
433
  T0N("a",                   K_A,                   GE(1),   NO_OBJ ),
434
435
  T1( "s",                   K_S,                   ARGS,    NO_OBJ ),
  T01("v",                   K_V,               CONCAT_ARGS, NO_OBJ ),
436
  T01("w",                   K_W,                   ARGS,    NO_OBJ ),
437
  T0N("m",                   K_M,               CONCAT_ARGS, NO_OBJ ),
438
  T0N("id",                  K_ID,                  GE(2),   NO_OBJ ),
439
  T01("pr",                  K_PROTO,           CONCAT_ARGS, NO_OBJ ),
440
441
442
443
  T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
  END_OF_TABLE
};

444
/** List of tokens common to V3 authority certificates and V3 consensuses. */
445
446
#define CERTIFICATE_MEMBERS                                                  \
  T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION,           \
Roger Dingledine's avatar
Roger Dingledine committed
447
                                                     GE(1),       NO_OBJ ),  \
448
449
450
451
  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 ),\
452
  T1("dir-key-crosscert", K_DIR_KEY_CROSSCERT,       NO_ARGS,     NEED_OBJ ),\
453
  T1("dir-key-certification", K_DIR_KEY_CERTIFICATION,                       \
454
455
                                                     NO_ARGS,     NEED_OBJ), \
  T01("dir-address",     K_DIR_ADDRESS,              GE(1),       NO_OBJ),
456

Nick Mathewson's avatar
Nick Mathewson committed
457
/** List of tokens recognized in V3 authority certificates. */
458
459
460
461
462
463
static token_rule_t dir_key_certificate_table[] = {
  CERTIFICATE_MEMBERS
  T1("fingerprint",      K_FINGERPRINT,              CONCAT_ARGS, NO_OBJ ),
  END_OF_TABLE
};

Nick Mathewson's avatar
Nick Mathewson committed
464
/** List of tokens recognized in rendezvous service descriptors */
465
static token_rule_t desc_token_table[] = {
466
467
  T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR,
           EQ(1), NO_OBJ),
468
469
470
471
472
  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),
473
  T01("introduction-points", R_INTRODUCTION_POINTS, NO_ARGS, NEED_OBJ),
474
  T1_END("signature", R_SIGNATURE, NO_ARGS, NEED_OBJ),
475
476
477
  END_OF_TABLE
};

Nick Mathewson's avatar
Nick Mathewson committed
478
/** List of tokens recognized in the (encrypted) list of introduction points of
479
480
 * rendezvous service descriptors */
static token_rule_t ipo_token_table[] = {
481
  T1_START("introduction-point", R_IPO_IDENTIFIER, EQ(1), NO_OBJ),
482
483
484
485
486
487
488
  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
};

Nick Mathewson's avatar
Nick Mathewson committed
489
/** List of tokens recognized in the (possibly encrypted) list of introduction
490
491
492
493
494
495
496
497
 * points of rendezvous service descriptors */
static token_rule_t client_keys_token_table[] = {
  T1_START("client-name", C_CLIENT_NAME, CONCAT_ARGS, NO_OBJ),
  T1("descriptor-cookie", C_DESCRIPTOR_COOKIE, EQ(1), NO_OBJ),
  T01("client-key", C_CLIENT_KEY, NO_ARGS, NEED_SKEY_1024),
  END_OF_TABLE
};

Nick Mathewson's avatar
Nick Mathewson committed
498
/** List of tokens recognized in V3 networkstatus votes. */
499
static token_rule_t networkstatus_token_table[] = {
500
  T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
501
502
503
                                                   GE(1),       NO_OBJ ),
  T1("vote-status",            K_VOTE_STATUS,      GE(1),       NO_OBJ ),
  T1("published",              K_PUBLISHED,        CONCAT_ARGS, NO_OBJ ),
504
505
  T1("valid-after",            K_VALID_AFTER,      CONCAT_ARGS, NO_OBJ ),
  T1("fresh-until",            K_FRESH_UNTIL,      CONCAT_ARGS, NO_OBJ ),
506
  T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
507
  T1("voting-delay",           K_VOTING_DELAY,     GE(2),       NO_OBJ ),
508
  T1("known-flags",            K_KNOWN_FLAGS,      ARGS,        NO_OBJ ),
509
  T01("params",                K_PARAMS,           ARGS,        NO_OBJ ),
510
  T( "fingerprint",            K_FINGERPRINT,      CONCAT_ARGS, NO_OBJ ),
511
512
513
514
515
  T01("signing-ed25519",       K_SIGNING_CERT_ED,  NO_ARGS ,    NEED_OBJ ),
  T01("shared-rand-participate",K_SR_FLAG,         NO_ARGS,     NO_OBJ ),
  T0N("shared-rand-commit",    K_COMMIT,           GE(3),       NO_OBJ ),
  T01("shared-rand-previous-value", K_PREVIOUS_SRV,EQ(2),       NO_OBJ ),
  T01("shared-rand-current-value",  K_CURRENT_SRV, EQ(2),       NO_OBJ ),
516
  T0N("package",               K_PACKAGE,          CONCAT_ARGS, NO_OBJ ),
517
518
519
520
521
522
523
524
  T01("recommended-client-protocols", K_RECOMMENDED_CLIENT_PROTOCOLS,
      CONCAT_ARGS, NO_OBJ ),
  T01("recommended-relay-protocols", K_RECOMMENDED_RELAY_PROTOCOLS,
      CONCAT_ARGS, NO_OBJ ),
  T01("required-client-protocols",    K_REQUIRED_CLIENT_PROTOCOLS,
      CONCAT_ARGS, NO_OBJ ),
  T01("required-relay-protocols",    K_REQUIRED_RELAY_PROTOCOLS,
      CONCAT_ARGS, NO_OBJ ),
525
526
527
528
529

  CERTIFICATE_MEMBERS

  T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
  T1( "contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ ),
530
  T1( "dir-source",          K_DIR_SOURCE,      GE(6),       NO_OBJ ),
531
  T01("legacy-dir-key",      K_LEGACY_DIR_KEY,  GE(1),       NO_OBJ ),
532
533
534
  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 ),
535
  T1( "consensus-methods",   K_CONSENSUS_METHODS, GE(1),     NO_OBJ ),
536
537
538

  END_OF_TABLE
};
539

Nick Mathewson's avatar
Nick Mathewson committed
540
/** List of tokens recognized in V3 networkstatus consensuses. */
541
static token_rule_t networkstatus_consensus_token_table[] = {
542
  T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
543
544
                                                   GE(1),       NO_OBJ ),
  T1("vote-status",            K_VOTE_STATUS,      GE(1),       NO_OBJ ),
545
546
  T1("valid-after",            K_VALID_AFTER,      CONCAT_ARGS, NO_OBJ ),
  T1("fresh-until",            K_FRESH_UNTIL,      CONCAT_ARGS, NO_OBJ ),
547
  T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
548
  T1("voting-delay",           K_VOTING_DELAY,     GE(2),       NO_OBJ ),
549
550
551

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

552
  T1N("dir-source",          K_DIR_SOURCE,          GE(6),   NO_OBJ ),
553
554
555
556
557
558
  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 ),
559
560
  T01("server-versions",     K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
  T01("consensus-method",    K_CONSENSUS_METHOD,    EQ(1),   NO_OBJ),
561
  T01("params",                K_PARAMS,           ARGS,        NO_OBJ ),
562

563
564
565
  T01("shared-rand-previous-value", K_PREVIOUS_SRV, EQ(2),   NO_OBJ ),
  T01("shared-rand-current-value",  K_CURRENT_SRV,  EQ(2),   NO_OBJ ),

566
567
568
569
570
571
572
573
574
  T01("recommended-client-protocols", K_RECOMMENDED_CLIENT_PROTOCOLS,
      CONCAT_ARGS, NO_OBJ ),
  T01("recommended-relay-protocols", K_RECOMMENDED_RELAY_PROTOCOLS,
      CONCAT_ARGS, NO_OBJ ),
  T01("required-client-protocols",    K_REQUIRED_CLIENT_PROTOCOLS,
      CONCAT_ARGS, NO_OBJ ),
  T01("required-relay-protocols",    K_REQUIRED_RELAY_PROTOCOLS,
      CONCAT_ARGS, NO_OBJ ),

575
576
577
  END_OF_TABLE
};

578
/** List of tokens recognized in the footer of v1 directory footers. */
579
static token_rule_t networkstatus_vote_footer_token_table[] = {
580
581
582
  T01("directory-footer",    K_DIRECTORY_FOOTER,    NO_ARGS,   NO_OBJ ),
  T01("bandwidth-weights",   K_BW_WEIGHTS,          ARGS,      NO_OBJ ),
  T(  "directory-signature", K_DIRECTORY_SIGNATURE, GE(2),     NEED_OBJ ),
583
584
  END_OF_TABLE
};
585

Nick Mathewson's avatar
Nick Mathewson committed
586
/** List of tokens recognized in detached networkstatus signature documents. */
587
588
static token_rule_t networkstatus_detached_signature_token_table[] = {
  T1_START("consensus-digest", K_CONSENSUS_DIGEST, GE(1),       NO_OBJ ),
589
  T("additional-digest",       K_ADDITIONAL_DIGEST,GE(3),       NO_OBJ ),
590
591
592
  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 ),
593
594
  T("additional-signature",  K_ADDITIONAL_SIGNATURE, GE(4),   NEED_OBJ ),
  T1N("directory-signature", K_DIRECTORY_SIGNATURE,  GE(2),   NEED_OBJ ),
595
596
597
  END_OF_TABLE
};

Nick Mathewson's avatar
Nick Mathewson committed
598
/** List of tokens recognized in microdescriptors */
599
600
static token_rule_t microdesc_token_table[] = {
  T1_START("onion-key",        K_ONION_KEY,        NO_ARGS,     NEED_KEY_1024),
601
  T01("ntor-onion-key",        K_ONION_KEY_NTOR,   GE(1),       NO_OBJ ),
602
  T0N("id",                    K_ID,               GE(2),       NO_OBJ ),
603
  T0N("a",                     K_A,                GE(1),       NO_OBJ ),
604
605
  T01("family",                K_FAMILY,           ARGS,        NO_OBJ ),
  T01("p",                     K_P,                CONCAT_ARGS, NO_OBJ ),
606
  T01("p6",                    K_P6,               CONCAT_ARGS, NO_OBJ ),
607
608
609
610
  A01("@last-listed",          A_LAST_LISTED,      CONCAT_ARGS, NO_OBJ ),
  END_OF_TABLE
};

611
612
#undef T

613
614
/* static function prototypes */
static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok);
615
616
static addr_policy_t *router_parse_addr_policy(directory_token_t *tok,
                                               unsigned fmt_flags);
617
618
static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok);

619
620
621
622
static int router_get_hash_impl_helper(const char *s, size_t s_len,
                            const char *start_str,
                            const char *end_str, char end_c,
                            const char **start_out, const char **end_out);
623
static int router_get_hash_impl(const char *s, size_t s_len, char *digest,
624
                                const char *start_str, const char *end_str,
625
626
                                char end_char,
                                digest_algorithm_t alg);
627
static int router_get_hashes_impl(const char *s, size_t s_len,
628
                                  common_digests_t *digests,
629
630
                                  const char *start_str, const char *end_str,
                                  char end_char);
631
static void token_clear(directory_token_t *tok);
632
static smartlist_t *find_all_by_keyword(smartlist_t *s, directory_keyword k);
633
static smartlist_t *find_all_exitpolicy(smartlist_t *s);
634
static directory_token_t *find_by_keyword_(smartlist_t *s,
635
636
                                           directory_keyword keyword,
                                           const char *keyword_str);
637
#define find_by_keyword(s, keyword) find_by_keyword_((s), (keyword), #keyword)
638
639
640
static directory_token_t *find_opt_by_keyword(smartlist_t *s,
                                              directory_keyword keyword);

641
642
643
#define TS_ANNOTATIONS_OK 1
#define TS_NOCHECK 2
#define TS_NO_NEW_ANNOTATIONS 4
644
645
static int tokenize_string(memarea_t *area,
                           const char *start, const char *end,
646
                           smartlist_t *out,
647
                           token_rule_t *table,
648
                           int flags);
649
650
static directory_token_t *get_next_token(memarea_t *area,
                                         const char **s,
651
                                         const char *eos,
652
                                         token_rule_t *table);
653
654
#define CST_CHECK_AUTHORITY   (1<<0)
#define CST_NO_CHECK_OBJTYPE  (1<<1)
655
static int check_signature_token(const char *digest,
656
                                 ssize_t digest_len,
657
                                 directory_token_t *tok,
658
                                 crypto_pk_t *pkey,
659
                                 int flags,
660
                                 const char *doctype);
661

662
663
664
665
666
667
668
669
670
671
672
673
674
#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

675
676
/* Dump mechanism for unparseable descriptors */

677
/** List of dumped descriptors for FIFO cleanup purposes */
678
STATIC smartlist_t *descs_dumped = NULL;
679
/** Total size of dumped descriptors for FIFO cleanup */
680
STATIC uint64_t len_descs_dumped = 0;
681
682
683
684
685
/** Directory to stash dumps in */
static int have_dump_desc_dir = 0;
static int problem_with_dump_desc_dir = 0;

#define DESC_DUMP_DATADIR_SUBDIR "unparseable-descs"
686
#define DESC_DUMP_BASE_FILENAME "unparseable-desc"
687

688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
/** Find the dump directory and check if we'll be able to create it */
static void
dump_desc_init(void)
{
  char *dump_desc_dir;

  dump_desc_dir = get_datadir_fname(DESC_DUMP_DATADIR_SUBDIR);

  /*
   * We just check for it, don't create it at this point; we'll
   * create it when we need it if it isn't already there.
   */
  if (check_private_dir(dump_desc_dir, CPD_CHECK, get_options()->User) < 0) {
    /* Error, log and flag it as having a problem */
    log_notice(LD_DIR,
               "Doesn't look like we'll be able to create descriptor dump "
               "directory %s; dumps will be disabled.",
               dump_desc_dir);
    problem_with_dump_desc_dir = 1;
    tor_free(dump_desc_dir);
    return;
  }

  /* Check if it exists */
  switch (file_status(dump_desc_dir)) {
    case FN_DIR:
      /* We already have a directory */
      have_dump_desc_dir = 1;
      break;
    case FN_NOENT:
      /* Nothing, we'll need to create it later */
      have_dump_desc_dir = 0;
      break;
    case FN_ERROR:
      /* Log and flag having a problem */
      log_notice(LD_DIR,
                 "Couldn't check whether descriptor dump directory %s already"
                 " exists: %s",
                 dump_desc_dir, strerror(errno));
      problem_with_dump_desc_dir = 1;
728
      break;
729
730
731
732
733
734
735
736
737
738
739
    case FN_FILE:
    case FN_EMPTY:
    default:
      /* Something else was here! */
      log_notice(LD_DIR,
                 "Descriptor dump directory %s already exists and isn't a "
                 "directory",
                 dump_desc_dir);
      problem_with_dump_desc_dir = 1;
  }

740
741
742
743
  if (have_dump_desc_dir && !problem_with_dump_desc_dir) {
    dump_desc_populate_fifo_from_directory(dump_desc_dir);
  }

744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
  tor_free(dump_desc_dir);
}

/** Create the dump directory if needed and possible */
static void
dump_desc_create_dir(void)
{
  char *dump_desc_dir;

  /* If the problem flag is set, skip it */
  if (problem_with_dump_desc_dir) return;

  /* Do we need it? */
  if (!have_dump_desc_dir) {
    dump_desc_dir = get_datadir_fname(DESC_DUMP_DATADIR_SUBDIR);

    if (check_private_dir(dump_desc_dir, CPD_CREATE,
                          get_options()->User) < 0) {
      log_notice(LD_DIR,
                 "Failed to create descriptor dump directory %s",
                 dump_desc_dir);
      problem_with_dump_desc_dir = 1;
    }

    /* Okay, we created it */
    have_dump_desc_dir = 1;

    tor_free(dump_desc_dir);
  }
}

775
776
/** Dump desc FIFO/cleanup; take ownership of the given filename, add it to
 * the FIFO, and clean up the oldest entries to the extent they exceed the
777
778
779
780
 * configured cap.  If any old entries with a matching hash existed, they
 * just got overwritten right before this was called and we should adjust
 * the total size counter without deleting them.
 */
781
static void
782
783
dump_desc_fifo_add_and_clean(char *filename, const uint8_t *digest_sha256,
                             size_t len)
784
785
{
  dumped_desc_t *ent = NULL, *tmp;
786
  uint64_t max_len;
787

788
789
790
  tor_assert(filename != NULL);
  tor_assert(digest_sha256 != NULL);

791
792
793
794
795
796
797
798
799
800
801
  if (descs_dumped == NULL) {
    /* We better have no length, then */
    tor_assert(len_descs_dumped == 0);
    /* Make a smartlist */
    descs_dumped = smartlist_new();
  }

  /* Make a new entry to put this one in */
  ent = tor_malloc_zero(sizeof(*ent));
  ent->filename = filename;
  ent->len = len;
802
  ent->when = time(NULL);
803
  memcpy(ent->digest_sha256, digest_sha256, DIGEST256_LEN);
804
805

  /* Do we need to do some cleanup? */
806
807
  max_len = get_options()->MaxUnparseableDescSizeToLog;
  /* Iterate over the list until we've freed enough space */
808
  while (len > max_len - len_descs_dumped &&
809
810
811
812
813
814
815
816
817
818
         smartlist_len(descs_dumped) > 0) {
    /* Get the oldest thing on the list */
    tmp = (dumped_desc_t *)(smartlist_get(descs_dumped, 0));

    /*
     * Check if it matches the filename we just added, so we don't delete
     * something we just emitted if we get repeated identical descriptors.
     */
    if (strcmp(tmp->filename, filename) != 0) {
      /* Delete it and adjust the length counter */
819
      tor_unlink(tmp->filename);
820
821
822
823
824
825
826
      tor_assert(len_descs_dumped >= tmp->len);
      len_descs_dumped -= tmp->len;
      log_info(LD_DIR,
               "Deleting old unparseable descriptor dump %s due to "
               "space limits",
               tmp->filename);
    } else {
827
      /*
828
829
       * Don't delete, but do adjust the counter since we will bump it
       * later
830
       */
831
832
833
834
835
      tor_assert(len_descs_dumped >= tmp->len);
      len_descs_dumped -= tmp->len;
      log_info(LD_DIR,
               "Replacing old descriptor dump %s with new identical one",
               tmp->filename);
836
    }
837
838
839
840
841

    /* Free it and remove it from the list */
    smartlist_del_keeporder(descs_dumped, 0);
    tor_free(tmp->filename);
    tor_free(tmp);
842
843
844
845
846
847
848
  }

  /* Append our entry to the end of the list and bump the counter */
  smartlist_add(descs_dumped, ent);
  len_descs_dumped += len;
}

849
850
851
852
853
854
855
856
857
858
859
860
861
862
/** Check if we already have a descriptor for this hash and move it to the
 * head of the queue if so.  Return 1 if one existed and 0 otherwise.
 */
static int
dump_desc_fifo_bump_hash(const uint8_t *digest_sha256)
{
  dumped_desc_t *match = NULL;

  tor_assert(digest_sha256);

  if (descs_dumped) {
    /* Find a match if one exists */
    SMARTLIST_FOREACH_BEGIN(descs_dumped, dumped_desc_t *, ent) {
      if (ent &&
Nick Mathewson's avatar
Nick Mathewson committed
863
          tor_memeq(ent->digest_sha256, digest_sha256, DIGEST256_LEN)) {
864
865
866
867
868
869
870
871
872
873
874
        /*
         * Save a pointer to the match and remove it from its current
         * position.
         */
        match = ent;
        SMARTLIST_DEL_CURRENT_KEEPORDER(descs_dumped, ent);
        break;
      }
    } SMARTLIST_FOREACH_END(ent);

    if (match) {
875
876
      /* Update the timestamp */
      match->when = time(NULL);
877
878
879
880
881
882
883
884
885
886
887
      /* Add it back at the end of the list */
      smartlist_add(descs_dumped, match);

      /* Indicate we found one */
      return 1;
    }
  }

  return 0;
}

888
889
/** Clean up on exit; just memory, leave the dumps behind
 */
890
STATIC void
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
dump_desc_fifo_cleanup(void)
{
  if (descs_dumped) {
    /* Free each descriptor */
    SMARTLIST_FOREACH_BEGIN(descs_dumped, dumped_desc_t *, ent) {
      tor_assert(ent);
      tor_free(ent->filename);
      tor_free(ent);
    } SMARTLIST_FOREACH_END(ent);
    /* Free the list */
    smartlist_free(descs_dumped);
    descs_dumped = NULL;
    len_descs_dumped = 0;
  }
}
906

907
908
909
910
/** Handle one file for dump_desc_populate_fifo_from_directory(); make sure
 * the filename is sensibly formed and matches the file content, and either
 * return a dumped_desc_t for it or remove the file and return NULL.
 */
911
912
MOCK_IMPL(STATIC dumped_desc_t *,
dump_desc_populate_one_file, (const char *dirname, const char *f))
913
914
915
916
917
918
919
920
921
922
923
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
957
958
959
960
961
962
963
964
{
  dumped_desc_t *ent = NULL;
  char *path = NULL, *desc = NULL;
  const char *digest_str;
  char digest[DIGEST256_LEN], content_digest[DIGEST256_LEN];
  /* Expected prefix before digest in filenames */
  const char *f_pfx = DESC_DUMP_BASE_FILENAME ".";
  /*
   * Stat while reading; this is important in case the file
   * contains a NUL character.
   */
  struct stat st;

  /* Sanity-check args */
  tor_assert(dirname != NULL);
  tor_assert(f != NULL);

  /* Form the full path */
  tor_asprintf(&path, "%s" PATH_SEPARATOR "%s", dirname, f);

  /* Check that f has the form DESC_DUMP_BASE_FILENAME.<digest256> */

  if (!strcmpstart(f, f_pfx)) {
    /* It matches the form, but is the digest parseable as such? */
    digest_str = f + strlen(f_pfx);
    if (base16_decode(digest, DIGEST256_LEN,
                      digest_str, strlen(digest_str)) != DIGEST256_LEN) {
      /* We failed to decode it */
      digest_str = NULL;
    }
  } else {
    /* No match */
    digest_str = NULL;
  }

  if (!digest_str) {
    /* We couldn't get a sensible digest */
    log_notice(LD_DIR,
               "Removing unrecognized filename %s from unparseable "
               "descriptors directory", f);
    tor_unlink(path);
    /* We're done */
    goto done;
  }

  /*
   * The filename has the form DESC_DUMP_BASE_FILENAME "." <digest256> and
   * we've decoded the digest.  Next, check that we can read it and the
   * content matches this digest.  We are relying on the fact that if the
   * file contains a '\0', read_file_to_str() will allocate space for and
   * read the entire file and return the correct size in st.
   */
965
  desc = read_file_to_str(path, RFTS_IGNORE_MISSING|RFTS_BIN, &st);
966
967
968
969
970
971
972
973
974
975
  if (!desc) {
    /* We couldn't read it */
    log_notice(LD_DIR,
               "Failed to read %s from unparseable descriptors directory; "
               "attempting to remove it.", f);
    tor_unlink(path);
    /* We're done */
    goto done;
  }

976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
#if SIZE_MAX > UINT64_MAX
  if (BUG((uint64_t)st.st_size > (uint64_t)SIZE_MAX)) {
    /* LCOV_EXCL_START
     * Should be impossible since RFTS above should have failed to read the
     * huge file into RAM. */
    goto done;
    /* LCOV_EXCL_STOP */
  }
#endif
  if (BUG(st.st_size < 0)) {
    /* LCOV_EXCL_START
     * Should be impossible, since the OS isn't supposed to be b0rken. */
    goto done;
    /* LCOV_EXCL_STOP */
  }
  /* (Now we can be sure that st.st_size is safe to cast to a size_t.) */

993
994
995
996
  /*
   * We got one; now compute its digest and check that it matches the
   * filename.
   */
997
  if (crypto_digest256((char *)content_digest, desc, (size_t) st.st_size,
998
999
1000
                       DIGEST_SHA256) != 0) {
    /* Weird, but okay */
    log_info(LD_DIR,