Back to index

tor  0.2.3.18-rc
routerparse.c
Go to the documentation of this file.
00001 /* Copyright (c) 2001 Matej Pfajfar.
00002  * Copyright (c) 2001-2004, Roger Dingledine.
00003  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
00004  * Copyright (c) 2007-2012, The Tor Project, Inc. */
00005 /* See LICENSE for licensing information */
00006 
00012 #include "or.h"
00013 #include "config.h"
00014 #include "circuitbuild.h"
00015 #include "dirserv.h"
00016 #include "dirvote.h"
00017 #include "policies.h"
00018 #include "rendcommon.h"
00019 #include "router.h"
00020 #include "routerlist.h"
00021 #include "memarea.h"
00022 #include "microdesc.h"
00023 #include "networkstatus.h"
00024 #include "rephist.h"
00025 #include "routerparse.h"
00026 #undef log
00027 #include <math.h>
00028 
00029 /****************************************************************************/
00030 
00035 typedef enum {
00036   K_ACCEPT = 0,
00037   K_ACCEPT6,
00038   K_DIRECTORY_SIGNATURE,
00039   K_RECOMMENDED_SOFTWARE,
00040   K_REJECT,
00041   K_REJECT6,
00042   K_ROUTER,
00043   K_SIGNED_DIRECTORY,
00044   K_SIGNING_KEY,
00045   K_ONION_KEY,
00046   K_ROUTER_SIGNATURE,
00047   K_PUBLISHED,
00048   K_RUNNING_ROUTERS,
00049   K_ROUTER_STATUS,
00050   K_PLATFORM,
00051   K_OPT,
00052   K_BANDWIDTH,
00053   K_CONTACT,
00054   K_NETWORK_STATUS,
00055   K_UPTIME,
00056   K_DIR_SIGNING_KEY,
00057   K_FAMILY,
00058   K_FINGERPRINT,
00059   K_HIBERNATING,
00060   K_READ_HISTORY,
00061   K_WRITE_HISTORY,
00062   K_NETWORK_STATUS_VERSION,
00063   K_DIR_SOURCE,
00064   K_DIR_OPTIONS,
00065   K_CLIENT_VERSIONS,
00066   K_SERVER_VERSIONS,
00067   K_OR_ADDRESS,
00068   K_P,
00069   K_R,
00070   K_S,
00071   K_V,
00072   K_W,
00073   K_M,
00074   K_EXTRA_INFO,
00075   K_EXTRA_INFO_DIGEST,
00076   K_CACHES_EXTRA_INFO,
00077   K_HIDDEN_SERVICE_DIR,
00078   K_ALLOW_SINGLE_HOP_EXITS,
00079 
00080   K_DIRREQ_END,
00081   K_DIRREQ_V2_IPS,
00082   K_DIRREQ_V3_IPS,
00083   K_DIRREQ_V2_REQS,
00084   K_DIRREQ_V3_REQS,
00085   K_DIRREQ_V2_SHARE,
00086   K_DIRREQ_V3_SHARE,
00087   K_DIRREQ_V2_RESP,
00088   K_DIRREQ_V3_RESP,
00089   K_DIRREQ_V2_DIR,
00090   K_DIRREQ_V3_DIR,
00091   K_DIRREQ_V2_TUN,
00092   K_DIRREQ_V3_TUN,
00093   K_ENTRY_END,
00094   K_ENTRY_IPS,
00095   K_CELL_END,
00096   K_CELL_PROCESSED,
00097   K_CELL_QUEUED,
00098   K_CELL_TIME,
00099   K_CELL_CIRCS,
00100   K_EXIT_END,
00101   K_EXIT_WRITTEN,
00102   K_EXIT_READ,
00103   K_EXIT_OPENED,
00104 
00105   K_DIR_KEY_CERTIFICATE_VERSION,
00106   K_DIR_IDENTITY_KEY,
00107   K_DIR_KEY_PUBLISHED,
00108   K_DIR_KEY_EXPIRES,
00109   K_DIR_KEY_CERTIFICATION,
00110   K_DIR_KEY_CROSSCERT,
00111   K_DIR_ADDRESS,
00112 
00113   K_VOTE_STATUS,
00114   K_VALID_AFTER,
00115   K_FRESH_UNTIL,
00116   K_VALID_UNTIL,
00117   K_VOTING_DELAY,
00118 
00119   K_KNOWN_FLAGS,
00120   K_PARAMS,
00121   K_BW_WEIGHTS,
00122   K_VOTE_DIGEST,
00123   K_CONSENSUS_DIGEST,
00124   K_ADDITIONAL_DIGEST,
00125   K_ADDITIONAL_SIGNATURE,
00126   K_CONSENSUS_METHODS,
00127   K_CONSENSUS_METHOD,
00128   K_LEGACY_DIR_KEY,
00129   K_DIRECTORY_FOOTER,
00130 
00131   A_PURPOSE,
00132   A_LAST_LISTED,
00133   _A_UNKNOWN,
00134 
00135   R_RENDEZVOUS_SERVICE_DESCRIPTOR,
00136   R_VERSION,
00137   R_PERMANENT_KEY,
00138   R_SECRET_ID_PART,
00139   R_PUBLICATION_TIME,
00140   R_PROTOCOL_VERSIONS,
00141   R_INTRODUCTION_POINTS,
00142   R_SIGNATURE,
00143 
00144   R_IPO_IDENTIFIER,
00145   R_IPO_IP_ADDRESS,
00146   R_IPO_ONION_PORT,
00147   R_IPO_ONION_KEY,
00148   R_IPO_SERVICE_KEY,
00149 
00150   C_CLIENT_NAME,
00151   C_DESCRIPTOR_COOKIE,
00152   C_CLIENT_KEY,
00153 
00154   _ERR,
00155   _EOF,
00156   _NIL
00157 } directory_keyword;
00158 
00159 #define MIN_ANNOTATION A_PURPOSE
00160 #define MAX_ANNOTATION _A_UNKNOWN
00161 
00172 typedef struct directory_token_t {
00173   directory_keyword tp;        
00174   int n_args:30;               
00175   char **args;                 
00177   char *object_type;           
00178   size_t object_size;          
00179   char *object_body;           
00181   crypto_pk_t *key;        
00183   char *error;                 
00184 } directory_token_t;
00185 
00186 /* ********************************************************************** */
00187 
00191 typedef enum {
00192   NO_OBJ,        
00193   NEED_OBJ,      
00194   NEED_SKEY_1024,
00195   NEED_KEY_1024, 
00196   NEED_KEY,      
00197   OBJ_OK,        
00198 } obj_syntax;
00199 
00200 #define AT_START 1
00201 #define AT_END 2
00202 
00204 typedef struct token_rule_t {
00206   const char *t;
00208   directory_keyword v;
00210   int min_args;
00212   int max_args;
00215   int concat_args;
00217   obj_syntax os;
00219   int min_cnt;
00221   int max_cnt;
00224   int pos;
00226   int is_annotation;
00227 } token_rule_t;
00228 
00229 /*
00230  * Helper macros to define token tables.  's' is a string, 't' is a
00231  * directory_keyword, 'a' is a trio of argument multiplicities, and 'o' is an
00232  * object syntax.
00233  *
00234  */
00235 
00237 #define END_OF_TABLE { NULL, _NIL, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 }
00238 
00239 #define T(s,t,a,o)    { s, t, a, o, 0, INT_MAX, 0, 0 }
00240 
00241 #define T0N(s,t,a,o)  { s, t, a, o, 0, INT_MAX, 0, 0 }
00242 
00243 #define T1(s,t,a,o)   { s, t, a, o, 1, 1, 0, 0 }
00244 
00245 #define T1_START(s,t,a,o)   { s, t, a, o, 1, 1, AT_START, 0 }
00246 
00247 #define T1_END(s,t,a,o)   { s, t, a, o, 1, 1, AT_END, 0 }
00248 
00249 #define T1N(s,t,a,o)  { s, t, a, o, 1, INT_MAX, 0, 0 }
00250 
00251 #define T01(s,t,a,o)  { s, t, a, o, 0, 1, 0, 0 }
00252 
00253 #define A01(s,t,a,o)  { s, t, a, o, 0, 1, 0, 1 }
00254 
00255 /* Argument multiplicity: any number of arguments. */
00256 #define ARGS        0,INT_MAX,0
00257 /* Argument multiplicity: no arguments. */
00258 #define NO_ARGS     0,0,0
00259 /* Argument multiplicity: concatenate all arguments. */
00260 #define CONCAT_ARGS 1,1,1
00261 /* Argument multiplicity: at least <b>n</b> arguments. */
00262 #define GE(n)       n,INT_MAX,0
00263 /* Argument multiplicity: exactly <b>n</b> arguments. */
00264 #define EQ(n)       n,n,0
00265 
00267 static token_rule_t routerdesc_token_table[] = {
00268   T0N("reject",              K_REJECT,              ARGS,    NO_OBJ ),
00269   T0N("accept",              K_ACCEPT,              ARGS,    NO_OBJ ),
00270   T0N("reject6",             K_REJECT6,             ARGS,    NO_OBJ ),
00271   T0N("accept6",             K_ACCEPT6,             ARGS,    NO_OBJ ),
00272   T1_START( "router",        K_ROUTER,              GE(5),   NO_OBJ ),
00273   T1( "signing-key",         K_SIGNING_KEY,         NO_ARGS, NEED_KEY_1024 ),
00274   T1( "onion-key",           K_ONION_KEY,           NO_ARGS, NEED_KEY_1024 ),
00275   T1_END( "router-signature",    K_ROUTER_SIGNATURE,    NO_ARGS, NEED_OBJ ),
00276   T1( "published",           K_PUBLISHED,       CONCAT_ARGS, NO_OBJ ),
00277   T01("uptime",              K_UPTIME,              GE(1),   NO_OBJ ),
00278   T01("fingerprint",         K_FINGERPRINT,     CONCAT_ARGS, NO_OBJ ),
00279   T01("hibernating",         K_HIBERNATING,         GE(1),   NO_OBJ ),
00280   T01("platform",            K_PLATFORM,        CONCAT_ARGS, NO_OBJ ),
00281   T01("contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ ),
00282   T01("read-history",        K_READ_HISTORY,        ARGS,    NO_OBJ ),
00283   T01("write-history",       K_WRITE_HISTORY,       ARGS,    NO_OBJ ),
00284   T01("extra-info-digest",   K_EXTRA_INFO_DIGEST,   GE(1),   NO_OBJ ),
00285   T01("hidden-service-dir",  K_HIDDEN_SERVICE_DIR,  NO_ARGS, NO_OBJ ),
00286   T01("allow-single-hop-exits",K_ALLOW_SINGLE_HOP_EXITS,    NO_ARGS, NO_OBJ ),
00287 
00288   T01("family",              K_FAMILY,              ARGS,    NO_OBJ ),
00289   T01("caches-extra-info",   K_CACHES_EXTRA_INFO,   NO_ARGS, NO_OBJ ),
00290   T0N("or-address",          K_OR_ADDRESS,          GE(1),   NO_OBJ ),
00291 
00292   T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
00293   T1( "bandwidth",           K_BANDWIDTH,           GE(3),   NO_OBJ ),
00294   A01("@purpose",            A_PURPOSE,             GE(1),   NO_OBJ ),
00295 
00296   END_OF_TABLE
00297 };
00298 
00300 static token_rule_t extrainfo_token_table[] = {
00301   T1_END( "router-signature",    K_ROUTER_SIGNATURE,    NO_ARGS, NEED_OBJ ),
00302   T1( "published",           K_PUBLISHED,       CONCAT_ARGS, NO_OBJ ),
00303   T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
00304   T01("read-history",        K_READ_HISTORY,        ARGS,    NO_OBJ ),
00305   T01("write-history",       K_WRITE_HISTORY,       ARGS,    NO_OBJ ),
00306   T01("dirreq-stats-end",    K_DIRREQ_END,          ARGS,    NO_OBJ ),
00307   T01("dirreq-v2-ips",       K_DIRREQ_V2_IPS,       ARGS,    NO_OBJ ),
00308   T01("dirreq-v3-ips",       K_DIRREQ_V3_IPS,       ARGS,    NO_OBJ ),
00309   T01("dirreq-v2-reqs",      K_DIRREQ_V2_REQS,      ARGS,    NO_OBJ ),
00310   T01("dirreq-v3-reqs",      K_DIRREQ_V3_REQS,      ARGS,    NO_OBJ ),
00311   T01("dirreq-v2-share",     K_DIRREQ_V2_SHARE,     ARGS,    NO_OBJ ),
00312   T01("dirreq-v3-share",     K_DIRREQ_V3_SHARE,     ARGS,    NO_OBJ ),
00313   T01("dirreq-v2-resp",      K_DIRREQ_V2_RESP,      ARGS,    NO_OBJ ),
00314   T01("dirreq-v3-resp",      K_DIRREQ_V3_RESP,      ARGS,    NO_OBJ ),
00315   T01("dirreq-v2-direct-dl", K_DIRREQ_V2_DIR,       ARGS,    NO_OBJ ),
00316   T01("dirreq-v3-direct-dl", K_DIRREQ_V3_DIR,       ARGS,    NO_OBJ ),
00317   T01("dirreq-v2-tunneled-dl", K_DIRREQ_V2_TUN,     ARGS,    NO_OBJ ),
00318   T01("dirreq-v3-tunneled-dl", K_DIRREQ_V3_TUN,     ARGS,    NO_OBJ ),
00319   T01("entry-stats-end",     K_ENTRY_END,           ARGS,    NO_OBJ ),
00320   T01("entry-ips",           K_ENTRY_IPS,           ARGS,    NO_OBJ ),
00321   T01("cell-stats-end",      K_CELL_END,            ARGS,    NO_OBJ ),
00322   T01("cell-processed-cells", K_CELL_PROCESSED,     ARGS,    NO_OBJ ),
00323   T01("cell-queued-cells",   K_CELL_QUEUED,         ARGS,    NO_OBJ ),
00324   T01("cell-time-in-queue",  K_CELL_TIME,           ARGS,    NO_OBJ ),
00325   T01("cell-circuits-per-decile", K_CELL_CIRCS,     ARGS,    NO_OBJ ),
00326   T01("exit-stats-end",      K_EXIT_END,            ARGS,    NO_OBJ ),
00327   T01("exit-kibibytes-written", K_EXIT_WRITTEN,     ARGS,    NO_OBJ ),
00328   T01("exit-kibibytes-read", K_EXIT_READ,           ARGS,    NO_OBJ ),
00329   T01("exit-streams-opened", K_EXIT_OPENED,         ARGS,    NO_OBJ ),
00330 
00331   T1_START( "extra-info",          K_EXTRA_INFO,          GE(2),   NO_OBJ ),
00332 
00333   END_OF_TABLE
00334 };
00335 
00338 static token_rule_t rtrstatus_token_table[] = {
00339   T01("p",                   K_P,               CONCAT_ARGS, NO_OBJ ),
00340   T1( "r",                   K_R,                   GE(7),   NO_OBJ ),
00341   T1( "s",                   K_S,                   ARGS,    NO_OBJ ),
00342   T01("v",                   K_V,               CONCAT_ARGS, NO_OBJ ),
00343   T01("w",                   K_W,                   ARGS,    NO_OBJ ),
00344   T0N("m",                   K_M,               CONCAT_ARGS, NO_OBJ ),
00345   T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
00346   END_OF_TABLE
00347 };
00348 
00351 static token_rule_t netstatus_token_table[] = {
00352   T1( "published",           K_PUBLISHED,       CONCAT_ARGS, NO_OBJ ),
00353   T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
00354   T1( "contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ ),
00355   T1( "dir-signing-key",     K_DIR_SIGNING_KEY,  NO_ARGS,    NEED_KEY_1024 ),
00356   T1( "fingerprint",         K_FINGERPRINT,     CONCAT_ARGS, NO_OBJ ),
00357   T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
00358                                                     GE(1),   NO_OBJ ),
00359   T1( "dir-source",          K_DIR_SOURCE,          GE(3),   NO_OBJ ),
00360   T01("dir-options",         K_DIR_OPTIONS,         ARGS,    NO_OBJ ),
00361   T01("client-versions",     K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
00362   T01("server-versions",     K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
00363 
00364   END_OF_TABLE
00365 };
00366 
00369 static token_rule_t dir_footer_token_table[] = {
00370   T1("directory-signature", K_DIRECTORY_SIGNATURE, EQ(1), NEED_OBJ ),
00371   END_OF_TABLE
00372 };
00373 
00375 static token_rule_t dir_token_table[] = {
00376   /* don't enforce counts; this is obsolete. */
00377   T( "network-status",      K_NETWORK_STATUS,      NO_ARGS, NO_OBJ ),
00378   T( "directory-signature", K_DIRECTORY_SIGNATURE, ARGS,    NEED_OBJ ),
00379   T( "recommended-software",K_RECOMMENDED_SOFTWARE,CONCAT_ARGS, NO_OBJ ),
00380   T( "signed-directory",    K_SIGNED_DIRECTORY,    NO_ARGS, NO_OBJ ),
00381 
00382   T( "running-routers",     K_RUNNING_ROUTERS,     ARGS,    NO_OBJ ),
00383   T( "router-status",       K_ROUTER_STATUS,       ARGS,    NO_OBJ ),
00384   T( "published",           K_PUBLISHED,       CONCAT_ARGS, NO_OBJ ),
00385   T( "opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
00386   T( "contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ ),
00387   T( "dir-signing-key",     K_DIR_SIGNING_KEY,     ARGS,    OBJ_OK ),
00388   T( "fingerprint",         K_FINGERPRINT,     CONCAT_ARGS, NO_OBJ ),
00389 
00390   END_OF_TABLE
00391 };
00392 
00394 #define CERTIFICATE_MEMBERS                                                  \
00395   T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION,           \
00396                                                      GE(1),       NO_OBJ ),  \
00397   T1("dir-identity-key", K_DIR_IDENTITY_KEY,         NO_ARGS,     NEED_KEY ),\
00398   T1("dir-key-published",K_DIR_KEY_PUBLISHED,        CONCAT_ARGS, NO_OBJ),   \
00399   T1("dir-key-expires",  K_DIR_KEY_EXPIRES,          CONCAT_ARGS, NO_OBJ),   \
00400   T1("dir-signing-key",  K_DIR_SIGNING_KEY,          NO_ARGS,     NEED_KEY ),\
00401   T01("dir-key-crosscert", K_DIR_KEY_CROSSCERT,       NO_ARGS,    NEED_OBJ ),\
00402   T1("dir-key-certification", K_DIR_KEY_CERTIFICATION,                       \
00403                                                      NO_ARGS,     NEED_OBJ), \
00404   T01("dir-address",     K_DIR_ADDRESS,              GE(1),       NO_OBJ),
00405 
00407 static token_rule_t dir_key_certificate_table[] = {
00408   CERTIFICATE_MEMBERS
00409   T1("fingerprint",      K_FINGERPRINT,              CONCAT_ARGS, NO_OBJ ),
00410   END_OF_TABLE
00411 };
00412 
00414 static token_rule_t desc_token_table[] = {
00415   T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR,
00416            EQ(1), NO_OBJ),
00417   T1("version", R_VERSION, EQ(1), NO_OBJ),
00418   T1("permanent-key", R_PERMANENT_KEY, NO_ARGS, NEED_KEY_1024),
00419   T1("secret-id-part", R_SECRET_ID_PART, EQ(1), NO_OBJ),
00420   T1("publication-time", R_PUBLICATION_TIME, CONCAT_ARGS, NO_OBJ),
00421   T1("protocol-versions", R_PROTOCOL_VERSIONS, EQ(1), NO_OBJ),
00422   T01("introduction-points", R_INTRODUCTION_POINTS, NO_ARGS, NEED_OBJ),
00423   T1_END("signature", R_SIGNATURE, NO_ARGS, NEED_OBJ),
00424   END_OF_TABLE
00425 };
00426 
00429 static token_rule_t ipo_token_table[] = {
00430   T1_START("introduction-point", R_IPO_IDENTIFIER, EQ(1), NO_OBJ),
00431   T1("ip-address", R_IPO_IP_ADDRESS, EQ(1), NO_OBJ),
00432   T1("onion-port", R_IPO_ONION_PORT, EQ(1), NO_OBJ),
00433   T1("onion-key", R_IPO_ONION_KEY, NO_ARGS, NEED_KEY_1024),
00434   T1("service-key", R_IPO_SERVICE_KEY, NO_ARGS, NEED_KEY_1024),
00435   END_OF_TABLE
00436 };
00437 
00440 static token_rule_t client_keys_token_table[] = {
00441   T1_START("client-name", C_CLIENT_NAME, CONCAT_ARGS, NO_OBJ),
00442   T1("descriptor-cookie", C_DESCRIPTOR_COOKIE, EQ(1), NO_OBJ),
00443   T01("client-key", C_CLIENT_KEY, NO_ARGS, NEED_SKEY_1024),
00444   END_OF_TABLE
00445 };
00446 
00448 static token_rule_t networkstatus_token_table[] = {
00449   T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
00450                                                    GE(1),       NO_OBJ ),
00451   T1("vote-status",            K_VOTE_STATUS,      GE(1),       NO_OBJ ),
00452   T1("published",              K_PUBLISHED,        CONCAT_ARGS, NO_OBJ ),
00453   T1("valid-after",            K_VALID_AFTER,      CONCAT_ARGS, NO_OBJ ),
00454   T1("fresh-until",            K_FRESH_UNTIL,      CONCAT_ARGS, NO_OBJ ),
00455   T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
00456   T1("voting-delay",           K_VOTING_DELAY,     GE(2),       NO_OBJ ),
00457   T1("known-flags",            K_KNOWN_FLAGS,      ARGS,        NO_OBJ ),
00458   T01("params",                K_PARAMS,           ARGS,        NO_OBJ ),
00459   T( "fingerprint",            K_FINGERPRINT,      CONCAT_ARGS, NO_OBJ ),
00460 
00461   CERTIFICATE_MEMBERS
00462 
00463   T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
00464   T1( "contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ ),
00465   T1( "dir-source",          K_DIR_SOURCE,      GE(6),       NO_OBJ ),
00466   T01("legacy-dir-key",      K_LEGACY_DIR_KEY,  GE(1),       NO_OBJ ),
00467   T1( "known-flags",         K_KNOWN_FLAGS,     CONCAT_ARGS, NO_OBJ ),
00468   T01("client-versions",     K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
00469   T01("server-versions",     K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
00470   T1( "consensus-methods",   K_CONSENSUS_METHODS, GE(1),     NO_OBJ ),
00471 
00472   END_OF_TABLE
00473 };
00474 
00476 static token_rule_t networkstatus_consensus_token_table[] = {
00477   T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
00478                                                    GE(1),       NO_OBJ ),
00479   T1("vote-status",            K_VOTE_STATUS,      GE(1),       NO_OBJ ),
00480   T1("valid-after",            K_VALID_AFTER,      CONCAT_ARGS, NO_OBJ ),
00481   T1("fresh-until",            K_FRESH_UNTIL,      CONCAT_ARGS, NO_OBJ ),
00482   T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
00483   T1("voting-delay",           K_VOTING_DELAY,     GE(2),       NO_OBJ ),
00484 
00485   T0N("opt",                 K_OPT,             CONCAT_ARGS, OBJ_OK ),
00486 
00487   T1N("dir-source",          K_DIR_SOURCE,          GE(6),   NO_OBJ ),
00488   T1N("contact",             K_CONTACT,         CONCAT_ARGS, NO_OBJ ),
00489   T1N("vote-digest",         K_VOTE_DIGEST,         GE(1),   NO_OBJ ),
00490 
00491   T1( "known-flags",         K_KNOWN_FLAGS,     CONCAT_ARGS, NO_OBJ ),
00492 
00493   T01("client-versions",     K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
00494   T01("server-versions",     K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
00495   T01("consensus-method",    K_CONSENSUS_METHOD,    EQ(1),   NO_OBJ),
00496   T01("params",                K_PARAMS,           ARGS,        NO_OBJ ),
00497 
00498   END_OF_TABLE
00499 };
00500 
00503 static token_rule_t networkstatus_vote_footer_token_table[] = {
00504   T01("directory-footer",    K_DIRECTORY_FOOTER,    NO_ARGS,   NO_OBJ ),
00505   T01("bandwidth-weights",   K_BW_WEIGHTS,          ARGS,      NO_OBJ ),
00506   T(  "directory-signature", K_DIRECTORY_SIGNATURE, GE(2),     NEED_OBJ ),
00507   END_OF_TABLE
00508 };
00509 
00511 static token_rule_t networkstatus_detached_signature_token_table[] = {
00512   T1_START("consensus-digest", K_CONSENSUS_DIGEST, GE(1),       NO_OBJ ),
00513   T("additional-digest",       K_ADDITIONAL_DIGEST,GE(3),       NO_OBJ ),
00514   T1("valid-after",            K_VALID_AFTER,      CONCAT_ARGS, NO_OBJ ),
00515   T1("fresh-until",            K_FRESH_UNTIL,      CONCAT_ARGS, NO_OBJ ),
00516   T1("valid-until",            K_VALID_UNTIL,      CONCAT_ARGS, NO_OBJ ),
00517   T("additional-signature",  K_ADDITIONAL_SIGNATURE, GE(4),   NEED_OBJ ),
00518   T1N("directory-signature", K_DIRECTORY_SIGNATURE,  GE(2),   NEED_OBJ ),
00519   END_OF_TABLE
00520 };
00521 
00523 static token_rule_t microdesc_token_table[] = {
00524   T1_START("onion-key",        K_ONION_KEY,        NO_ARGS,     NEED_KEY_1024),
00525   T01("family",                K_FAMILY,           ARGS,        NO_OBJ ),
00526   T01("p",                     K_P,                CONCAT_ARGS, NO_OBJ ),
00527   A01("@last-listed",          A_LAST_LISTED,      CONCAT_ARGS, NO_OBJ ),
00528   END_OF_TABLE
00529 };
00530 
00531 #undef T
00532 
00533 /* static function prototypes */
00534 static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok);
00535 static addr_policy_t *router_parse_addr_policy(directory_token_t *tok);
00536 static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok);
00537 
00538 static int router_get_hash_impl(const char *s, size_t s_len, char *digest,
00539                                 const char *start_str, const char *end_str,
00540                                 char end_char,
00541                                 digest_algorithm_t alg);
00542 static int router_get_hashes_impl(const char *s, size_t s_len,
00543                                   digests_t *digests,
00544                                   const char *start_str, const char *end_str,
00545                                   char end_char);
00546 static void token_clear(directory_token_t *tok);
00547 static smartlist_t *find_all_by_keyword(smartlist_t *s, directory_keyword k);
00548 static smartlist_t *find_all_exitpolicy(smartlist_t *s);
00549 static directory_token_t *_find_by_keyword(smartlist_t *s,
00550                                            directory_keyword keyword,
00551                                            const char *keyword_str);
00552 #define find_by_keyword(s, keyword) _find_by_keyword((s), (keyword), #keyword)
00553 static directory_token_t *find_opt_by_keyword(smartlist_t *s,
00554                                               directory_keyword keyword);
00555 
00556 #define TS_ANNOTATIONS_OK 1
00557 #define TS_NOCHECK 2
00558 #define TS_NO_NEW_ANNOTATIONS 4
00559 static int tokenize_string(memarea_t *area,
00560                            const char *start, const char *end,
00561                            smartlist_t *out,
00562                            token_rule_t *table,
00563                            int flags);
00564 static directory_token_t *get_next_token(memarea_t *area,
00565                                          const char **s,
00566                                          const char *eos,
00567                                          token_rule_t *table);
00568 #define CST_CHECK_AUTHORITY   (1<<0)
00569 #define CST_NO_CHECK_OBJTYPE  (1<<1)
00570 static int check_signature_token(const char *digest,
00571                                  ssize_t digest_len,
00572                                  directory_token_t *tok,
00573                                  crypto_pk_t *pkey,
00574                                  int flags,
00575                                  const char *doctype);
00576 static crypto_pk_t *find_dir_signing_key(const char *str, const char *eos);
00577 
00578 #undef DEBUG_AREA_ALLOC
00579 
00580 #ifdef DEBUG_AREA_ALLOC
00581 #define DUMP_AREA(a,name) STMT_BEGIN                              \
00582   size_t alloc=0, used=0;                                         \
00583   memarea_get_stats((a),&alloc,&used);                            \
00584   log_debug(LD_MM, "Area for %s has %lu allocated; using %lu.",   \
00585             name, (unsigned long)alloc, (unsigned long)used);     \
00586   STMT_END
00587 #else
00588 #define DUMP_AREA(a,name) STMT_NIL
00589 #endif
00590 
00592 static time_t last_desc_dumped = 0;
00593 
00598 static void
00599 dump_desc(const char *desc, const char *type)
00600 {
00601   time_t now = time(NULL);
00602   tor_assert(desc);
00603   tor_assert(type);
00604   if (!last_desc_dumped || last_desc_dumped + 60 < now) {
00605     char *debugfile = get_datadir_fname("unparseable-desc");
00606     size_t filelen = 50 + strlen(type) + strlen(desc);
00607     char *content = tor_malloc_zero(filelen);
00608     tor_snprintf(content, filelen, "Unable to parse descriptor of type "
00609                  "%s:\n%s", type, desc);
00610     write_str_to_file(debugfile, content, 0);
00611     log_info(LD_DIR, "Unable to parse descriptor of type %s. See file "
00612              "unparseable-desc in data directory for details.", type);
00613     tor_free(content);
00614     tor_free(debugfile);
00615     last_desc_dumped = now;
00616   }
00617 }
00618 
00622 int
00623 router_get_dir_hash(const char *s, char *digest)
00624 {
00625   return router_get_hash_impl(s, strlen(s), digest,
00626                               "signed-directory","\ndirectory-signature",'\n',
00627                               DIGEST_SHA1);
00628 }
00629 
00633 int
00634 router_get_router_hash(const char *s, size_t s_len, char *digest)
00635 {
00636   return router_get_hash_impl(s, s_len, digest,
00637                               "router ","\nrouter-signature", '\n',
00638                               DIGEST_SHA1);
00639 }
00640 
00644 int
00645 router_get_runningrouters_hash(const char *s, char *digest)
00646 {
00647   return router_get_hash_impl(s, strlen(s), digest,
00648                               "network-status","\ndirectory-signature", '\n',
00649                               DIGEST_SHA1);
00650 }
00651 
00654 int
00655 router_get_networkstatus_v2_hash(const char *s, char *digest)
00656 {
00657   return router_get_hash_impl(s, strlen(s), digest,
00658                               "network-status-version","\ndirectory-signature",
00659                               '\n',
00660                               DIGEST_SHA1);
00661 }
00662 
00665 int
00666 router_get_networkstatus_v3_hashes(const char *s, digests_t *digests)
00667 {
00668   return router_get_hashes_impl(s,strlen(s),digests,
00669                                 "network-status-version",
00670                                 "\ndirectory-signature",
00671                                 ' ');
00672 }
00673 
00676 int
00677 router_get_networkstatus_v3_hash(const char *s, char *digest,
00678                                  digest_algorithm_t alg)
00679 {
00680   return router_get_hash_impl(s, strlen(s), digest,
00681                               "network-status-version",
00682                               "\ndirectory-signature",
00683                               ' ', alg);
00684 }
00685 
00688 int
00689 router_get_extrainfo_hash(const char *s, size_t s_len, char *digest)
00690 {
00691   return router_get_hash_impl(s, s_len, digest, "extra-info",
00692                               "\nrouter-signature",'\n', DIGEST_SHA1);
00693 }
00694 
00702 int
00703 router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
00704                                size_t digest_len, crypto_pk_t *private_key)
00705 {
00706   char *signature;
00707   size_t i, keysize;
00708   int siglen;
00709 
00710   keysize = crypto_pk_keysize(private_key);
00711   signature = tor_malloc(keysize);
00712   siglen = crypto_pk_private_sign(private_key, signature, keysize,
00713                                   digest, digest_len);
00714   if (siglen < 0) {
00715     log_warn(LD_BUG,"Couldn't sign digest.");
00716     goto err;
00717   }
00718   if (strlcat(buf, "-----BEGIN SIGNATURE-----\n", buf_len) >= buf_len)
00719     goto truncated;
00720 
00721   i = strlen(buf);
00722   if (base64_encode(buf+i, buf_len-i, signature, siglen) < 0) {
00723     log_warn(LD_BUG,"couldn't base64-encode signature");
00724     goto err;
00725   }
00726 
00727   if (strlcat(buf, "-----END SIGNATURE-----\n", buf_len) >= buf_len)
00728     goto truncated;
00729 
00730   tor_free(signature);
00731   return 0;
00732 
00733  truncated:
00734   log_warn(LD_BUG,"tried to exceed string length.");
00735  err:
00736   tor_free(signature);
00737   return -1;
00738 }
00739 
00754 version_status_t
00755 tor_version_is_obsolete(const char *myversion, const char *versionlist)
00756 {
00757   tor_version_t mine, other;
00758   int found_newer = 0, found_older = 0, found_newer_in_series = 0,
00759     found_any_in_series = 0, r, same;
00760   version_status_t ret = VS_UNRECOMMENDED;
00761   smartlist_t *version_sl;
00762 
00763   log_debug(LD_CONFIG,"Checking whether version '%s' is in '%s'",
00764             myversion, versionlist);
00765 
00766   if (tor_version_parse(myversion, &mine)) {
00767     log_err(LD_BUG,"I couldn't parse my own version (%s)", myversion);
00768     tor_assert(0);
00769   }
00770   version_sl = smartlist_new();
00771   smartlist_split_string(version_sl, versionlist, ",", SPLIT_SKIP_SPACE, 0);
00772 
00773   if (!strlen(versionlist)) { /* no authorities cared or agreed */
00774     ret = VS_EMPTY;
00775     goto done;
00776   }
00777 
00778   SMARTLIST_FOREACH(version_sl, const char *, cp, {
00779     if (!strcmpstart(cp, "Tor "))
00780       cp += 4;
00781 
00782     if (tor_version_parse(cp, &other)) {
00783       /* Couldn't parse other; it can't be a match. */
00784     } else {
00785       same = tor_version_same_series(&mine, &other);
00786       if (same)
00787         found_any_in_series = 1;
00788       r = tor_version_compare(&mine, &other);
00789       if (r==0) {
00790         ret = VS_RECOMMENDED;
00791         goto done;
00792       } else if (r<0) {
00793         found_newer = 1;
00794         if (same)
00795           found_newer_in_series = 1;
00796       } else if (r>0) {
00797         found_older = 1;
00798       }
00799     }
00800   });
00801 
00802   /* We didn't find the listed version. Is it new or old? */
00803   if (found_any_in_series && !found_newer_in_series && found_newer) {
00804     ret = VS_NEW_IN_SERIES;
00805   } else if (found_newer && !found_older) {
00806     ret = VS_OLD;
00807   } else if (found_older && !found_newer) {
00808     ret = VS_NEW;
00809   } else {
00810     ret = VS_UNRECOMMENDED;
00811   }
00812 
00813  done:
00814   SMARTLIST_FOREACH(version_sl, char *, version, tor_free(version));
00815   smartlist_free(version_sl);
00816   return ret;
00817 }
00818 
00822 int
00823 router_parse_directory(const char *str)
00824 {
00825   directory_token_t *tok;
00826   char digest[DIGEST_LEN];
00827   time_t published_on;
00828   int r;
00829   const char *end, *cp, *str_dup = str;
00830   smartlist_t *tokens = NULL;
00831   crypto_pk_t *declared_key = NULL;
00832   memarea_t *area = memarea_new();
00833 
00834   /* XXXX This could be simplified a lot, but it will all go away
00835    * once pre-0.1.1.8 is obsolete, and for now it's better not to
00836    * touch it. */
00837 
00838   if (router_get_dir_hash(str, digest)) {
00839     log_warn(LD_DIR, "Unable to compute digest of directory");
00840     goto err;
00841   }
00842   log_debug(LD_DIR,"Received directory hashes to %s",hex_str(digest,4));
00843 
00844   /* Check signature first, before we try to tokenize. */
00845   cp = str;
00846   while (cp && (end = strstr(cp+1, "\ndirectory-signature")))
00847     cp = end;
00848   if (cp == str || !cp) {
00849     log_warn(LD_DIR, "No signature found on directory."); goto err;
00850   }
00851   ++cp;
00852   tokens = smartlist_new();
00853   if (tokenize_string(area,cp,strchr(cp,'\0'),tokens,dir_token_table,0)) {
00854     log_warn(LD_DIR, "Error tokenizing directory signature"); goto err;
00855   }
00856   if (smartlist_len(tokens) != 1) {
00857     log_warn(LD_DIR, "Unexpected number of tokens in signature"); goto err;
00858   }
00859   tok=smartlist_get(tokens,0);
00860   if (tok->tp != K_DIRECTORY_SIGNATURE) {
00861     log_warn(LD_DIR,"Expected a single directory signature"); goto err;
00862   }
00863   declared_key = find_dir_signing_key(str, str+strlen(str));
00864   note_crypto_pk_op(VERIFY_DIR);
00865   if (check_signature_token(digest, DIGEST_LEN, tok, declared_key,
00866                             CST_CHECK_AUTHORITY, "directory")<0)
00867     goto err;
00868 
00869   SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
00870   smartlist_clear(tokens);
00871   memarea_clear(area);
00872 
00873   /* Now try to parse the first part of the directory. */
00874   if ((end = strstr(str,"\nrouter "))) {
00875     ++end;
00876   } else if ((end = strstr(str, "\ndirectory-signature"))) {
00877     ++end;
00878   } else {
00879     end = str + strlen(str);
00880   }
00881 
00882   if (tokenize_string(area,str,end,tokens,dir_token_table,0)) {
00883     log_warn(LD_DIR, "Error tokenizing directory"); goto err;
00884   }
00885 
00886   tok = find_by_keyword(tokens, K_PUBLISHED);
00887   tor_assert(tok->n_args == 1);
00888 
00889   if (parse_iso_time(tok->args[0], &published_on) < 0) {
00890      goto err;
00891   }
00892 
00893   /* Now that we know the signature is okay, and we have a
00894    * publication time, cache the directory. */
00895   if (directory_caches_v1_dir_info(get_options()) &&
00896       !authdir_mode_v1(get_options()))
00897     dirserv_set_cached_directory(str, published_on, 0);
00898 
00899   r = 0;
00900   goto done;
00901  err:
00902   dump_desc(str_dup, "v1 directory");
00903   r = -1;
00904  done:
00905   if (declared_key) crypto_pk_free(declared_key);
00906   if (tokens) {
00907     SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
00908     smartlist_free(tokens);
00909   }
00910   if (area) {
00911     DUMP_AREA(area, "v1 directory");
00912     memarea_drop_all(area);
00913   }
00914   return r;
00915 }
00916 
00920 int
00921 router_parse_runningrouters(const char *str)
00922 {
00923   char digest[DIGEST_LEN];
00924   directory_token_t *tok;
00925   time_t published_on;
00926   int r = -1;
00927   crypto_pk_t *declared_key = NULL;
00928   smartlist_t *tokens = NULL;
00929   const char *eos = str + strlen(str), *str_dup = str;
00930   memarea_t *area = NULL;
00931 
00932   if (router_get_runningrouters_hash(str, digest)) {
00933     log_warn(LD_DIR, "Unable to compute digest of running-routers");
00934     goto err;
00935   }
00936   area = memarea_new();
00937   tokens = smartlist_new();
00938   if (tokenize_string(area,str,eos,tokens,dir_token_table,0)) {
00939     log_warn(LD_DIR, "Error tokenizing running-routers"); goto err;
00940   }
00941   tok = smartlist_get(tokens,0);
00942   if (tok->tp != K_NETWORK_STATUS) {
00943     log_warn(LD_DIR, "Network-status starts with wrong token");
00944     goto err;
00945   }
00946 
00947   tok = find_by_keyword(tokens, K_PUBLISHED);
00948   tor_assert(tok->n_args == 1);
00949   if (parse_iso_time(tok->args[0], &published_on) < 0) {
00950      goto err;
00951   }
00952   if (!(tok = find_opt_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) {
00953     log_warn(LD_DIR, "Missing signature on running-routers");
00954     goto err;
00955   }
00956   declared_key = find_dir_signing_key(str, eos);
00957   note_crypto_pk_op(VERIFY_DIR);
00958   if (check_signature_token(digest, DIGEST_LEN, tok, declared_key,
00959                             CST_CHECK_AUTHORITY, "running-routers")
00960       < 0)
00961     goto err;
00962 
00963   /* Now that we know the signature is okay, and we have a
00964    * publication time, cache the list. */
00965   if (get_options()->DirPort && !authdir_mode_v1(get_options()))
00966     dirserv_set_cached_directory(str, published_on, 1);
00967 
00968   r = 0;
00969  err:
00970   dump_desc(str_dup, "v1 running-routers");
00971   if (declared_key) crypto_pk_free(declared_key);
00972   if (tokens) {
00973     SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
00974     smartlist_free(tokens);
00975   }
00976   if (area) {
00977     DUMP_AREA(area, "v1 running-routers");
00978     memarea_drop_all(area);
00979   }
00980   return r;
00981 }
00982 
00986 static crypto_pk_t *
00987 find_dir_signing_key(const char *str, const char *eos)
00988 {
00989   const char *cp;
00990   directory_token_t *tok;
00991   crypto_pk_t *key = NULL;
00992   memarea_t *area = NULL;
00993   tor_assert(str);
00994   tor_assert(eos);
00995 
00996   /* Is there a dir-signing-key in the directory? */
00997   cp = tor_memstr(str, eos-str, "\nopt dir-signing-key");
00998   if (!cp)
00999     cp = tor_memstr(str, eos-str, "\ndir-signing-key");
01000   if (!cp)
01001     return NULL;
01002   ++cp; /* Now cp points to the start of the token. */
01003 
01004   area = memarea_new();
01005   tok = get_next_token(area, &cp, eos, dir_token_table);
01006   if (!tok) {
01007     log_warn(LD_DIR, "Unparseable dir-signing-key token");
01008     goto done;
01009   }
01010   if (tok->tp != K_DIR_SIGNING_KEY) {
01011     log_warn(LD_DIR, "Dir-signing-key token did not parse as expected");
01012     goto done;
01013   }
01014 
01015   if (tok->key) {
01016     key = tok->key;
01017     tok->key = NULL; /* steal reference. */
01018   } else {
01019     log_warn(LD_DIR, "Dir-signing-key token contained no key");
01020   }
01021 
01022  done:
01023   if (tok) token_clear(tok);
01024   if (area) {
01025     DUMP_AREA(area, "dir-signing-key token");
01026     memarea_drop_all(area);
01027   }
01028   return key;
01029 }
01030 
01033 static int
01034 dir_signing_key_is_trusted(crypto_pk_t *key)
01035 {
01036   char digest[DIGEST_LEN];
01037   if (!key) return 0;
01038   if (crypto_pk_get_digest(key, digest) < 0) {
01039     log_warn(LD_DIR, "Error computing dir-signing-key digest");
01040     return 0;
01041   }
01042   if (!router_digest_is_trusted_dir(digest)) {
01043     log_warn(LD_DIR, "Listed dir-signing-key is not trusted");
01044     return 0;
01045   }
01046   return 1;
01047 }
01048 
01057 static int
01058 check_signature_token(const char *digest,
01059                       ssize_t digest_len,
01060                       directory_token_t *tok,
01061                       crypto_pk_t *pkey,
01062                       int flags,
01063                       const char *doctype)
01064 {
01065   char *signed_digest;
01066   size_t keysize;
01067   const int check_authority = (flags & CST_CHECK_AUTHORITY);
01068   const int check_objtype = ! (flags & CST_NO_CHECK_OBJTYPE);
01069 
01070   tor_assert(pkey);
01071   tor_assert(tok);
01072   tor_assert(digest);
01073   tor_assert(doctype);
01074 
01075   if (check_authority && !dir_signing_key_is_trusted(pkey)) {
01076     log_warn(LD_DIR, "Key on %s did not come from an authority; rejecting",
01077              doctype);
01078     return -1;
01079   }
01080 
01081   if (check_objtype) {
01082     if (strcmp(tok->object_type, "SIGNATURE")) {
01083       log_warn(LD_DIR, "Bad object type on %s signature", doctype);
01084       return -1;
01085     }
01086   }
01087 
01088   keysize = crypto_pk_keysize(pkey);
01089   signed_digest = tor_malloc(keysize);
01090   if (crypto_pk_public_checksig(pkey, signed_digest, keysize,
01091                                 tok->object_body, tok->object_size)
01092       < digest_len) {
01093     log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype);
01094     tor_free(signed_digest);
01095     return -1;
01096   }
01097 //  log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
01098 //            hex_str(signed_digest,4));
01099   if (tor_memneq(digest, signed_digest, digest_len)) {
01100     log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
01101     tor_free(signed_digest);
01102     return -1;
01103   }
01104   tor_free(signed_digest);
01105   return 0;
01106 }
01107 
01113 static int
01114 find_start_of_next_router_or_extrainfo(const char **s_ptr,
01115                                        const char *eos,
01116                                        int *is_extrainfo_out)
01117 {
01118   const char *annotations = NULL;
01119   const char *s = *s_ptr;
01120 
01121   s = eat_whitespace_eos(s, eos);
01122 
01123   while (s < eos-32) {  /* 32 gives enough room for a the first keyword. */
01124     /* We're at the start of a line. */
01125     tor_assert(*s != '\n');
01126 
01127     if (*s == '@' && !annotations) {
01128       annotations = s;
01129     } else if (*s == 'r' && !strcmpstart(s, "router ")) {
01130       *s_ptr = annotations ? annotations : s;
01131       *is_extrainfo_out = 0;
01132       return 0;
01133     } else if (*s == 'e' && !strcmpstart(s, "extra-info ")) {
01134       *s_ptr = annotations ? annotations : s;
01135       *is_extrainfo_out = 1;
01136       return 0;
01137     }
01138 
01139     if (!(s = memchr(s+1, '\n', eos-(s+1))))
01140       break;
01141     s = eat_whitespace_eos(s, eos);
01142   }
01143   return -1;
01144 }
01145 
01158 int
01159 router_parse_list_from_string(const char **s, const char *eos,
01160                               smartlist_t *dest,
01161                               saved_location_t saved_location,
01162                               int want_extrainfo,
01163                               int allow_annotations,
01164                               const char *prepend_annotations)
01165 {
01166   routerinfo_t *router;
01167   extrainfo_t *extrainfo;
01168   signed_descriptor_t *signed_desc;
01169   void *elt;
01170   const char *end, *start;
01171   int have_extrainfo;
01172 
01173   tor_assert(s);
01174   tor_assert(*s);
01175   tor_assert(dest);
01176 
01177   start = *s;
01178   if (!eos)
01179     eos = *s + strlen(*s);
01180 
01181   tor_assert(eos >= *s);
01182 
01183   while (1) {
01184     if (find_start_of_next_router_or_extrainfo(s, eos, &have_extrainfo) < 0)
01185       break;
01186 
01187     end = tor_memstr(*s, eos-*s, "\nrouter-signature");
01188     if (end)
01189       end = tor_memstr(end, eos-end, "\n-----END SIGNATURE-----\n");
01190     if (end)
01191       end += strlen("\n-----END SIGNATURE-----\n");
01192 
01193     if (!end)
01194       break;
01195 
01196     elt = NULL;
01197 
01198     if (have_extrainfo && want_extrainfo) {
01199       routerlist_t *rl = router_get_routerlist();
01200       extrainfo = extrainfo_parse_entry_from_string(*s, end,
01201                                        saved_location != SAVED_IN_CACHE,
01202                                        rl->identity_map);
01203       if (extrainfo) {
01204         signed_desc = &extrainfo->cache_info;
01205         elt = extrainfo;
01206       }
01207     } else if (!have_extrainfo && !want_extrainfo) {
01208       router = router_parse_entry_from_string(*s, end,
01209                                               saved_location != SAVED_IN_CACHE,
01210                                               allow_annotations,
01211                                               prepend_annotations);
01212       if (router) {
01213         log_debug(LD_DIR, "Read router '%s', purpose '%s'",
01214                   router_describe(router),
01215                   router_purpose_to_string(router->purpose));
01216         signed_desc = &router->cache_info;
01217         elt = router;
01218       }
01219     }
01220     if (!elt) {
01221       *s = end;
01222       continue;
01223     }
01224     if (saved_location != SAVED_NOWHERE) {
01225       signed_desc->saved_location = saved_location;
01226       signed_desc->saved_offset = *s - start;
01227     }
01228     *s = end;
01229     smartlist_add(dest, elt);
01230   }
01231 
01232   return 0;
01233 }
01234 
01235 /* For debugging: define to count every descriptor digest we've seen so we
01236  * know if we need to try harder to avoid duplicate verifies. */
01237 #undef COUNT_DISTINCT_DIGESTS
01238 
01239 #ifdef COUNT_DISTINCT_DIGESTS
01240 static digestmap_t *verified_digests = NULL;
01241 #endif
01242 
01247 void
01248 dump_distinct_digest_count(int severity)
01249 {
01250 #ifdef COUNT_DISTINCT_DIGESTS
01251   if (!verified_digests)
01252     verified_digests = digestmap_new();
01253   log(severity, LD_GENERAL, "%d *distinct* router digests verified",
01254       digestmap_size(verified_digests));
01255 #else
01256   (void)severity; /* suppress "unused parameter" warning */
01257 #endif
01258 }
01259 
01276 routerinfo_t *
01277 router_parse_entry_from_string(const char *s, const char *end,
01278                                int cache_copy, int allow_annotations,
01279                                const char *prepend_annotations)
01280 {
01281   routerinfo_t *router = NULL;
01282   char digest[128];
01283   smartlist_t *tokens = NULL, *exit_policy_tokens = NULL;
01284   directory_token_t *tok;
01285   struct in_addr in;
01286   const char *start_of_annotations, *cp, *s_dup = s;
01287   size_t prepend_len = prepend_annotations ? strlen(prepend_annotations) : 0;
01288   int ok = 1;
01289   memarea_t *area = NULL;
01290 
01291   tor_assert(!allow_annotations || !prepend_annotations);
01292 
01293   if (!end) {
01294     end = s + strlen(s);
01295   }
01296 
01297   /* point 'end' to a point immediately after the final newline. */
01298   while (end > s+2 && *(end-1) == '\n' && *(end-2) == '\n')
01299     --end;
01300 
01301   area = memarea_new();
01302   tokens = smartlist_new();
01303   if (prepend_annotations) {
01304     if (tokenize_string(area,prepend_annotations,NULL,tokens,
01305                         routerdesc_token_table,TS_NOCHECK)) {
01306       log_warn(LD_DIR, "Error tokenizing router descriptor (annotations).");
01307       goto err;
01308     }
01309   }
01310 
01311   start_of_annotations = s;
01312   cp = tor_memstr(s, end-s, "\nrouter ");
01313   if (!cp) {
01314     if (end-s < 7 || strcmpstart(s, "router ")) {
01315       log_warn(LD_DIR, "No router keyword found.");
01316       goto err;
01317     }
01318   } else {
01319     s = cp+1;
01320   }
01321 
01322   if (start_of_annotations != s) { /* We have annotations */
01323     if (allow_annotations) {
01324       if (tokenize_string(area,start_of_annotations,s,tokens,
01325                           routerdesc_token_table,TS_NOCHECK)) {
01326         log_warn(LD_DIR, "Error tokenizing router descriptor (annotations).");
01327         goto err;
01328       }
01329     } else {
01330       log_warn(LD_DIR, "Found unexpected annotations on router descriptor not "
01331                "loaded from disk.  Dropping it.");
01332       goto err;
01333     }
01334   }
01335 
01336   if (router_get_router_hash(s, end - s, digest) < 0) {
01337     log_warn(LD_DIR, "Couldn't compute router hash.");
01338     goto err;
01339   }
01340   {
01341     int flags = 0;
01342     if (allow_annotations)
01343       flags |= TS_ANNOTATIONS_OK;
01344     if (prepend_annotations)
01345       flags |= TS_ANNOTATIONS_OK|TS_NO_NEW_ANNOTATIONS;
01346 
01347     if (tokenize_string(area,s,end,tokens,routerdesc_token_table, flags)) {
01348       log_warn(LD_DIR, "Error tokenizing router descriptor.");
01349       goto err;
01350     }
01351   }
01352 
01353   if (smartlist_len(tokens) < 2) {
01354     log_warn(LD_DIR, "Impossibly short router descriptor.");
01355     goto err;
01356   }
01357 
01358   tok = find_by_keyword(tokens, K_ROUTER);
01359   tor_assert(tok->n_args >= 5);
01360 
01361   router = tor_malloc_zero(sizeof(routerinfo_t));
01362   router->cache_info.routerlist_index = -1;
01363   router->cache_info.annotations_len = s-start_of_annotations + prepend_len;
01364   router->cache_info.signed_descriptor_len = end-s;
01365   if (cache_copy) {
01366     size_t len = router->cache_info.signed_descriptor_len +
01367                  router->cache_info.annotations_len;
01368     char *cp =
01369       router->cache_info.signed_descriptor_body = tor_malloc(len+1);
01370     if (prepend_annotations) {
01371       memcpy(cp, prepend_annotations, prepend_len);
01372       cp += prepend_len;
01373     }
01374     /* This assertion will always succeed.
01375      * len == signed_desc_len + annotations_len
01376      *     == end-s + s-start_of_annotations + prepend_len
01377      *     == end-start_of_annotations + prepend_len
01378      * We already wrote prepend_len bytes into the buffer; now we're
01379      * writing end-start_of_annotations -NM. */
01380     tor_assert(cp+(end-start_of_annotations) ==
01381                router->cache_info.signed_descriptor_body+len);
01382     memcpy(cp, start_of_annotations, end-start_of_annotations);
01383     router->cache_info.signed_descriptor_body[len] = '\0';
01384     tor_assert(strlen(router->cache_info.signed_descriptor_body) == len);
01385   }
01386   memcpy(router->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
01387 
01388   router->nickname = tor_strdup(tok->args[0]);
01389   if (!is_legal_nickname(router->nickname)) {
01390     log_warn(LD_DIR,"Router nickname is invalid");
01391     goto err;
01392   }
01393   router->address = tor_strdup(tok->args[1]);
01394   if (!tor_inet_aton(router->address, &in)) {
01395     log_warn(LD_DIR,"Router address is not an IP address.");
01396     goto err;
01397   }
01398   router->addr = ntohl(in.s_addr);
01399 
01400   router->or_port =
01401     (uint16_t) tor_parse_long(tok->args[2],10,0,65535,&ok,NULL);
01402   if (!ok) {
01403     log_warn(LD_DIR,"Invalid OR port %s", escaped(tok->args[2]));
01404     goto err;
01405   }
01406   router->dir_port =
01407     (uint16_t) tor_parse_long(tok->args[4],10,0,65535,&ok,NULL);
01408   if (!ok) {
01409     log_warn(LD_DIR,"Invalid dir port %s", escaped(tok->args[4]));
01410     goto err;
01411   }
01412 
01413   tok = find_by_keyword(tokens, K_BANDWIDTH);
01414   tor_assert(tok->n_args >= 3);
01415   router->bandwidthrate = (int)
01416     tor_parse_long(tok->args[0],10,1,INT_MAX,&ok,NULL);
01417 
01418   if (!ok) {
01419     log_warn(LD_DIR, "bandwidthrate %s unreadable or 0. Failing.",
01420              escaped(tok->args[0]));
01421     goto err;
01422   }
01423   router->bandwidthburst =
01424     (int) tor_parse_long(tok->args[1],10,0,INT_MAX,&ok,NULL);
01425   if (!ok) {
01426     log_warn(LD_DIR, "Invalid bandwidthburst %s", escaped(tok->args[1]));
01427     goto err;
01428   }
01429   router->bandwidthcapacity = (int)
01430     tor_parse_long(tok->args[2],10,0,INT_MAX,&ok,NULL);
01431   if (!ok) {
01432     log_warn(LD_DIR, "Invalid bandwidthcapacity %s", escaped(tok->args[1]));
01433     goto err;
01434   }
01435 
01436   if ((tok = find_opt_by_keyword(tokens, A_PURPOSE))) {
01437     tor_assert(tok->n_args);
01438     router->purpose = router_purpose_from_string(tok->args[0]);
01439   } else {
01440     router->purpose = ROUTER_PURPOSE_GENERAL;
01441   }
01442   router->cache_info.send_unencrypted =
01443     (router->purpose == ROUTER_PURPOSE_GENERAL) ? 1 : 0;
01444 
01445   if ((tok = find_opt_by_keyword(tokens, K_UPTIME))) {
01446     tor_assert(tok->n_args >= 1);
01447     router->uptime = tor_parse_long(tok->args[0],10,0,LONG_MAX,&ok,NULL);
01448     if (!ok) {
01449       log_warn(LD_DIR, "Invalid uptime %s", escaped(tok->args[0]));
01450       goto err;
01451     }
01452   }
01453 
01454   if ((tok = find_opt_by_keyword(tokens, K_HIBERNATING))) {
01455     tor_assert(tok->n_args >= 1);
01456     router->is_hibernating
01457       = (tor_parse_long(tok->args[0],10,0,LONG_MAX,NULL,NULL) != 0);
01458   }
01459 
01460   tok = find_by_keyword(tokens, K_PUBLISHED);
01461   tor_assert(tok->n_args == 1);
01462   if (parse_iso_time(tok->args[0], &router->cache_info.published_on) < 0)
01463     goto err;
01464 
01465   tok = find_by_keyword(tokens, K_ONION_KEY);
01466   if (!crypto_pk_public_exponent_ok(tok->key)) {
01467     log_warn(LD_DIR,
01468              "Relay's onion key had invalid exponent.");
01469     goto err;
01470   }
01471   router->onion_pkey = tok->key;
01472   tok->key = NULL; /* Prevent free */
01473 
01474   tok = find_by_keyword(tokens, K_SIGNING_KEY);
01475   router->identity_pkey = tok->key;
01476   tok->key = NULL; /* Prevent free */
01477   if (crypto_pk_get_digest(router->identity_pkey,
01478                            router->cache_info.identity_digest)) {
01479     log_warn(LD_DIR, "Couldn't calculate key digest"); goto err;
01480   }
01481 
01482   if ((tok = find_opt_by_keyword(tokens, K_FINGERPRINT))) {
01483     /* If there's a fingerprint line, it must match the identity digest. */
01484     char d[DIGEST_LEN];
01485     tor_assert(tok->n_args == 1);
01486     tor_strstrip(tok->args[0], " ");
01487     if (base16_decode(d, DIGEST_LEN, tok->args[0], strlen(tok->args[0]))) {
01488       log_warn(LD_DIR, "Couldn't decode router fingerprint %s",
01489                escaped(tok->args[0]));
01490       goto err;
01491     }
01492     if (tor_memneq(d,router->cache_info.identity_digest, DIGEST_LEN)) {
01493       log_warn(LD_DIR, "Fingerprint '%s' does not match identity digest.",
01494                tok->args[0]);
01495       goto err;
01496     }
01497   }
01498 
01499   if ((tok = find_opt_by_keyword(tokens, K_PLATFORM))) {
01500     router->platform = tor_strdup(tok->args[0]);
01501   }
01502 
01503   if ((tok = find_opt_by_keyword(tokens, K_CONTACT))) {
01504     router->contact_info = tor_strdup(tok->args[0]);
01505   }
01506 
01507   if (find_opt_by_keyword(tokens, K_REJECT6) ||
01508       find_opt_by_keyword(tokens, K_ACCEPT6)) {
01509     log_warn(LD_DIR, "Rejecting router with reject6/accept6 line: they crash "
01510              "older Tors.");
01511     goto err;
01512   }
01513   {
01514     smartlist_t *or_addresses = find_all_by_keyword(tokens, K_OR_ADDRESS);
01515     if (or_addresses) {
01516       SMARTLIST_FOREACH_BEGIN(or_addresses, directory_token_t *, t) {
01517         tor_addr_t a;
01518         maskbits_t bits;
01519         uint16_t port_min, port_max;
01520         /* XXXX Prop186 the full spec allows much more than this. */
01521         if (tor_addr_parse_mask_ports(t->args[0], &a, &bits, &port_min,
01522                                       &port_max) == AF_INET6 &&
01523             bits == 128 &&
01524             port_min == port_max) {
01525           /* Okay, this is one we can understand. */
01526           tor_addr_copy(&router->ipv6_addr, &a);
01527           router->ipv6_orport = port_min;
01528           break;
01529         }
01530       } SMARTLIST_FOREACH_END(t);
01531       smartlist_free(or_addresses);
01532     }
01533   }
01534   exit_policy_tokens = find_all_exitpolicy(tokens);
01535   if (!smartlist_len(exit_policy_tokens)) {
01536     log_warn(LD_DIR, "No exit policy tokens in descriptor.");
01537     goto err;
01538   }
01539   SMARTLIST_FOREACH(exit_policy_tokens, directory_token_t *, t,
01540                     if (router_add_exit_policy(router,t)<0) {
01541                       log_warn(LD_DIR,"Error in exit policy");
01542                       goto err;
01543                     });
01544   policy_expand_private(&router->exit_policy);
01545   if (policy_is_reject_star(router->exit_policy))
01546     router->policy_is_reject_star = 1;
01547 
01548   if ((tok = find_opt_by_keyword(tokens, K_FAMILY)) && tok->n_args) {
01549     int i;
01550     router->declared_family = smartlist_new();
01551     for (i=0;i<tok->n_args;++i) {
01552       if (!is_legal_nickname_or_hexdigest(tok->args[i])) {
01553         log_warn(LD_DIR, "Illegal nickname %s in family line",
01554                  escaped(tok->args[i]));
01555         goto err;
01556       }
01557       smartlist_add(router->declared_family, tor_strdup(tok->args[i]));
01558     }
01559   }
01560 
01561   if (find_opt_by_keyword(tokens, K_CACHES_EXTRA_INFO))
01562     router->caches_extra_info = 1;
01563 
01564   if (find_opt_by_keyword(tokens, K_ALLOW_SINGLE_HOP_EXITS))
01565     router->allow_single_hop_exits = 1;
01566 
01567   if ((tok = find_opt_by_keyword(tokens, K_EXTRA_INFO_DIGEST))) {
01568     tor_assert(tok->n_args >= 1);
01569     if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {
01570       base16_decode(router->cache_info.extra_info_digest,
01571                     DIGEST_LEN, tok->args[0], HEX_DIGEST_LEN);
01572     } else {
01573       log_warn(LD_DIR, "Invalid extra info digest %s", escaped(tok->args[0]));
01574     }
01575   }
01576 
01577   if (find_opt_by_keyword(tokens, K_HIDDEN_SERVICE_DIR)) {
01578     router->wants_to_be_hs_dir = 1;
01579   }
01580 
01581   tok = find_by_keyword(tokens, K_ROUTER_SIGNATURE);
01582   note_crypto_pk_op(VERIFY_RTR);
01583 #ifdef COUNT_DISTINCT_DIGESTS
01584   if (!verified_digests)
01585     verified_digests = digestmap_new();
01586   digestmap_set(verified_digests, signed_digest, (void*)(uintptr_t)1);
01587 #endif
01588   if (check_signature_token(digest, DIGEST_LEN, tok, router->identity_pkey, 0,
01589                             "router descriptor") < 0)
01590     goto err;
01591 
01592   if (!router->or_port) {
01593     log_warn(LD_DIR,"or_port unreadable or 0. Failing.");
01594     goto err;
01595   }
01596 
01597   if (!router->platform) {
01598     router->platform = tor_strdup("<unknown>");
01599   }
01600 
01601   goto done;
01602 
01603  err:
01604   dump_desc(s_dup, "router descriptor");
01605   routerinfo_free(router);
01606   router = NULL;
01607  done:
01608   if (tokens) {
01609     SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
01610     smartlist_free(tokens);
01611   }
01612   smartlist_free(exit_policy_tokens);
01613   if (area) {
01614     DUMP_AREA(area, "routerinfo");
01615     memarea_drop_all(area);
01616   }
01617   return router;
01618 }
01619 
01626 extrainfo_t *
01627 extrainfo_parse_entry_from_string(const char *s, const char *end,
01628                            int cache_copy, struct digest_ri_map_t *routermap)
01629 {
01630   extrainfo_t *extrainfo = NULL;
01631   char digest[128];
01632   smartlist_t *tokens = NULL;
01633   directory_token_t *tok;
01634   crypto_pk_t *key = NULL;
01635   routerinfo_t *router = NULL;
01636   memarea_t *area = NULL;
01637   const char *s_dup = s;
01638 
01639   if (!end) {
01640     end = s + strlen(s);
01641   }
01642 
01643   /* point 'end' to a point immediately after the final newline. */
01644   while (end > s+2 && *(end-1) == '\n' && *(end-2) == '\n')
01645     --end;
01646 
01647   if (router_get_extrainfo_hash(s, end-s, digest) < 0) {
01648     log_warn(LD_DIR, "Couldn't compute router hash.");
01649     goto err;
01650   }
01651   tokens = smartlist_new();
01652   area = memarea_new();
01653   if (tokenize_string(area,s,end,tokens,extrainfo_token_table,0)) {
01654     log_warn(LD_DIR, "Error tokenizing extra-info document.");
01655     goto err;
01656   }
01657 
01658   if (smartlist_len(tokens) < 2) {
01659     log_warn(LD_DIR, "Impossibly short extra-info document.");
01660     goto err;
01661   }
01662 
01663   tok = smartlist_get(tokens,0);
01664   if (tok->tp != K_EXTRA_INFO) {
01665     log_warn(LD_DIR,"Entry does not start with \"extra-info\"");
01666     goto err;
01667   }
01668 
01669   extrainfo = tor_malloc_zero(sizeof(extrainfo_t));
01670   extrainfo->cache_info.is_extrainfo = 1;
01671   if (cache_copy)
01672     extrainfo->cache_info.signed_descriptor_body = tor_strndup(s, end-s);
01673   extrainfo->cache_info.signed_descriptor_len = end-s;
01674   memcpy(extrainfo->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
01675 
01676   tor_assert(tok->n_args >= 2);
01677   if (!is_legal_nickname(tok->args[0])) {
01678     log_warn(LD_DIR,"Bad nickname %s on \"extra-info\"",escaped(tok->args[0]));
01679     goto err;
01680   }
01681   strlcpy(extrainfo->nickname, tok->args[0], sizeof(extrainfo->nickname));
01682   if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
01683       base16_decode(extrainfo->cache_info.identity_digest, DIGEST_LEN,
01684                     tok->args[1], HEX_DIGEST_LEN)) {
01685     log_warn(LD_DIR,"Invalid fingerprint %s on \"extra-info\"",
01686              escaped(tok->args[1]));
01687     goto err;
01688   }
01689 
01690   tok = find_by_keyword(tokens, K_PUBLISHED);
01691   if (parse_iso_time(tok->args[0], &extrainfo->cache_info.published_on)) {
01692     log_warn(LD_DIR,"Invalid published time %s on \"extra-info\"",
01693              escaped(tok->args[0]));
01694     goto err;
01695   }
01696 
01697   if (routermap &&
01698       (router = digestmap_get((digestmap_t*)routermap,
01699                               extrainfo->cache_info.identity_digest))) {
01700     key = router->identity_pkey;
01701   }
01702 
01703   tok = find_by_keyword(tokens, K_ROUTER_SIGNATURE);
01704   if (strcmp(tok->object_type, "SIGNATURE") ||
01705       tok->object_size < 128 || tok->object_size > 512) {
01706     log_warn(LD_DIR, "Bad object type or length on extra-info signature");
01707     goto err;
01708   }
01709 
01710   if (key) {
01711     note_crypto_pk_op(VERIFY_RTR);
01712     if (check_signature_token(digest, DIGEST_LEN, tok, key, 0,
01713                               "extra-info") < 0)
01714       goto err;
01715 
01716     if (router)
01717       extrainfo->cache_info.send_unencrypted =
01718         router->cache_info.send_unencrypted;
01719   } else {
01720     extrainfo->pending_sig = tor_memdup(tok->object_body,
01721                                         tok->object_size);
01722     extrainfo->pending_sig_len = tok->object_size;
01723   }
01724 
01725   goto done;
01726  err:
01727   dump_desc(s_dup, "extra-info descriptor");
01728   extrainfo_free(extrainfo);
01729   extrainfo = NULL;
01730  done:
01731   if (tokens) {
01732     SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
01733     smartlist_free(tokens);
01734   }
01735   if (area) {
01736     DUMP_AREA(area, "extrainfo");
01737     memarea_drop_all(area);
01738   }
01739   return extrainfo;
01740 }
01741 
01744 authority_cert_t *
01745 authority_cert_parse_from_string(const char *s, const char **end_of_string)
01746 {
01749 #define MAX_CERT_SIZE (128*1024)
01750 
01751   authority_cert_t *cert = NULL, *old_cert;
01752   smartlist_t *tokens = NULL;
01753   char digest[DIGEST_LEN];
01754   directory_token_t *tok;
01755   char fp_declared[DIGEST_LEN];
01756   char *eos;
01757   size_t len;
01758   int found;
01759   memarea_t *area = NULL;
01760   const char *s_dup = s;
01761 
01762   s = eat_whitespace(s);
01763   eos = strstr(s, "\ndir-key-certification");
01764   if (! eos) {
01765     log_warn(LD_DIR, "No signature found on key certificate");
01766     return NULL;
01767   }
01768   eos = strstr(eos, "\n-----END SIGNATURE-----\n");
01769   if (! eos) {
01770     log_warn(LD_DIR, "No end-of-signature found on key certificate");
01771     return NULL;
01772   }
01773   eos = strchr(eos+2, '\n');
01774   tor_assert(eos);
01775   ++eos;
01776   len = eos - s;
01777 
01778   if (len > MAX_CERT_SIZE) {
01779     log_warn(LD_DIR, "Certificate is far too big (at %lu bytes long); "
01780              "rejecting", (unsigned long)len);
01781     return NULL;
01782   }
01783 
01784   tokens = smartlist_new();
01785   area = memarea_new();
01786   if (tokenize_string(area,s, eos, tokens, dir_key_certificate_table, 0) < 0) {
01787     log_warn(LD_DIR, "Error tokenizing key certificate");
01788     goto err;
01789   }
01790   if (router_get_hash_impl(s, strlen(s), digest, "dir-key-certificate-version",
01791                            "\ndir-key-certification", '\n', DIGEST_SHA1) < 0)
01792     goto err;
01793   tok = smartlist_get(tokens, 0);
01794   if (tok->tp != K_DIR_KEY_CERTIFICATE_VERSION || strcmp(tok->args[0], "3")) {
01795     log_warn(LD_DIR,
01796              "Key certificate does not begin with a recognized version (3).");
01797     goto err;
01798   }
01799 
01800   cert = tor_malloc_zero(sizeof(authority_cert_t));
01801   memcpy(cert->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
01802 
01803   tok = find_by_keyword(tokens, K_DIR_SIGNING_KEY);
01804   tor_assert(tok->key);
01805   cert->signing_key = tok->key;
01806   tok->key = NULL;
01807   if (crypto_pk_get_digest(cert->signing_key, cert->signing_key_digest))
01808     goto err;
01809 
01810   tok = find_by_keyword(tokens, K_DIR_IDENTITY_KEY);
01811   tor_assert(tok->key);
01812   cert->identity_key = tok->key;
01813   tok->key = NULL;
01814 
01815   tok = find_by_keyword(tokens, K_FINGERPRINT);
01816   tor_assert(tok->n_args);
01817   if (base16_decode(fp_declared, DIGEST_LEN, tok->args[0],
01818                     strlen(tok->args[0]))) {
01819     log_warn(LD_DIR, "Couldn't decode key certificate fingerprint %s",
01820              escaped(tok->args[0]));
01821     goto err;
01822   }
01823 
01824   if (crypto_pk_get_digest(cert->identity_key,
01825                            cert->cache_info.identity_digest))
01826     goto err;
01827 
01828   if (tor_memneq(cert->cache_info.identity_digest, fp_declared, DIGEST_LEN)) {
01829     log_warn(LD_DIR, "Digest of certificate key didn't match declared "
01830              "fingerprint");
01831     goto err;
01832   }
01833 
01834   tok = find_opt_by_keyword(tokens, K_DIR_ADDRESS);
01835   if (tok) {
01836     struct in_addr in;
01837     char *address = NULL;
01838     tor_assert(tok->n_args);
01839     /* XXX024 use some tor_addr parse function below instead. -RD */
01840     if (tor_addr_port_split(LOG_WARN, tok->args[0], &address,
01841                             &cert->dir_port) < 0 ||
01842         tor_inet_aton(address, &in) == 0) {
01843       log_warn(LD_DIR, "Couldn't parse dir-address in certificate");
01844       tor_free(address);
01845       goto err;
01846     }
01847     cert->addr = ntohl(in.s_addr);
01848     tor_free(address);
01849   }
01850 
01851   tok = find_by_keyword(tokens, K_DIR_KEY_PUBLISHED);
01852   if (parse_iso_time(tok->args[0], &cert->cache_info.published_on) < 0) {
01853      goto err;
01854   }
01855   tok = find_by_keyword(tokens, K_DIR_KEY_EXPIRES);
01856   if (parse_iso_time(tok->args[0], &cert->expires) < 0) {
01857      goto err;
01858   }
01859 
01860   tok = smartlist_get(tokens, smartlist_len(tokens)-1);
01861   if (tok->tp != K_DIR_KEY_CERTIFICATION) {
01862     log_warn(LD_DIR, "Certificate didn't end with dir-key-certification.");
01863     goto err;
01864   }
01865 
01866   /* If we already have this cert, don't bother checking the signature. */
01867   old_cert = authority_cert_get_by_digests(
01868                                      cert->cache_info.identity_digest,
01869                                      cert->signing_key_digest);
01870   found = 0;
01871   if (old_cert) {
01872     /* XXXX We could just compare signed_descriptor_digest, but that wouldn't
01873      * buy us much. */
01874     if (old_cert->cache_info.signed_descriptor_len == len &&
01875         old_cert->cache_info.signed_descriptor_body &&
01876         tor_memeq(s, old_cert->cache_info.signed_descriptor_body, len)) {
01877       log_debug(LD_DIR, "We already checked the signature on this "
01878                 "certificate; no need to do so again.");
01879       found = 1;
01880       cert->is_cross_certified = old_cert->is_cross_certified;
01881     }
01882   }
01883   if (!found) {
01884     if (check_signature_token(digest, DIGEST_LEN, tok, cert->identity_key, 0,
01885                               "key certificate")) {
01886       goto err;
01887     }
01888 
01889     if ((tok = find_opt_by_keyword(tokens, K_DIR_KEY_CROSSCERT))) {
01890       /* XXXX Once all authorities generate cross-certified certificates,
01891        * make this field mandatory. */
01892       if (check_signature_token(cert->cache_info.identity_digest,
01893                                 DIGEST_LEN,
01894                                 tok,
01895                                 cert->signing_key,
01896                                 CST_NO_CHECK_OBJTYPE,
01897                                 "key cross-certification")) {
01898         goto err;
01899       }
01900       cert->is_cross_certified = 1;
01901     }
01902   }
01903 
01904   cert->cache_info.signed_descriptor_len = len;
01905   cert->cache_info.signed_descriptor_body = tor_malloc(len+1);
01906   memcpy(cert->cache_info.signed_descriptor_body, s, len);
01907   cert->cache_info.signed_descriptor_body[len] = 0;
01908   cert->cache_info.saved_location = SAVED_NOWHERE;
01909 
01910   if (end_of_string) {
01911     *end_of_string = eat_whitespace(eos);
01912   }
01913   SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
01914   smartlist_free(tokens);
01915   if (area) {
01916     DUMP_AREA(area, "authority cert");
01917     memarea_drop_all(area);
01918   }
01919   return cert;
01920  err:
01921   dump_desc(s_dup, "authority cert");
01922   authority_cert_free(cert);
01923   SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
01924   smartlist_free(tokens);
01925   if (area) {
01926     DUMP_AREA(area, "authority cert");
01927     memarea_drop_all(area);
01928   }
01929   return NULL;
01930 }
01931 
01936 static INLINE const char *
01937 find_start_of_next_routerstatus(const char *s)
01938 {
01939   const char *eos, *footer, *sig;
01940   if ((eos = strstr(s, "\nr ")))
01941     ++eos;
01942   else
01943     eos = s + strlen(s);
01944 
01945   footer = tor_memstr(s, eos-s, "\ndirectory-footer");
01946   sig = tor_memstr(s, eos-s, "\ndirectory-signature");
01947 
01948   if (footer && sig)
01949     return MIN(footer, sig) + 1;
01950   else if (footer)
01951     return footer+1;
01952   else if (sig)
01953     return sig+1;
01954   else
01955     return eos;
01956 }
01957 
01972 static routerstatus_t *
01973 routerstatus_parse_entry_from_string(memarea_t *area,
01974                                      const char **s, smartlist_t *tokens,
01975                                      networkstatus_t *vote,
01976                                      vote_routerstatus_t *vote_rs,
01977                                      int consensus_method,
01978                                      consensus_flavor_t flav)
01979 {
01980   const char *eos, *s_dup = *s;
01981   routerstatus_t *rs = NULL;
01982   directory_token_t *tok;
01983   char timebuf[ISO_TIME_LEN+1];
01984   struct in_addr in;
01985   int offset = 0;
01986   tor_assert(tokens);
01987   tor_assert(bool_eq(vote, vote_rs));
01988 
01989   if (!consensus_method)
01990     flav = FLAV_NS;
01991   tor_assert(flav == FLAV_NS || flav == FLAV_MICRODESC);
01992 
01993   eos = find_start_of_next_routerstatus(*s);
01994 
01995   if (tokenize_string(area,*s, eos, tokens, rtrstatus_token_table,0)) {
01996     log_warn(LD_DIR, "Error tokenizing router status");
01997     goto err;
01998   }
01999   if (smartlist_len(tokens) < 1) {
02000     log_warn(LD_DIR, "Impossibly short router status");
02001     goto err;
02002   }
02003   tok = find_by_keyword(tokens, K_R);
02004   tor_assert(tok->n_args >= 7); /* guaranteed by GE(7) in K_R setup */
02005   if (flav == FLAV_NS) {
02006     if (tok->n_args < 8) {
02007       log_warn(LD_DIR, "Too few arguments to r");
02008       goto err;
02009     }
02010   } else if (flav == FLAV_MICRODESC) {
02011     offset = -1; /* There is no identity digest */
02012   }
02013 
02014   if (vote_rs) {
02015     rs = &vote_rs->status;
02016   } else {
02017     rs = tor_malloc_zero(sizeof(routerstatus_t));
02018   }
02019 
02020   if (!is_legal_nickname(tok->args[0])) {
02021     log_warn(LD_DIR,
02022              "Invalid nickname %s in router status; skipping.",
02023              escaped(tok->args[0]));
02024     goto err;
02025   }
02026   strlcpy(rs->nickname, tok->args[0], sizeof(rs->nickname));
02027 
02028   if (digest_from_base64(rs->identity_digest, tok->args[1])) {
02029     log_warn(LD_DIR, "Error decoding identity digest %s",
02030              escaped(tok->args[1]));
02031     goto err;
02032   }
02033 
02034   if (flav == FLAV_NS) {
02035     if (digest_from_base64(rs->descriptor_digest, tok->args[2])) {
02036       log_warn(LD_DIR, "Error decoding descriptor digest %s",
02037                escaped(tok->args[2]));
02038       goto err;
02039     }
02040   }
02041 
02042   if (tor_snprintf(timebuf, sizeof(timebuf), "%s %s",
02043                    tok->args[3+offset], tok->args[4+offset]) < 0 ||
02044       parse_iso_time(timebuf, &rs->published_on)<0) {
02045     log_warn(LD_DIR, "Error parsing time '%s %s' [%d %d]",
02046              tok->args[3+offset], tok->args[4+offset],
02047              offset, (int)flav);
02048     goto err;
02049   }
02050 
02051   if (tor_inet_aton(tok->args[5+offset], &in) == 0) {
02052     log_warn(LD_DIR, "Error parsing router address in network-status %s",
02053              escaped(tok->args[5+offset]));
02054     goto err;
02055   }
02056   rs->addr = ntohl(in.s_addr);
02057 
02058   rs->or_port = (uint16_t) tor_parse_long(tok->args[6+offset],
02059                                          10,0,65535,NULL,NULL);
02060   rs->dir_port = (uint16_t) tor_parse_long(tok->args[7+offset],
02061                                            10,0,65535,NULL,NULL);
02062 
02063   tok = find_opt_by_keyword(tokens, K_S);
02064   if (tok && vote) {
02065     int i;
02066     vote_rs->flags = 0;
02067     for (i=0; i < tok->n_args; ++i) {
02068       int p = smartlist_string_pos(vote->known_flags, tok->args[i]);
02069       if (p >= 0) {
02070         vote_rs->flags |= (1<<p);
02071       } else {
02072         log_warn(LD_DIR, "Flags line had a flag %s not listed in known_flags.",
02073                  escaped(tok->args[i]));
02074         goto err;
02075       }
02076     }
02077   } else if (tok) {
02078     int i;
02079     for (i=0; i < tok->n_args; ++i) {
02080       if (!strcmp(tok->args[i], "Exit"))
02081         rs->is_exit = 1;
02082       else if (!strcmp(tok->args[i], "Stable"))
02083         rs->is_stable = 1;
02084       else if (!strcmp(tok->args[i], "Fast"))
02085         rs->is_fast = 1;
02086       else if (!strcmp(tok->args[i], "Running"))
02087         rs->is_flagged_running = 1;
02088       else if (!strcmp(tok->args[i], "Named"))
02089         rs->is_named = 1;
02090       else if (!strcmp(tok->args[i], "Valid"))
02091         rs->is_valid = 1;
02092       else if (!strcmp(tok->args[i], "V2Dir"))
02093         rs->is_v2_dir = 1;
02094       else if (!strcmp(tok->args[i], "Guard"))
02095         rs->is_possible_guard = 1;
02096       else if (!strcmp(tok->args[i], "BadExit"))
02097         rs->is_bad_exit = 1;
02098       else if (!strcmp(tok->args[i], "BadDirectory"))
02099         rs->is_bad_directory = 1;
02100       else if (!strcmp(tok->args[i], "Authority"))
02101         rs->is_authority = 1;
02102       else if (!strcmp(tok->args[i], "Unnamed") &&
02103                consensus_method >= 2) {
02104         /* Unnamed is computed right by consensus method 2 and later. */
02105         rs->is_unnamed = 1;
02106       } else if (!strcmp(tok->args[i], "HSDir")) {
02107         rs->is_hs_dir = 1;
02108       }
02109     }
02110   }
02111   if ((tok = find_opt_by_keyword(tokens, K_V))) {
02112     tor_assert(tok->n_args == 1);
02113     rs->version_known = 1;
02114     if (strcmpstart(tok->args[0], "Tor ")) {
02115       rs->version_supports_begindir = 1;
02116       rs->version_supports_extrainfo_upload = 1;
02117       rs->version_supports_conditional_consensus = 1;
02118       rs->version_supports_microdesc_cache = 1;
02119       rs->version_supports_optimistic_data = 1;
02120     } else {
02121       rs->version_supports_begindir =
02122         tor_version_as_new_as(tok->args[0], "0.2.0.1-alpha");
02123       rs->version_supports_extrainfo_upload =
02124         tor_version_as_new_as(tok->args[0], "0.2.0.0-alpha-dev (r10070)");
02125       rs->version_supports_v3_dir =
02126         tor_version_as_new_as(tok->args[0], "0.2.0.8-alpha");
02127       rs->version_supports_conditional_consensus =
02128         tor_version_as_new_as(tok->args[0], "0.2.1.1-alpha");
02129       rs->version_supports_microdesc_cache =
02130         tor_version_supports_microdescriptors(tok->args[0]);
02131       rs->version_supports_optimistic_data =
02132         tor_version_as_new_as(tok->args[0], "0.2.3.1-alpha");
02133     }
02134     if (vote_rs) {
02135       vote_rs->version = tor_strdup(tok->args[0]);
02136     }
02137   }
02138 
02139   /* handle weighting/bandwidth info */
02140   if ((tok = find_opt_by_keyword(tokens, K_W))) {
02141     int i;
02142     for (i=0; i < tok->n_args; ++i) {
02143       if (!strcmpstart(tok->args[i], "Bandwidth=")) {
02144         int ok;
02145         rs->bandwidth = (uint32_t)tor_parse_ulong(strchr(tok->args[i], '=')+1,
02146                                                   10, 0, UINT32_MAX,
02147                                                   &ok, NULL);
02148         if (!ok) {
02149           log_warn(LD_DIR, "Invalid Bandwidth %s", escaped(tok->args[i]));
02150           goto err;
02151         }
02152         rs->has_bandwidth = 1;
02153       } else if (!strcmpstart(tok->args[i], "Measured=")) {
02154         int ok;
02155         rs->measured_bw =
02156             (uint32_t)tor_parse_ulong(strchr(tok->args[i], '=')+1,
02157                                       10, 0, UINT32_MAX, &ok, NULL);
02158         if (!ok) {
02159           log_warn(LD_DIR, "Invalid Measured Bandwidth %s",
02160                    escaped(tok->args[i]));
02161           goto err;
02162         }
02163         rs->has_measured_bw = 1;
02164       }
02165     }
02166   }
02167 
02168   /* parse exit policy summaries */
02169   if ((tok = find_opt_by_keyword(tokens, K_P))) {
02170     tor_assert(tok->n_args == 1);
02171     if (strcmpstart(tok->args[0], "accept ") &&
02172         strcmpstart(tok->args[0], "reject ")) {
02173       log_warn(LD_DIR, "Unknown exit policy summary type %s.",
02174                escaped(tok->args[0]));
02175       goto err;
02176     }
02177     /* XXX weasel: parse this into ports and represent them somehow smart,
02178      * maybe not here but somewhere on if we need it for the client.
02179      * we should still parse it here to check it's valid tho.
02180      */
02181     rs->exitsummary = tor_strdup(tok->args[0]);
02182     rs->has_exitsummary = 1;
02183   }
02184 
02185   if (vote_rs) {
02186     SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, t) {
02187       if (t->tp == K_M && t->n_args) {
02188         vote_microdesc_hash_t *line =
02189           tor_malloc(sizeof(vote_microdesc_hash_t));
02190         line->next = vote_rs->microdesc;
02191         line->microdesc_hash_line = tor_strdup(t->args[0]);
02192         vote_rs->microdesc = line;
02193       }
02194     } SMARTLIST_FOREACH_END(t);
02195   } else if (flav == FLAV_MICRODESC) {
02196     tok = find_opt_by_keyword(tokens, K_M);
02197     if (tok) {
02198       tor_assert(tok->n_args);
02199       if (digest256_from_base64(rs->descriptor_digest, tok->args[0])) {
02200         log_warn(LD_DIR, "Error decoding microdescriptor digest %s",
02201                  escaped(tok->args[0]));
02202         goto err;
02203       }
02204     }
02205   }
02206 
02207   if (!strcasecmp(rs->nickname, UNNAMED_ROUTER_NICKNAME))
02208     rs->is_named = 0;
02209 
02210   goto done;
02211  err:
02212   dump_desc(s_dup, "routerstatus entry");
02213   if (rs && !vote_rs)
02214     routerstatus_free(rs);
02215   rs = NULL;
02216  done:
02217   SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
02218   smartlist_clear(tokens);
02219   if (area) {
02220     DUMP_AREA(area, "routerstatus entry");
02221     memarea_clear(area);
02222   }
02223   *s = eos;
02224 
02225   return rs;
02226 }
02227 
02229 int
02230 compare_routerstatus_entries(const void **_a, const void **_b)
02231 {
02232   const routerstatus_t *a = *_a, *b = *_b;
02233   return fast_memcmp(a->identity_digest, b->identity_digest, DIGEST_LEN);
02234 }
02235 
02237 static void
02238 _free_duplicate_routerstatus_entry(void *e)
02239 {
02240   log_warn(LD_DIR,
02241            "Network-status has two entries for the same router. "
02242            "Dropping one.");
02243   routerstatus_free(e);
02244 }
02245 
02251 networkstatus_v2_t *
02252 networkstatus_v2_parse_from_string(const char *s)
02253 {
02254   const char *eos, *s_dup = s;
02255   smartlist_t *tokens = smartlist_new();
02256   smartlist_t *footer_tokens = smartlist_new();
02257   networkstatus_v2_t *ns = NULL;
02258   char ns_digest[DIGEST_LEN];
02259   char tmp_digest[DIGEST_LEN];
02260   struct in_addr in;
02261   directory_token_t *tok;
02262   int i;
02263   memarea_t *area = NULL;
02264 
02265   if (router_get_networkstatus_v2_hash(s, ns_digest)) {
02266     log_warn(LD_DIR, "Unable to compute digest of network-status");
02267     goto err;
02268   }
02269 
02270   area = memarea_new();
02271   eos = find_start_of_next_routerstatus(s);
02272   if (tokenize_string(area, s, eos, tokens, netstatus_token_table,0)) {
02273     log_warn(LD_DIR, "Error tokenizing network-status header.");
02274     goto err;
02275   }
02276   ns = tor_malloc_zero(sizeof(networkstatus_v2_t));
02277   memcpy(ns->networkstatus_digest, ns_digest, DIGEST_LEN);
02278 
02279   tok = find_by_keyword(tokens, K_NETWORK_STATUS_VERSION);
02280   tor_assert(tok->n_args >= 1);
02281   if (strcmp(tok->args[0], "2")) {
02282     log_warn(LD_BUG, "Got a non-v2 networkstatus. Version was "
02283              "%s", escaped(tok->args[0]));
02284     goto err;
02285   }
02286 
02287   tok = find_by_keyword(tokens, K_DIR_SOURCE);
02288   tor_assert(tok->n_args >= 3);
02289   ns->source_address = tor_strdup(tok->args[0]);
02290   if (tor_inet_aton(tok->args[1], &in) == 0) {
02291     log_warn(LD_DIR, "Error parsing network-status source address %s",
02292              escaped(tok->args[1]));
02293     goto err;
02294   }
02295   ns->source_addr = ntohl(in.s_addr);
02296   ns->source_dirport =
02297     (uint16_t) tor_parse_long(tok->args[2],10,0,65535,NULL,NULL);
02298   if (ns->source_dirport == 0) {
02299     log_warn(LD_DIR, "Directory source without dirport; skipping.");
02300     goto err;
02301   }
02302 
02303   tok = find_by_keyword(tokens, K_FINGERPRINT);
02304   tor_assert(tok->n_args);
02305   if (base16_decode(ns->identity_digest, DIGEST_LEN, tok->args[0],
02306                     strlen(tok->args[0]))) {
02307     log_warn(LD_DIR, "Couldn't decode networkstatus fingerprint %s",
02308              escaped(tok->args[0]));
02309     goto err;
02310   }
02311 
02312   if ((tok = find_opt_by_keyword(tokens, K_CONTACT))) {
02313     tor_assert(tok->n_args);
02314     ns->contact = tor_strdup(tok->args[0]);
02315   }
02316 
02317   tok = find_by_keyword(tokens, K_DIR_SIGNING_KEY);
02318   tor_assert(tok->key);
02319   ns->signing_key = tok->key;
02320   tok->key = NULL;
02321 
02322   if (crypto_pk_get_digest(ns->signing_key, tmp_digest)<0) {
02323     log_warn(LD_DIR, "Couldn't compute signing key digest");
02324     goto err;
02325   }
02326   if (tor_memneq(tmp_digest, ns->identity_digest, DIGEST_LEN)) {
02327     log_warn(LD_DIR,
02328              "network-status fingerprint did not match dir-signing-key");
02329     goto err;
02330   }
02331 
02332   if ((tok = find_opt_by_keyword(tokens, K_DIR_OPTIONS))) {
02333     for (i=0; i < tok->n_args; ++i) {
02334       if (!strcmp(tok->args[i], "Names"))
02335         ns->binds_names = 1;
02336       if (!strcmp(tok->args[i], "Versions"))
02337         ns->recommends_versions = 1;
02338       if (!strcmp(tok->args[i], "BadExits"))
02339         ns->lists_bad_exits = 1;
02340       if (!strcmp(tok->args[i], "BadDirectories"))
02341         ns->lists_bad_directories = 1;
02342     }
02343   }
02344 
02345   if (ns->recommends_versions) {
02346     if (!(tok = find_opt_by_keyword(tokens, K_CLIENT_VERSIONS))) {
02347       log_warn(LD_DIR, "Missing client-versions on versioning directory");
02348       goto err;
02349     }
02350     ns->client_versions = tor_strdup(tok->args[0]);
02351 
02352     if (!(tok = find_opt_by_keyword(tokens, K_SERVER_VERSIONS)) ||
02353         tok->n_args<1) {
02354       log_warn(LD_DIR, "Missing server-versions on versioning directory");
02355       goto err;
02356     }
02357     ns->server_versions = tor_strdup(tok->args[0]);
02358   }
02359 
02360   tok = find_by_keyword(tokens, K_PUBLISHED);
02361   tor_assert(tok->n_args == 1);
02362   if (parse_iso_time(tok->args[0], &ns->published_on) < 0) {
02363      goto err;
02364   }
02365 
02366   ns->entries = smartlist_new();
02367   s = eos;
02368   SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
02369   smartlist_clear(tokens);
02370   memarea_clear(area);
02371   while (!strcmpstart(s, "r ")) {
02372     routerstatus_t *rs;
02373     if ((rs = routerstatus_parse_entry_from_string(area, &s, tokens,
02374                                                    NULL, NULL, 0, 0)))
02375       smartlist_add(ns->entries, rs);
02376   }
02377   smartlist_sort(ns->entries, compare_routerstatus_entries);
02378   smartlist_uniq(ns->entries, compare_routerstatus_entries,
02379                  _free_duplicate_routerstatus_entry);
02380 
02381   if (tokenize_string(area,s, NULL, footer_tokens, dir_footer_token_table,0)) {
02382     log_warn(LD_DIR, "Error tokenizing network-status footer.");
02383     goto err;
02384   }
02385   if (smartlist_len(footer_tokens) < 1) {
02386     log_warn(LD_DIR, "Too few items in network-status footer.");
02387     goto err;
02388   }
02389   tok = smartlist_get(footer_tokens, smartlist_len(footer_tokens)-1);
02390   if (tok->tp != K_DIRECTORY_SIGNATURE) {
02391     log_warn(LD_DIR,
02392              "Expected network-status footer to end with a signature.");
02393     goto err;
02394   }
02395 
02396   note_crypto_pk_op(VERIFY_DIR);
02397   if (check_signature_token(ns_digest, DIGEST_LEN, tok, ns->signing_key, 0,
02398                             "network-status") < 0)
02399     goto err;
02400 
02401   goto done;
02402  err:
02403   dump_desc(s_dup, "v2 networkstatus");
02404   networkstatus_v2_free(ns);
02405   ns = NULL;
02406  done:
02407   SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
02408   smartlist_free(tokens);
02409   SMARTLIST_FOREACH(footer_tokens, directory_token_t *, t, token_clear(t));
02410   smartlist_free(footer_tokens);
02411   if (area) {
02412     DUMP_AREA(area, "v2 networkstatus");
02413     memarea_drop_all(area);
02414   }
02415   return ns;
02416 }
02417 
02419 int
02420 networkstatus_verify_bw_weights(networkstatus_t *ns)
02421 {
02422   int64_t weight_scale;
02423   int64_t G=0, M=0, E=0, D=0, T=0;
02424   double Wgg, Wgm, Wgd, Wmg, Wmm, Wme, Wmd, Weg, Wem, Wee, Wed;
02425   double Gtotal=0, Mtotal=0, Etotal=0;
02426   const char *casename = NULL;
02427   int valid = 1;
02428 
02429   weight_scale = circuit_build_times_get_bw_scale(ns);
02430   Wgg = networkstatus_get_bw_weight(ns, "Wgg", -1);
02431   Wgm = networkstatus_get_bw_weight(ns, "Wgm", -1);
02432   Wgd = networkstatus_get_bw_weight(ns, "Wgd", -1);
02433   Wmg = networkstatus_get_bw_weight(ns, "Wmg", -1);
02434   Wmm = networkstatus_get_bw_weight(ns, "Wmm", -1);
02435   Wme = networkstatus_get_bw_weight(ns, "Wme", -1);
02436   Wmd = networkstatus_get_bw_weight(ns, "Wmd", -1);
02437   Weg = networkstatus_get_bw_weight(ns, "Weg", -1);
02438   Wem = networkstatus_get_bw_weight(ns, "Wem", -1);
02439   Wee = networkstatus_get_bw_weight(ns, "Wee", -1);
02440   Wed = networkstatus_get_bw_weight(ns, "Wed", -1);
02441 
02442   if (Wgg<0 || Wgm<0 || Wgd<0 || Wmg<0 || Wmm<0 || Wme<0 || Wmd<0 || Weg<0
02443           || Wem<0 || Wee<0 || Wed<0) {
02444     log_warn(LD_BUG, "No bandwidth weights produced in consensus!");
02445     return 0;
02446   }
02447 
02448   // First, sanity check basic summing properties that hold for all cases
02449   // We use > 1 as the check for these because they are computed as integers.
02450   // Sometimes there are rounding errors.
02451   if (fabs(Wmm - weight_scale) > 1) {
02452     log_warn(LD_BUG, "Wmm=%f != "I64_FORMAT,
02453              Wmm, I64_PRINTF_ARG(weight_scale));
02454     valid = 0;
02455   }
02456 
02457   if (fabs(Wem - Wee) > 1) {
02458     log_warn(LD_BUG, "Wem=%f != Wee=%f", Wem, Wee);
02459     valid = 0;
02460   }
02461 
02462   if (fabs(Wgm - Wgg) > 1) {
02463     log_warn(LD_BUG, "Wgm=%f != Wgg=%f", Wgm, Wgg);
02464     valid = 0;
02465   }
02466 
02467   if (fabs(Weg - Wed) > 1) {
02468     log_warn(LD_BUG, "Wed=%f != Weg=%f", Wed, Weg);
02469     valid = 0;
02470   }
02471 
02472   if (fabs(Wgg + Wmg - weight_scale) > 0.001*weight_scale) {
02473     log_warn(LD_BUG, "Wgg=%f != "I64_FORMAT" - Wmg=%f", Wgg,
02474              I64_PRINTF_ARG(weight_scale), Wmg);
02475     valid = 0;
02476   }
02477 
02478   if (fabs(Wee + Wme - weight_scale) > 0.001*weight_scale) {
02479     log_warn(LD_BUG, "Wee=%f != "I64_FORMAT" - Wme=%f", Wee,
02480              I64_PRINTF_ARG(weight_scale), Wme);
02481     valid = 0;
02482   }
02483 
02484   if (fabs(Wgd + Wmd + Wed - weight_scale) > 0.001*weight_scale) {
02485     log_warn(LD_BUG, "Wgd=%f + Wmd=%f + Wed=%f != "I64_FORMAT,
02486              Wgd, Wmd, Wed, I64_PRINTF_ARG(weight_scale));
02487     valid = 0;
02488   }
02489 
02490   Wgg /= weight_scale;
02491   Wgm /= weight_scale;
02492   Wgd /= weight_scale;
02493 
02494   Wmg /= weight_scale;
02495   Wmm /= weight_scale;
02496   Wme /= weight_scale;
02497   Wmd /= weight_scale;
02498 
02499   Weg /= weight_scale;
02500   Wem /= weight_scale;
02501   Wee /= weight_scale;
02502   Wed /= weight_scale;
02503 
02504   // Then, gather G, M, E, D, T to determine case
02505   SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) {
02506     if (rs->has_bandwidth) {
02507       T += rs->bandwidth;
02508       if (rs->is_exit && rs->is_possible_guard) {
02509         D += rs->bandwidth;
02510         Gtotal += Wgd*rs->bandwidth;
02511         Mtotal += Wmd*rs->bandwidth;
02512         Etotal += Wed*rs->bandwidth;
02513       } else if (rs->is_exit) {
02514         E += rs->bandwidth;
02515         Mtotal += Wme*rs->bandwidth;
02516         Etotal += Wee*rs->bandwidth;
02517       } else if (rs->is_possible_guard) {
02518         G += rs->bandwidth;
02519         Gtotal += Wgg*rs->bandwidth;
02520         Mtotal += Wmg*rs->bandwidth;
02521       } else {
02522         M += rs->bandwidth;
02523         Mtotal += Wmm*rs->bandwidth;
02524       }
02525     } else {
02526       log_warn(LD_BUG, "Missing consensus bandwidth for router %s",
02527                routerstatus_describe(rs));
02528     }
02529   } SMARTLIST_FOREACH_END(rs);
02530 
02531   // Finally, check equality conditions depending upon case 1, 2 or 3
02532   // Full equality cases: 1, 3b
02533   // Partial equality cases: 2b (E=G), 3a (M=E)
02534   // Fully unknown: 2a
02535   if (3*E >= T && 3*G >= T) {
02536     // Case 1: Neither are scarce
02537     casename = "Case 1";
02538     if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
02539       log_warn(LD_DIR,
02540                "Bw Weight Failure for %s: Etotal %f != Mtotal %f. "
02541                "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
02542                " T="I64_FORMAT". "
02543                "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02544                casename, Etotal, Mtotal,
02545                I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02546                I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02547                Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02548       valid = 0;
02549     }
02550     if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
02551       log_warn(LD_DIR,
02552                "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
02553                "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
02554                " T="I64_FORMAT". "
02555                "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02556                casename, Etotal, Gtotal,
02557                I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02558                I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02559                Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02560       valid = 0;
02561     }
02562     if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
02563       log_warn(LD_DIR,
02564                "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. "
02565                "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
02566                " T="I64_FORMAT". "
02567                "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02568                casename, Mtotal, Gtotal,
02569                I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02570                I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02571                Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02572       valid = 0;
02573     }
02574   } else if (3*E < T && 3*G < T) {
02575     int64_t R = MIN(E, G);
02576     int64_t S = MAX(E, G);
02577     /*
02578      * Case 2: Both Guards and Exits are scarce
02579      * Balance D between E and G, depending upon
02580      * D capacity and scarcity. Devote no extra
02581      * bandwidth to middle nodes.
02582      */
02583     if (R+D < S) { // Subcase a
02584       double Rtotal, Stotal;
02585       if (E < G) {
02586         Rtotal = Etotal;
02587         Stotal = Gtotal;
02588       } else {
02589         Rtotal = Gtotal;
02590         Stotal = Etotal;
02591       }
02592       casename = "Case 2a";
02593       // Rtotal < Stotal
02594       if (Rtotal > Stotal) {
02595         log_warn(LD_DIR,
02596                    "Bw Weight Failure for %s: Rtotal %f > Stotal %f. "
02597                    "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
02598                    " T="I64_FORMAT". "
02599                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02600                    casename, Rtotal, Stotal,
02601                    I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02602                    I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02603                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02604         valid = 0;
02605       }
02606       // Rtotal < T/3
02607       if (3*Rtotal > T) {
02608         log_warn(LD_DIR,
02609                    "Bw Weight Failure for %s: 3*Rtotal %f > T "
02610                    I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
02611                    " D="I64_FORMAT" T="I64_FORMAT". "
02612                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02613                    casename, Rtotal*3, I64_PRINTF_ARG(T),
02614                    I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02615                    I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02616                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02617         valid = 0;
02618       }
02619       // Stotal < T/3
02620       if (3*Stotal > T) {
02621         log_warn(LD_DIR,
02622                    "Bw Weight Failure for %s: 3*Stotal %f > T "
02623                    I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
02624                    " D="I64_FORMAT" T="I64_FORMAT". "
02625                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02626                    casename, Stotal*3, I64_PRINTF_ARG(T),
02627                    I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02628                    I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02629                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02630         valid = 0;
02631       }
02632       // Mtotal > T/3
02633       if (3*Mtotal < T) {
02634         log_warn(LD_DIR,
02635                    "Bw Weight Failure for %s: 3*Mtotal %f < T "
02636                    I64_FORMAT". "
02637                    "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
02638                    " T="I64_FORMAT". "
02639                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02640                    casename, Mtotal*3, I64_PRINTF_ARG(T),
02641                    I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02642                    I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02643                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02644         valid = 0;
02645       }
02646     } else { // Subcase b: R+D > S
02647       casename = "Case 2b";
02648 
02649       /* Check the rare-M redirect case. */
02650       if (D != 0 && 3*M < T) {
02651         casename = "Case 2b (balanced)";
02652         if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
02653           log_warn(LD_DIR,
02654                    "Bw Weight Failure for %s: Etotal %f != Mtotal %f. "
02655                    "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
02656                    " T="I64_FORMAT". "
02657                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02658                    casename, Etotal, Mtotal,
02659                    I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02660                    I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02661                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02662           valid = 0;
02663         }
02664         if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
02665           log_warn(LD_DIR,
02666                    "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
02667                    "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
02668                    " T="I64_FORMAT". "
02669                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02670                    casename, Etotal, Gtotal,
02671                    I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02672                    I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02673                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02674           valid = 0;
02675         }
02676         if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
02677           log_warn(LD_DIR,
02678                    "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. "
02679                    "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
02680                    " T="I64_FORMAT". "
02681                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02682                    casename, Mtotal, Gtotal,
02683                    I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02684                    I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02685                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02686           valid = 0;
02687         }
02688       } else {
02689         if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
02690           log_warn(LD_DIR,
02691                    "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
02692                    "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
02693                    " T="I64_FORMAT". "
02694                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02695                    casename, Etotal, Gtotal,
02696                    I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02697                    I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02698                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02699           valid = 0;
02700         }
02701       }
02702     }
02703   } else { // if (E < T/3 || G < T/3) {
02704     int64_t S = MIN(E, G);
02705     int64_t NS = MAX(E, G);
02706     if (3*(S+D) < T) { // Subcase a:
02707       double Stotal;
02708       double NStotal;
02709       if (G < E) {
02710         casename = "Case 3a (G scarce)";
02711         Stotal = Gtotal;
02712         NStotal = Etotal;
02713       } else { // if (G >= E) {
02714         casename = "Case 3a (E scarce)";
02715         NStotal = Gtotal;
02716         Stotal = Etotal;
02717       }
02718       // Stotal < T/3
02719       if (3*Stotal > T) {
02720         log_warn(LD_DIR,
02721                    "Bw Weight Failure for %s: 3*Stotal %f > T "
02722                    I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
02723                    " D="I64_FORMAT" T="I64_FORMAT". "
02724                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02725                    casename, Stotal*3, I64_PRINTF_ARG(T),
02726                    I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02727                    I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02728                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02729         valid = 0;
02730       }
02731       if (NS >= M) {
02732         if (fabs(NStotal-Mtotal) > 0.01*MAX(NStotal,Mtotal)) {
02733           log_warn(LD_DIR,
02734                    "Bw Weight Failure for %s: NStotal %f != Mtotal %f. "
02735                    "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
02736                    " T="I64_FORMAT". "
02737                    "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02738                    casename, NStotal, Mtotal,
02739                    I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02740                    I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02741                    Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02742           valid = 0;
02743         }
02744       } else {
02745         // if NS < M, NStotal > T/3 because only one of G or E is scarce
02746         if (3*NStotal < T) {
02747           log_warn(LD_DIR,
02748                      "Bw Weight Failure for %s: 3*NStotal %f < T "
02749                      I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT
02750                      " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT". "
02751                      "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02752                      casename, NStotal*3, I64_PRINTF_ARG(T),
02753                      I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02754                      I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02755                      Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02756           valid = 0;
02757         }
02758       }
02759     } else { // Subcase b: S+D >= T/3
02760       casename = "Case 3b";
02761       if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
02762         log_warn(LD_DIR,
02763                  "Bw Weight Failure for %s: Etotal %f != Mtotal %f. "
02764                  "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
02765                  " T="I64_FORMAT". "
02766                  "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02767                  casename, Etotal, Mtotal,
02768                  I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02769                  I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02770                  Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02771         valid = 0;
02772       }
02773       if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
02774         log_warn(LD_DIR,
02775                  "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
02776                  "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
02777                  " T="I64_FORMAT". "
02778                  "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02779                  casename, Etotal, Gtotal,
02780                  I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02781                  I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02782                  Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02783         valid = 0;
02784       }
02785       if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
02786         log_warn(LD_DIR,
02787                  "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. "
02788                  "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
02789                  " T="I64_FORMAT". "
02790                  "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
02791                  casename, Mtotal, Gtotal,
02792                  I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
02793                  I64_PRINTF_ARG(D), I64_PRINTF_ARG(T),
02794                  Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
02795         valid = 0;
02796       }
02797     }
02798   }
02799 
02800   if (valid)
02801     log_notice(LD_DIR, "Bandwidth-weight %s is verified and valid.",
02802                casename);
02803 
02804   return valid;
02805 }
02806 
02809 networkstatus_t *
02810 networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
02811                                      networkstatus_type_t ns_type)
02812 {
02813   smartlist_t *tokens = smartlist_new();
02814   smartlist_t *rs_tokens = NULL, *footer_tokens = NULL;
02815   networkstatus_voter_info_t *voter = NULL;
02816   networkstatus_t *ns = NULL;
02817   digests_t ns_digests;
02818   const char *cert, *end_of_header, *end_of_footer, *s_dup = s;
02819   directory_token_t *tok;
02820   int ok;
02821   struct in_addr in;
02822   int i, inorder, n_signatures = 0;
02823   memarea_t *area = NULL, *rs_area = NULL;
02824   consensus_flavor_t flav = FLAV_NS;
02825   char *last_kwd=NULL;
02826 
02827   tor_assert(s);
02828 
02829   if (eos_out)
02830     *eos_out = NULL;
02831 
02832   if (router_get_networkstatus_v3_hashes(s, &ns_digests)) {
02833     log_warn(LD_DIR, "Unable to compute digest of network-status");
02834     goto err;
02835   }
02836 
02837   area = memarea_new();
02838   end_of_header = find_start_of_next_routerstatus(s);
02839   if (tokenize_string(area, s, end_of_header, tokens,
02840                       (ns_type == NS_TYPE_CONSENSUS) ?
02841                       networkstatus_consensus_token_table :
02842                       networkstatus_token_table, 0)) {
02843     log_warn(LD_DIR, "Error tokenizing network-status vote header");
02844     goto err;
02845   }
02846 
02847   ns = tor_malloc_zero(sizeof(networkstatus_t));
02848   memcpy(&ns->digests, &ns_digests, sizeof(ns_digests));
02849 
02850   tok = find_by_keyword(tokens, K_NETWORK_STATUS_VERSION);
02851   tor_assert(tok);
02852   if (tok->n_args > 1) {
02853     int flavor = networkstatus_parse_flavor_name(tok->args[1]);
02854     if (flavor < 0) {
02855       log_warn(LD_DIR, "Can't parse document with unknown flavor %s",
02856                escaped(tok->args[2]));
02857       goto err;
02858     }
02859     ns->flavor = flav = flavor;
02860   }
02861   if (flav != FLAV_NS && ns_type != NS_TYPE_CONSENSUS) {
02862     log_warn(LD_DIR, "Flavor found on non-consensus networkstatus.");
02863     goto err;
02864   }
02865 
02866   if (ns_type != NS_TYPE_CONSENSUS) {
02867     const char *end_of_cert = NULL;
02868     if (!(cert = strstr(s, "\ndir-key-certificate-version")))
02869       goto err;
02870     ++cert;
02871     ns->cert = authority_cert_parse_from_string(cert, &end_of_cert);
02872     if (!ns->cert || !end_of_cert || end_of_cert > end_of_header)
02873       goto err;
02874   }
02875 
02876   tok = find_by_keyword(tokens, K_VOTE_STATUS);
02877   tor_assert(tok->n_args);
02878   if (!strcmp(tok->args[0], "vote")) {
02879     ns->type = NS_TYPE_VOTE;
02880   } else if (!strcmp(tok->args[0], "consensus")) {
02881     ns->type = NS_TYPE_CONSENSUS;
02882   } else if (!strcmp(tok->args[0], "opinion")) {
02883     ns->type = NS_TYPE_OPINION;
02884   } else {
02885     log_warn(LD_DIR, "Unrecognized vote status %s in network-status",
02886              escaped(tok->args[0]));
02887     goto err;
02888   }
02889   if (ns_type != ns->type) {
02890     log_warn(LD_DIR, "Got the wrong kind of v3 networkstatus.");
02891     goto err;
02892   }
02893 
02894   if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_OPINION) {
02895     tok = find_by_keyword(tokens, K_PUBLISHED);
02896     if (parse_iso_time(tok->args[0], &ns->published))
02897       goto err;
02898 
02899     ns->supported_methods = smartlist_new();
02900     tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHODS);
02901     if (tok) {
02902       for (i=0; i < tok->n_args; ++i)
02903         smartlist_add(ns->supported_methods, tor_strdup(tok->args[i]));
02904     } else {
02905       smartlist_add(ns->supported_methods, tor_strdup("1"));
02906     }
02907   } else {
02908     tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHOD);
02909     if (tok) {
02910       ns->consensus_method = (int)tor_parse_long(tok->args[0], 10, 1, INT_MAX,
02911                                                  &ok, NULL);
02912       if (!ok)
02913         goto err;
02914     } else {
02915       ns->consensus_method = 1;
02916     }
02917   }
02918 
02919   tok = find_by_keyword(tokens, K_VALID_AFTER);
02920   if (parse_iso_time(tok->args[0], &ns->valid_after))
02921     goto err;
02922 
02923   tok = find_by_keyword(tokens, K_FRESH_UNTIL);
02924   if (parse_iso_time(tok->args[0], &ns->fresh_until))
02925     goto err;
02926 
02927   tok = find_by_keyword(tokens, K_VALID_UNTIL);
02928   if (parse_iso_time(tok->args[0], &ns->valid_until))
02929     goto err;
02930 
02931   tok = find_by_keyword(tokens, K_VOTING_DELAY);
02932   tor_assert(tok->n_args >= 2);
02933   ns->vote_seconds =
02934     (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &ok, NULL);
02935   if (!ok)
02936     goto err;
02937   ns->dist_seconds =
02938     (int) tor_parse_long(tok->args[1], 10, 0, INT_MAX, &ok, NULL);
02939   if (!ok)
02940     goto err;
02941   if (ns->valid_after + MIN_VOTE_INTERVAL > ns->fresh_until) {
02942     log_warn(LD_DIR, "Vote/consensus freshness interval is too short");
02943     goto err;
02944   }
02945   if (ns->valid_after + MIN_VOTE_INTERVAL*2 > ns->valid_until) {
02946     log_warn(LD_DIR, "Vote/consensus liveness interval is too short");
02947     goto err;
02948   }
02949   if (ns->vote_seconds < MIN_VOTE_SECONDS) {
02950     log_warn(LD_DIR, "Vote seconds is too short");
02951     goto err;
02952   }
02953   if (ns->dist_seconds < MIN_DIST_SECONDS) {
02954     log_warn(LD_DIR, "Dist seconds is too short");
02955     goto err;
02956   }
02957 
02958   if ((tok = find_opt_by_keyword(tokens, K_CLIENT_VERSIONS))) {
02959     ns->client_versions = tor_strdup(tok->args[0]);
02960   }
02961   if ((tok = find_opt_by_keyword(tokens, K_SERVER_VERSIONS))) {
02962     ns->server_versions = tor_strdup(tok->args[0]);
02963   }
02964 
02965   tok = find_by_keyword(tokens, K_KNOWN_FLAGS);
02966   ns->known_flags = smartlist_new();
02967   inorder = 1;
02968   for (i = 0; i < tok->n_args; ++i) {
02969     smartlist_add(ns->known_flags, tor_strdup(tok->args[i]));
02970     if (i>0 && strcmp(tok->args[i-1], tok->args[i])>= 0) {
02971       log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]);
02972       inorder = 0;
02973     }
02974   }
02975   if (!inorder) {
02976     log_warn(LD_DIR, "known-flags not in order");
02977     goto err;
02978   }
02979 
02980   tok = find_opt_by_keyword(tokens, K_PARAMS);
02981   if (tok) {
02982     int any_dups = 0;
02983     inorder = 1;
02984     ns->net_params = smartlist_new();
02985     for (i = 0; i < tok->n_args; ++i) {
02986       int ok=0;
02987       char *eq = strchr(tok->args[i], '=');
02988       size_t eq_pos;
02989       if (!eq) {
02990         log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
02991         goto err;
02992       }
02993       eq_pos = eq-tok->args[i];
02994       tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL);
02995       if (!ok) {
02996         log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
02997         goto err;
02998       }
02999       if (i > 0 && strcmp(tok->args[i-1], tok->args[i]) >= 0) {
03000         log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]);
03001         inorder = 0;
03002       }
03003       if (last_kwd && eq_pos == strlen(last_kwd) &&
03004           fast_memeq(last_kwd, tok->args[i], eq_pos)) {
03005         log_warn(LD_DIR, "Duplicate value for %s parameter",
03006                  escaped(tok->args[i]));
03007         any_dups = 1;
03008       }
03009       tor_free(last_kwd);
03010       last_kwd = tor_strndup(tok->args[i], eq_pos);
03011       smartlist_add(ns->net_params, tor_strdup(tok->args[i]));
03012     }
03013     if (!inorder) {
03014       log_warn(LD_DIR, "params not in order");
03015       goto err;
03016     }
03017     if (any_dups) {
03018       log_warn(LD_DIR, "Duplicate in parameters");
03019       goto err;
03020     }
03021   }
03022 
03023   ns->voters = smartlist_new();
03024 
03025   SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) {
03026     tok = _tok;
03027     if (tok->tp == K_DIR_SOURCE) {
03028       tor_assert(tok->n_args >= 6);
03029 
03030       if (voter)
03031         smartlist_add(ns->voters, voter);
03032       voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
03033       voter->sigs = smartlist_new();
03034       if (ns->type != NS_TYPE_CONSENSUS)
03035         memcpy(voter->vote_digest, ns_digests.d[DIGEST_SHA1], DIGEST_LEN);
03036 
03037       voter->nickname = tor_strdup(tok->args[0]);
03038       if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
03039           base16_decode(voter->identity_digest, sizeof(voter->identity_digest),
03040                         tok->args[1], HEX_DIGEST_LEN) < 0) {
03041         log_warn(LD_DIR, "Error decoding identity digest %s in "
03042                  "network-status vote.", escaped(tok->args[1]));
03043         goto err;
03044       }
03045       if (ns->type != NS_TYPE_CONSENSUS &&
03046           tor_memneq(ns->cert->cache_info.identity_digest,
03047                  voter->identity_digest, DIGEST_LEN)) {
03048         log_warn(LD_DIR,"Mismatch between identities in certificate and vote");
03049         goto err;
03050       }
03051       voter->address = tor_strdup(tok->args[2]);
03052       if (!tor_inet_aton(tok->args[3], &in)) {
03053         log_warn(LD_DIR, "Error decoding IP address %s in network-status.",
03054                  escaped(tok->args[3]));
03055         goto err;
03056       }
03057       voter->addr = ntohl(in.s_addr);
03058       voter->dir_port = (uint16_t)
03059         tor_parse_long(tok->args[4], 10, 0, 65535, &ok, NULL);
03060       if (!ok)
03061         goto err;
03062       voter->or_port = (uint16_t)
03063         tor_parse_long(tok->args[5], 10, 0, 65535, &ok, NULL);
03064       if (!ok)
03065         goto err;
03066     } else if (tok->tp == K_CONTACT) {
03067       if (!voter || voter->contact) {
03068         log_warn(LD_DIR, "contact element is out of place.");
03069         goto err;
03070       }
03071       voter->contact = tor_strdup(tok->args[0]);
03072     } else if (tok->tp == K_VOTE_DIGEST) {
03073       tor_assert(ns->type == NS_TYPE_CONSENSUS);
03074       tor_assert(tok->n_args >= 1);
03075       if (!voter || ! tor_digest_is_zero(voter->vote_digest)) {
03076         log_warn(LD_DIR, "vote-digest element is out of place.");
03077         goto err;
03078       }
03079       if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
03080         base16_decode(voter->vote_digest, sizeof(voter->vote_digest),
03081                       tok->args[0], HEX_DIGEST_LEN) < 0) {
03082         log_warn(LD_DIR, "Error decoding vote digest %s in "
03083                  "network-status consensus.", escaped(tok->args[0]));
03084         goto err;
03085       }
03086     }
03087   } SMARTLIST_FOREACH_END(_tok);
03088   if (voter) {
03089     smartlist_add(ns->voters, voter);
03090     voter = NULL;
03091   }
03092   if (smartlist_len(ns->voters) == 0) {
03093     log_warn(LD_DIR, "Missing dir-source elements in a vote networkstatus.");
03094     goto err;
03095   } else if (ns->type != NS_TYPE_CONSENSUS && smartlist_len(ns->voters) != 1) {
03096     log_warn(LD_DIR, "Too many dir-source elements in a vote networkstatus.");
03097     goto err;
03098   }
03099 
03100   if (ns->type != NS_TYPE_CONSENSUS &&
03101       (tok = find_opt_by_keyword(tokens, K_LEGACY_DIR_KEY))) {
03102     int bad = 1;
03103     if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {
03104       networkstatus_voter_info_t *voter = smartlist_get(ns->voters, 0);
03105       if (base16_decode(voter->legacy_id_digest, DIGEST_LEN,
03106                         tok->args[0], HEX_DIGEST_LEN)<0)
03107         bad = 1;
03108       else
03109         bad = 0;
03110     }
03111     if (bad) {
03112       log_warn(LD_DIR, "Invalid legacy key digest %s on vote.",
03113                escaped(tok->args[0]));
03114     }
03115   }
03116 
03117   /* Parse routerstatus lines. */
03118   rs_tokens = smartlist_new();
03119   rs_area = memarea_new();
03120   s = end_of_header;
03121   ns->routerstatus_list = smartlist_new();
03122 
03123   while (!strcmpstart(s, "r ")) {
03124     if (ns->type != NS_TYPE_CONSENSUS) {
03125       vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t));
03126       if (routerstatus_parse_entry_from_string(rs_area, &s, rs_tokens, ns,
03127                                                rs, 0, 0))
03128         smartlist_add(ns->routerstatus_list, rs);
03129       else {
03130         tor_free(rs->version);
03131         tor_free(rs);
03132       }
03133     } else {
03134       routerstatus_t *rs;
03135       if ((rs = routerstatus_parse_entry_from_string(rs_area, &s, rs_tokens,
03136                                                      NULL, NULL,
03137                                                      ns->consensus_method,
03138                                                      flav)))
03139         smartlist_add(ns->routerstatus_list, rs);
03140     }
03141   }
03142   for (i = 1; i < smartlist_len(ns->routerstatus_list); ++i) {
03143     routerstatus_t *rs1, *rs2;
03144     if (ns->type != NS_TYPE_CONSENSUS) {
03145       vote_routerstatus_t *a = smartlist_get(ns->routerstatus_list, i-1);
03146       vote_routerstatus_t *b = smartlist_get(ns->routerstatus_list, i);
03147       rs1 = &a->status; rs2 = &b->status;
03148     } else {
03149       rs1 = smartlist_get(ns->routerstatus_list, i-1);
03150       rs2 = smartlist_get(ns->routerstatus_list, i);
03151     }
03152     if (fast_memcmp(rs1->identity_digest, rs2->identity_digest, DIGEST_LEN)
03153         >= 0) {
03154       log_warn(LD_DIR, "Vote networkstatus entries not sorted by identity "
03155                "digest");
03156       goto err;
03157     }
03158   }
03159 
03160   /* Parse footer; check signature. */
03161   footer_tokens = smartlist_new();
03162   if ((end_of_footer = strstr(s, "\nnetwork-status-version ")))
03163     ++end_of_footer;
03164   else
03165     end_of_footer = s + strlen(s);
03166   if (tokenize_string(area,s, end_of_footer, footer_tokens,
03167                       networkstatus_vote_footer_token_table, 0)) {
03168     log_warn(LD_DIR, "Error tokenizing network-status vote footer.");
03169     goto err;
03170   }
03171 
03172   {
03173     int found_sig = 0;
03174     SMARTLIST_FOREACH_BEGIN(footer_tokens, directory_token_t *, _tok) {
03175       tok = _tok;
03176       if (tok->tp == K_DIRECTORY_SIGNATURE)
03177         found_sig = 1;
03178       else if (found_sig) {
03179         log_warn(LD_DIR, "Extraneous token after first directory-signature");
03180         goto err;
03181       }
03182     } SMARTLIST_FOREACH_END(_tok);
03183   }
03184 
03185   if ((tok = find_opt_by_keyword(footer_tokens, K_DIRECTORY_FOOTER))) {
03186     if (tok != smartlist_get(footer_tokens, 0)) {
03187       log_warn(LD_DIR, "Misplaced directory-footer token");
03188       goto err;
03189     }
03190   }
03191 
03192   tok = find_opt_by_keyword(footer_tokens, K_BW_WEIGHTS);
03193   if (tok) {
03194     ns->weight_params = smartlist_new();
03195     for (i = 0; i < tok->n_args; ++i) {
03196       int ok=0;
03197       char *eq = strchr(tok->args[i], '=');
03198       if (!eq) {
03199         log_warn(LD_DIR, "Bad element '%s' in weight params",
03200                  escaped(tok->args[i]));
03201         goto err;
03202       }
03203       tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL);
03204       if (!ok) {
03205         log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
03206         goto err;
03207       }
03208       smartlist_add(ns->weight_params, tor_strdup(tok->args[i]));
03209     }
03210   }
03211 
03212   SMARTLIST_FOREACH_BEGIN(footer_tokens, directory_token_t *, _tok) {
03213     char declared_identity[DIGEST_LEN];
03214     networkstatus_voter_info_t *v;
03215     document_signature_t *sig;
03216     const char *id_hexdigest = NULL;
03217     const char *sk_hexdigest = NULL;
03218     digest_algorithm_t alg = DIGEST_SHA1;
03219     tok = _tok;
03220     if (tok->tp != K_DIRECTORY_SIGNATURE)
03221       continue;
03222     tor_assert(tok->n_args >= 2);
03223     if (tok->n_args == 2) {
03224       id_hexdigest = tok->args[0];
03225       sk_hexdigest = tok->args[1];
03226     } else {
03227       const char *algname = tok->args[0];
03228       int a;
03229       id_hexdigest = tok->args[1];
03230       sk_hexdigest = tok->args[2];
03231       a = crypto_digest_algorithm_parse_name(algname);
03232       if (a<0) {
03233         log_warn(LD_DIR, "Unknown digest algorithm %s; skipping",
03234                  escaped(algname));
03235         continue;
03236       }
03237       alg = a;
03238     }
03239 
03240     if (!tok->object_type ||
03241         strcmp(tok->object_type, "SIGNATURE") ||
03242         tok->object_size < 128 || tok->object_size > 512) {
03243       log_warn(LD_DIR, "Bad object type or length on directory-signature");
03244       goto err;
03245     }
03246 
03247     if (strlen(id_hexdigest) != HEX_DIGEST_LEN ||
03248         base16_decode(declared_identity, sizeof(declared_identity),
03249                       id_hexdigest, HEX_DIGEST_LEN) < 0) {
03250       log_warn(LD_DIR, "Error decoding declared identity %s in "
03251                "network-status vote.", escaped(id_hexdigest));
03252       goto err;
03253     }
03254     if (!(v = networkstatus_get_voter_by_id(ns, declared_identity))) {
03255       log_warn(LD_DIR, "ID on signature on network-status vote does not match "
03256                "any declared directory source.");
03257       goto err;
03258     }
03259     sig = tor_malloc_zero(sizeof(document_signature_t));
03260     memcpy(sig->identity_digest, v->identity_digest, DIGEST_LEN);
03261     sig->alg = alg;
03262     if (strlen(sk_hexdigest) != HEX_DIGEST_LEN ||
03263         base16_decode(sig->signing_key_digest, sizeof(sig->signing_key_digest),
03264                       sk_hexdigest, HEX_DIGEST_LEN) < 0) {
03265       log_warn(LD_DIR, "Error decoding declared signing key digest %s in "
03266                "network-status vote.", escaped(sk_hexdigest));
03267       tor_free(sig);
03268       goto err;
03269     }
03270 
03271     if (ns->type != NS_TYPE_CONSENSUS) {
03272       if (tor_memneq(declared_identity, ns->cert->cache_info.identity_digest,
03273                  DIGEST_LEN)) {
03274         log_warn(LD_DIR, "Digest mismatch between declared and actual on "
03275                  "network-status vote.");
03276         tor_free(sig);
03277         goto err;
03278       }
03279     }
03280 
03281     if (voter_get_sig_by_algorithm(v, sig->alg)) {
03282       /* We already parsed a vote with this algorithm from this voter. Use the
03283          first one. */
03284       log_fn(LOG_PROTOCOL_WARN, LD_DIR, "We received a networkstatus "
03285              "that contains two votes from the same voter with the same "
03286              "algorithm. Ignoring the second vote.");
03287       tor_free(sig);
03288       continue;
03289     }
03290 
03291     if (ns->type != NS_TYPE_CONSENSUS) {
03292       if (check_signature_token(ns_digests.d[DIGEST_SHA1], DIGEST_LEN,
03293                                 tok, ns->cert->signing_key, 0,
03294                                 "network-status vote")) {
03295         tor_free(sig);
03296         goto err;
03297       }
03298       sig->good_signature = 1;
03299     } else {
03300       if (tok->object_size >= INT_MAX || tok->object_size >= SIZE_T_CEILING) {
03301         tor_free(sig);
03302         goto err;
03303       }
03304       sig->signature = tor_memdup(tok->object_body, tok->object_size);
03305       sig->signature_len = (int) tok->object_size;
03306     }
03307     smartlist_add(v->sigs, sig);
03308 
03309     ++n_signatures;
03310   } SMARTLIST_FOREACH_END(_tok);
03311 
03312   if (! n_signatures) {
03313     log_warn(LD_DIR, "No signatures on networkstatus vote.");
03314     goto err;
03315   } else if (ns->type == NS_TYPE_VOTE && n_signatures != 1) {
03316     log_warn(LD_DIR, "Received more than one signature on a "
03317              "network-status vote.");
03318     goto err;
03319   }
03320 
03321   if (eos_out)
03322     *eos_out = end_of_footer;
03323 
03324   goto done;
03325  err:
03326   dump_desc(s_dup, "v3 networkstatus");
03327   networkstatus_vote_free(ns);
03328   ns = NULL;
03329  done:
03330   if (tokens) {
03331     SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
03332     smartlist_free(tokens);
03333   }
03334   if (voter) {
03335     if (voter->sigs) {
03336       SMARTLIST_FOREACH(voter->sigs, document_signature_t *, sig,
03337                         document_signature_free(sig));
03338       smartlist_free(voter->sigs);
03339     }
03340     tor_free(voter->nickname);
03341     tor_free(voter->address);
03342     tor_free(voter->contact);
03343     tor_free(voter);
03344   }
03345   if (rs_tokens) {
03346     SMARTLIST_FOREACH(rs_tokens, directory_token_t *, t, token_clear(t));
03347     smartlist_free(rs_tokens);
03348   }
03349   if (footer_tokens) {
03350     SMARTLIST_FOREACH(footer_tokens, directory_token_t *, t, token_clear(t));
03351     smartlist_free(footer_tokens);
03352   }
03353   if (area) {
03354     DUMP_AREA(area, "v3 networkstatus");
03355     memarea_drop_all(area);
03356   }
03357   if (rs_area)
03358     memarea_drop_all(rs_area);
03359   tor_free(last_kwd);
03360 
03361   return ns;
03362 }
03363 
03367 static digests_t *
03368 detached_get_digests(ns_detached_signatures_t *sigs, const char *flavor_name)
03369 {
03370   digests_t *d = strmap_get(sigs->digests, flavor_name);
03371   if (!d) {
03372     d = tor_malloc_zero(sizeof(digests_t));
03373     strmap_set(sigs->digests, flavor_name, d);
03374   }
03375   return d;
03376 }
03377 
03381 static smartlist_t *
03382 detached_get_signatures(ns_detached_signatures_t *sigs,
03383                         const char *flavor_name)
03384 {
03385   smartlist_t *sl = strmap_get(sigs->signatures, flavor_name);
03386   if (!sl) {
03387     sl = smartlist_new();
03388     strmap_set(sigs->signatures, flavor_name, sl);
03389   }
03390   return sl;
03391 }
03392 
03395 ns_detached_signatures_t *
03396 networkstatus_parse_detached_signatures(const char *s, const char *eos)
03397 {
03398   /* XXXX there is too much duplicate shared between this function and
03399    * networkstatus_parse_vote_from_string(). */
03400   directory_token_t *tok;
03401   memarea_t *area = NULL;
03402   digests_t *digests;
03403 
03404   smartlist_t *tokens = smartlist_new();
03405   ns_detached_signatures_t *sigs =
03406     tor_malloc_zero(sizeof(ns_detached_signatures_t));
03407   sigs->digests = strmap_new();
03408   sigs->signatures = strmap_new();
03409 
03410   if (!eos)
03411     eos = s + strlen(s);
03412 
03413   area = memarea_new();
03414   if (tokenize_string(area,s, eos, tokens,
03415                       networkstatus_detached_signature_token_table, 0)) {
03416     log_warn(LD_DIR, "Error tokenizing detached networkstatus signatures");
03417     goto err;
03418   }
03419 
03420   /* Grab all the digest-like tokens. */
03421   SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) {
03422     const char *algname;
03423     digest_algorithm_t alg;
03424     const char *flavor;
03425     const char *hexdigest;
03426     size_t expected_length;
03427 
03428     tok = _tok;
03429 
03430     if (tok->tp == K_CONSENSUS_DIGEST) {
03431       algname = "sha1";
03432       alg = DIGEST_SHA1;
03433       flavor = "ns";
03434       hexdigest = tok->args[0];
03435     } else if (tok->tp == K_ADDITIONAL_DIGEST) {
03436       int a = crypto_digest_algorithm_parse_name(tok->args[1]);
03437       if (a<0) {
03438         log_warn(LD_DIR, "Unrecognized algorithm name %s", tok->args[0]);
03439         continue;
03440       }
03441       alg = (digest_algorithm_t) a;
03442       flavor = tok->args[0];
03443       algname = tok->args[1];
03444       hexdigest = tok->args[2];
03445     } else {
03446       continue;
03447     }
03448 
03449     expected_length =
03450       (alg == DIGEST_SHA1) ? HEX_DIGEST_LEN : HEX_DIGEST256_LEN;
03451 
03452     if (strlen(hexdigest) != expected_length) {
03453       log_warn(LD_DIR, "Wrong length on consensus-digest in detached "
03454                "networkstatus signatures");
03455       goto err;
03456     }
03457     digests = detached_get_digests(sigs, flavor);
03458     tor_assert(digests);
03459     if (!tor_mem_is_zero(digests->d[alg], DIGEST256_LEN)) {
03460       log_warn(LD_DIR, "Multiple digests for %s with %s on detached "
03461                "signatures document", flavor, algname);
03462       continue;
03463     }
03464     if (base16_decode(digests->d[alg], DIGEST256_LEN,
03465                       hexdigest, strlen(hexdigest)) < 0) {
03466       log_warn(LD_DIR, "Bad encoding on consensus-digest in detached "
03467                "networkstatus signatures");
03468       goto err;
03469     }
03470   } SMARTLIST_FOREACH_END(_tok);
03471 
03472   tok = find_by_keyword(tokens, K_VALID_AFTER);
03473   if (parse_iso_time(tok->args[0], &sigs->valid_after)) {
03474     log_warn(LD_DIR, "Bad valid-after in detached networkstatus signatures");
03475     goto err;
03476   }
03477 
03478   tok = find_by_keyword(tokens, K_FRESH_UNTIL);
03479   if (parse_iso_time(tok->args[0], &sigs->fresh_until)) {
03480     log_warn(LD_DIR, "Bad fresh-until in detached networkstatus signatures");
03481     goto err;
03482   }
03483 
03484   tok = find_by_keyword(tokens, K_VALID_UNTIL);
03485   if (parse_iso_time(tok->args[0], &sigs->valid_until)) {
03486     log_warn(LD_DIR, "Bad valid-until in detached networkstatus signatures");
03487     goto err;
03488   }
03489 
03490   SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) {
03491     const char *id_hexdigest;
03492     const char *sk_hexdigest;
03493     const char *algname;
03494     const char *flavor;
03495     digest_algorithm_t alg;
03496 
03497     char id_digest[DIGEST_LEN];
03498     char sk_digest[DIGEST_LEN];
03499     smartlist_t *siglist;
03500     document_signature_t *sig;
03501     int is_duplicate;
03502 
03503     tok = _tok;
03504     if (tok->tp == K_DIRECTORY_SIGNATURE) {
03505       tor_assert(tok->n_args >= 2);
03506       flavor = "ns";
03507       algname = "sha1";
03508       id_hexdigest = tok->args[0];
03509       sk_hexdigest = tok->args[1];
03510     } else if (tok->tp == K_ADDITIONAL_SIGNATURE) {
03511       tor_assert(tok->n_args >= 4);
03512       flavor = tok->args[0];
03513       algname = tok->args[1];
03514       id_hexdigest = tok->args[2];
03515       sk_hexdigest = tok->args[3];
03516     } else {
03517       continue;
03518     }
03519 
03520     {
03521       int a = crypto_digest_algorithm_parse_name(algname);
03522       if (a<0) {
03523         log_warn(LD_DIR, "Unrecognized algorithm name %s", algname);
03524         continue;
03525       }
03526       alg = (digest_algorithm_t) a;
03527     }
03528 
03529     if (!tok->object_type ||
03530         strcmp(tok->object_type, "SIGNATURE") ||
03531         tok->object_size < 128 || tok->object_size > 512) {
03532       log_warn(LD_DIR, "Bad object type or length on directory-signature");
03533       goto err;
03534     }
03535 
03536     if (strlen(id_hexdigest) != HEX_DIGEST_LEN ||
03537         base16_decode(id_digest, sizeof(id_digest),
03538                       id_hexdigest, HEX_DIGEST_LEN) < 0) {
03539       log_warn(LD_DIR, "Error decoding declared identity %s in "
03540                "network-status vote.", escaped(id_hexdigest));
03541       goto err;
03542     }
03543     if (strlen(sk_hexdigest) != HEX_DIGEST_LEN ||
03544         base16_decode(sk_digest, sizeof(sk_digest),
03545                       sk_hexdigest, HEX_DIGEST_LEN) < 0) {
03546       log_warn(LD_DIR, "Error decoding declared signing key digest %s in "
03547                "network-status vote.", escaped(sk_hexdigest));
03548       goto err;
03549     }
03550 
03551     siglist = detached_get_signatures(sigs, flavor);
03552     is_duplicate = 0;
03553     SMARTLIST_FOREACH(siglist, document_signature_t *, dsig, {
03554       if (dsig->alg == alg &&
03555           tor_memeq(id_digest, dsig->identity_digest, DIGEST_LEN) &&
03556           tor_memeq(sk_digest, dsig->signing_key_digest, DIGEST_LEN)) {
03557         is_duplicate = 1;
03558       }
03559     });
03560     if (is_duplicate) {
03561       log_warn(LD_DIR, "Two signatures with identical keys and algorithm "
03562                "found.");
03563       continue;
03564     }
03565 
03566     sig = tor_malloc_zero(sizeof(document_signature_t));
03567     sig->alg = alg;
03568     memcpy(sig->identity_digest, id_digest, DIGEST_LEN);
03569     memcpy(sig->signing_key_digest, sk_digest, DIGEST_LEN);
03570     if (tok->object_size >= INT_MAX || tok->object_size >= SIZE_T_CEILING) {
03571       tor_free(sig);
03572       goto err;
03573     }
03574     sig->signature = tor_memdup(tok->object_body, tok->object_size);
03575     sig->signature_len = (int) tok->object_size;
03576 
03577     smartlist_add(siglist, sig);
03578   } SMARTLIST_FOREACH_END(_tok);
03579 
03580   goto done;
03581  err:
03582   ns_detached_signatures_free(sigs);
03583   sigs = NULL;
03584  done:
03585   SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
03586   smartlist_free(tokens);
03587   if (area) {
03588     DUMP_AREA(area, "detached signatures");
03589     memarea_drop_all(area);
03590   }
03591   return sigs;
03592 }
03593 
03598 addr_policy_t *
03599 router_parse_addr_policy_item_from_string(const char *s, int assume_action)
03600 {
03601   directory_token_t *tok = NULL;
03602   const char *cp, *eos;
03603   /* Longest possible policy is "accept ffff:ffff:..255/ffff:...255:0-65535".
03604    * But note that there can be an arbitrary amount of space between the
03605    * accept and the address:mask/port element. */
03606   char line[TOR_ADDR_BUF_LEN*2 + 32];
03607   addr_policy_t *r;
03608   memarea_t *area = NULL;
03609 
03610   s = eat_whitespace(s);
03611   if ((*s == '*' || TOR_ISDIGIT(*s)) && assume_action >= 0) {
03612     if (tor_snprintf(line, sizeof(line), "%s %s",
03613                assume_action == ADDR_POLICY_ACCEPT?"accept":"reject", s)<0) {
03614       log_warn(LD_DIR, "Policy %s is too long.", escaped(s));
03615       return NULL;
03616     }
03617     cp = line;
03618     tor_strlower(line);
03619   } else { /* assume an already well-formed address policy line */
03620     cp = s;
03621   }
03622 
03623   eos = cp + strlen(cp);
03624   area = memarea_new();
03625   tok = get_next_token(area, &cp, eos, routerdesc_token_table);
03626   if (tok->tp == _ERR) {
03627     log_warn(LD_DIR, "Error reading address policy: %s", tok->error);
03628     goto err;
03629   }
03630   if (tok->tp != K_ACCEPT && tok->tp != K_ACCEPT6 &&
03631       tok->tp != K_REJECT && tok->tp != K_REJECT6) {
03632     log_warn(LD_DIR, "Expected 'accept' or 'reject'.");
03633     goto err;
03634   }
03635 
03636   r = router_parse_addr_policy(tok);
03637   goto done;
03638  err:
03639   r = NULL;
03640  done:
03641   token_clear(tok);
03642   if (area) {
03643     DUMP_AREA(area, "policy item");
03644     memarea_drop_all(area);
03645   }
03646   return r;
03647 }
03648 
03651 static int
03652 router_add_exit_policy(routerinfo_t *router, directory_token_t *tok)
03653 {
03654   addr_policy_t *newe;
03655   newe = router_parse_addr_policy(tok);
03656   if (!newe)
03657     return -1;
03658   if (! router->exit_policy)
03659     router->exit_policy = smartlist_new();
03660 
03661   if (((tok->tp == K_ACCEPT6 || tok->tp == K_REJECT6) &&
03662        tor_addr_family(&newe->addr) == AF_INET)
03663       ||
03664       ((tok->tp == K_ACCEPT || tok->tp == K_REJECT) &&
03665        tor_addr_family(&newe->addr) == AF_INET6)) {
03666     log_warn(LD_DIR, "Mismatch between field type and address type in exit "
03667              "policy");
03668     addr_policy_free(newe);
03669     return -1;
03670   }
03671 
03672   smartlist_add(router->exit_policy, newe);
03673 
03674   return 0;
03675 }
03676 
03679 static addr_policy_t *
03680 router_parse_addr_policy(directory_token_t *tok)
03681 {
03682   addr_policy_t newe;
03683   char *arg;
03684 
03685   tor_assert(tok->tp == K_REJECT || tok->tp == K_REJECT6 ||
03686              tok->tp == K_ACCEPT || tok->tp == K_ACCEPT6);
03687 
03688   if (tok->n_args != 1)
03689     return NULL;
03690   arg = tok->args[0];
03691 
03692   if (!strcmpstart(arg,"private"))
03693     return router_parse_addr_policy_private(tok);
03694 
03695   memset(&newe, 0, sizeof(newe));
03696 
03697   if (tok->tp == K_REJECT || tok->tp == K_REJECT6)
03698     newe.policy_type = ADDR_POLICY_REJECT;
03699   else
03700     newe.policy_type = ADDR_POLICY_ACCEPT;
03701 
03702   if (tor_addr_parse_mask_ports(arg, &newe.addr, &newe.maskbits,
03703                                 &newe.prt_min, &newe.prt_max) < 0) {
03704     log_warn(LD_DIR,"Couldn't parse line %s. Dropping", escaped(arg));
03705     return NULL;
03706   }
03707 
03708   return addr_policy_get_canonical_entry(&newe);
03709 }
03710 
03715 static addr_policy_t *
03716 router_parse_addr_policy_private(directory_token_t *tok)
03717 {
03718   const char *arg;
03719   uint16_t port_min, port_max;
03720   addr_policy_t result;
03721 
03722   arg = tok->args[0];
03723   if (strcmpstart(arg, "private"))
03724     return NULL;
03725 
03726   arg += strlen("private");
03727   arg = (char*) eat_whitespace(arg);
03728   if (!arg || *arg != ':')
03729     return NULL;
03730 
03731   if (parse_port_range(arg+1, &port_min, &port_max)<0)
03732     return NULL;
03733 
03734   memset(&result, 0, sizeof(result));
03735   if (tok->tp == K_REJECT || tok->tp == K_REJECT6)
03736     result.policy_type = ADDR_POLICY_REJECT;
03737   else
03738     result.policy_type = ADDR_POLICY_ACCEPT;
03739   result.is_private = 1;
03740   result.prt_min = port_min;
03741   result.prt_max = port_max;
03742 
03743   return addr_policy_get_canonical_entry(&result);
03744 }
03745 
03747 void
03748 assert_addr_policy_ok(smartlist_t *lst)
03749 {
03750   if (!lst) return;
03751   SMARTLIST_FOREACH(lst, addr_policy_t *, t, {
03752     tor_assert(t->policy_type == ADDR_POLICY_REJECT ||
03753                t->policy_type == ADDR_POLICY_ACCEPT);
03754     tor_assert(t->prt_min <= t->prt_max);
03755   });
03756 }
03757 
03758 /*
03759  * Low-level tokenizer for router descriptors and directories.
03760  */
03761 
03763 static void
03764 token_clear(directory_token_t *tok)
03765 {
03766   if (tok->key)
03767     crypto_pk_free(tok->key);
03768 }
03769 
03770 #define ALLOC_ZERO(sz) memarea_alloc_zero(area,sz)
03771 #define ALLOC(sz) memarea_alloc(area,sz)
03772 #define STRDUP(str) memarea_strdup(area,str)
03773 #define STRNDUP(str,n) memarea_strndup(area,(str),(n))
03774 
03775 #define RET_ERR(msg)                                               \
03776   STMT_BEGIN                                                       \
03777     if (tok) token_clear(tok);                                      \
03778     tok = ALLOC_ZERO(sizeof(directory_token_t));                   \
03779     tok->tp = _ERR;                                                \
03780     tok->error = STRDUP(msg);                                      \
03781     goto done_tokenizing;                                          \
03782   STMT_END
03783 
03789 static INLINE directory_token_t *
03790 token_check_object(memarea_t *area, const char *kwd,
03791                    directory_token_t *tok, obj_syntax o_syn)
03792 {
03793   char ebuf[128];
03794   switch (o_syn) {
03795     case NO_OBJ:
03796       /* No object is allowed for this token. */
03797       if (tok->object_body) {
03798         tor_snprintf(ebuf, sizeof(ebuf), "Unexpected object for %s", kwd);
03799         RET_ERR(ebuf);
03800       }
03801       if (tok->key) {
03802         tor_snprintf(ebuf, sizeof(ebuf), "Unexpected public key for %s", kwd);
03803         RET_ERR(ebuf);
03804       }
03805       break;
03806     case NEED_OBJ:
03807       /* There must be a (non-key) object. */
03808       if (!tok->object_body) {
03809         tor_snprintf(ebuf, sizeof(ebuf), "Missing object for %s", kwd);
03810         RET_ERR(ebuf);
03811       }
03812       break;
03813     case NEED_KEY_1024: /* There must be a 1024-bit public key. */
03814     case NEED_SKEY_1024: /* There must be a 1024-bit private key. */
03815       if (tok->key && crypto_pk_num_bits(tok->key) != PK_BYTES*8) {
03816         tor_snprintf(ebuf, sizeof(ebuf), "Wrong size on key for %s: %d bits",
03817                      kwd, crypto_pk_num_bits(tok->key));
03818         RET_ERR(ebuf);
03819       }
03820       /* fall through */
03821     case NEED_KEY: /* There must be some kind of key. */
03822       if (!tok->key) {
03823         tor_snprintf(ebuf, sizeof(ebuf), "Missing public key for %s", kwd);
03824         RET_ERR(ebuf);
03825       }
03826       if (o_syn != NEED_SKEY_1024) {
03827         if (crypto_pk_key_is_private(tok->key)) {
03828           tor_snprintf(ebuf, sizeof(ebuf),
03829                "Private key given for %s, which wants a public key", kwd);
03830           RET_ERR(ebuf);
03831         }
03832       } else { /* o_syn == NEED_SKEY_1024 */
03833         if (!crypto_pk_key_is_private(tok->key)) {
03834           tor_snprintf(ebuf, sizeof(ebuf),
03835                "Public key given for %s, which wants a private key", kwd);
03836           RET_ERR(ebuf);
03837         }
03838       }
03839       break;
03840     case OBJ_OK:
03841       /* Anything goes with this token. */
03842       break;
03843   }
03844 
03845  done_tokenizing:
03846   return tok;
03847 }
03848 
03854 static INLINE int
03855 get_token_arguments(memarea_t *area, directory_token_t *tok,
03856                     const char *s, const char *eol)
03857 {
03859 #define MAX_ARGS 512
03860   char *mem = memarea_strndup(area, s, eol-s);
03861   char *cp = mem;
03862   int j = 0;
03863   char *args[MAX_ARGS];
03864   while (*cp) {
03865     if (j == MAX_ARGS)
03866       return -1;
03867     args[j++] = cp;
03868     cp = (char*)find_whitespace(cp);
03869     if (!cp || !*cp)
03870       break; /* End of the line. */
03871     *cp++ = '\0';
03872     cp = (char*)eat_whitespace(cp);
03873   }
03874   tok->n_args = j;
03875   tok->args = memarea_memdup(area, args, j*sizeof(char*));
03876   return j;
03877 #undef MAX_ARGS
03878 }
03879 
03884 static directory_token_t *
03885 get_next_token(memarea_t *area,
03886                const char **s, const char *eos, token_rule_t *table)
03887 {
03890 #define MAX_UNPARSED_OBJECT_SIZE (128*1024)
03891 
03893 #define MAX_LINE_LENGTH (128*1024)
03894 
03895   const char *next, *eol, *obstart;
03896   size_t obname_len;
03897   int i;
03898   directory_token_t *tok;
03899   obj_syntax o_syn = NO_OBJ;
03900   char ebuf[128];
03901   const char *kwd = "";
03902 
03903   tor_assert(area);
03904   tok = ALLOC_ZERO(sizeof(directory_token_t));
03905   tok->tp = _ERR;
03906 
03907   /* Set *s to first token, eol to end-of-line, next to after first token */
03908   *s = eat_whitespace_eos(*s, eos); /* eat multi-line whitespace */
03909   tor_assert(eos >= *s);
03910   eol = memchr(*s, '\n', eos-*s);
03911   if (!eol)
03912     eol = eos;
03913   if (eol - *s > MAX_LINE_LENGTH) {
03914     RET_ERR("Line far too long");
03915   }
03916 
03917   next = find_whitespace_eos(*s, eol);
03918 
03919   if (!strcmp_len(*s, "opt", next-*s)) {
03920     /* Skip past an "opt" at the start of the line. */
03921     *s = eat_whitespace_eos_no_nl(next, eol);
03922     next = find_whitespace_eos(*s, eol);
03923   } else if (*s == eos) {  /* If no "opt", and end-of-line, line is invalid */
03924     RET_ERR("Unexpected EOF");
03925   }
03926 
03927   /* Search the table for the appropriate entry.  (I tried a binary search
03928    * instead, but it wasn't any faster.) */
03929   for (i = 0; table[i].t ; ++i) {
03930     if (!strcmp_len(*s, table[i].t, next-*s)) {
03931       /* We've found the keyword. */
03932       kwd = table[i].t;
03933       tok->tp = table[i].v;
03934       o_syn = table[i].os;
03935       *s = eat_whitespace_eos_no_nl(next, eol);
03936       /* We go ahead whether there are arguments or not, so that tok->args is
03937        * always set if we want arguments. */
03938       if (table[i].concat_args) {
03939         /* The keyword takes the line as a single argument */
03940         tok->args = ALLOC(sizeof(char*));
03941         tok->args[0] = STRNDUP(*s,eol-*s); /* Grab everything on line */
03942         tok->n_args = 1;
03943       } else {
03944         /* This keyword takes multiple arguments. */
03945         if (get_token_arguments(area, tok, *s, eol)<0) {
03946           tor_snprintf(ebuf, sizeof(ebuf),"Far too many arguments to %s", kwd);
03947           RET_ERR(ebuf);
03948         }
03949         *s = eol;
03950       }
03951       if (tok->n_args < table[i].min_args) {
03952         tor_snprintf(ebuf, sizeof(ebuf), "Too few arguments to %s", kwd);
03953         RET_ERR(ebuf);
03954       } else if (tok->n_args > table[i].max_args) {
03955         tor_snprintf(ebuf, sizeof(ebuf), "Too many arguments to %s", kwd);
03956         RET_ERR(ebuf);
03957       }
03958       break;
03959     }
03960   }
03961 
03962   if (tok->tp == _ERR) {
03963     /* No keyword matched; call it an "K_opt" or "A_unrecognized" */
03964     if (**s == '@')
03965       tok->tp = _A_UNKNOWN;
03966     else
03967       tok->tp = K_OPT;
03968     tok->args = ALLOC(sizeof(char*));
03969     tok->args[0] = STRNDUP(*s, eol-*s);
03970     tok->n_args = 1;
03971     o_syn = OBJ_OK;
03972   }
03973 
03974   /* Check whether there's an object present */
03975   *s = eat_whitespace_eos(eol, eos);  /* Scan from end of first line */
03976   tor_assert(eos >= *s);
03977   eol = memchr(*s, '\n', eos-*s);
03978   if (!eol || eol-*s<11 || strcmpstart(*s, "-----BEGIN ")) /* No object. */
03979     goto check_object;
03980 
03981   obstart = *s; /* Set obstart to start of object spec */
03982   if (*s+16 >= eol || memchr(*s+11,'\0',eol-*s-16) || /* no short lines, */
03983       strcmp_len(eol-5, "-----", 5) ||           /* nuls or invalid endings */
03984       (eol-*s) > MAX_UNPARSED_OBJECT_SIZE) {     /* name too long */
03985     RET_ERR("Malformed object: bad begin line");
03986   }
03987   tok->object_type = STRNDUP(*s+11, eol-*s-16);
03988   obname_len = eol-*s-16; /* store objname length here to avoid a strlen() */
03989   *s = eol+1;    /* Set *s to possible start of object data (could be eos) */
03990 
03991   /* Go to the end of the object */
03992   next = tor_memstr(*s, eos-*s, "-----END ");
03993   if (!next) {
03994     RET_ERR("Malformed object: missing object end line");
03995   }
03996   tor_assert(eos >= next);
03997   eol = memchr(next, '\n', eos-next);
03998   if (!eol)  /* end-of-line marker, or eos if there's no '\n' */
03999     eol = eos;
04000   /* Validate the ending tag, which should be 9 + NAME + 5 + eol */
04001   if ((size_t)(eol-next) != 9+obname_len+5 ||
04002       strcmp_len(next+9, tok->object_type, obname_len) ||
04003       strcmp_len(eol-5, "-----", 5)) {
04004     snprintf(ebuf, sizeof(ebuf), "Malformed object: mismatched end tag %s",
04005              tok->object_type);
04006     ebuf[sizeof(ebuf)-1] = '\0';
04007     RET_ERR(ebuf);
04008   }
04009   if (next - *s > MAX_UNPARSED_OBJECT_SIZE)
04010     RET_ERR("Couldn't parse object: missing footer or object much too big.");
04011 
04012   if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) { /* If it's a public key */
04013     tok->key = crypto_pk_new();
04014     if (crypto_pk_read_public_key_from_string(tok->key, obstart, eol-obstart))
04015       RET_ERR("Couldn't parse public key.");
04016   } else if (!strcmp(tok->object_type, "RSA PRIVATE KEY")) { /* private key */
04017     tok->key = crypto_pk_new();
04018     if (crypto_pk_read_private_key_from_string(tok->key, obstart, eol-obstart))
04019       RET_ERR("Couldn't parse private key.");
04020   } else { /* If it's something else, try to base64-decode it */
04021     int r;
04022     tok->object_body = ALLOC(next-*s); /* really, this is too much RAM. */
04023     r = base64_decode(tok->object_body, next-*s, *s, next-*s);
04024     if (r<0)
04025       RET_ERR("Malformed object: bad base64-encoded data");
04026     tok->object_size = r;
04027   }
04028   *s = eol;
04029 
04030  check_object:
04031   tok = token_check_object(area, kwd, tok, o_syn);
04032 
04033  done_tokenizing:
04034   return tok;
04035 
04036 #undef RET_ERR
04037 #undef ALLOC
04038 #undef ALLOC_ZERO
04039 #undef STRDUP
04040 #undef STRNDUP
04041 }
04042 
04048 static int
04049 tokenize_string(memarea_t *area,
04050                 const char *start, const char *end, smartlist_t *out,
04051                 token_rule_t *table, int flags)
04052 {
04053   const char **s;
04054   directory_token_t *tok = NULL;
04055   int counts[_NIL];
04056   int i;
04057   int first_nonannotation;
04058   int prev_len = smartlist_len(out);
04059   tor_assert(area);
04060 
04061   s = &start;
04062   if (!end)
04063     end = start+strlen(start);
04064   for (i = 0; i < _NIL; ++i)
04065     counts[i] = 0;
04066 
04067   SMARTLIST_FOREACH(out, const directory_token_t *, t, ++counts[t->tp]);
04068 
04069   while (*s < end && (!tok || tok->tp != _EOF)) {
04070     tok = get_next_token(area, s, end, table);
04071     if (tok->tp == _ERR) {
04072       log_warn(LD_DIR, "parse error: %s", tok->error);
04073       token_clear(tok);
04074       return -1;
04075     }
04076     ++counts[tok->tp];
04077     smartlist_add(out, tok);
04078     *s = eat_whitespace_eos(*s, end);
04079   }
04080 
04081   if (flags & TS_NOCHECK)
04082     return 0;
04083 
04084   if ((flags & TS_ANNOTATIONS_OK)) {
04085     first_nonannotation = -1;
04086     for (i = 0; i < smartlist_len(out); ++i) {
04087       tok = smartlist_get(out, i);
04088       if (tok->tp < MIN_ANNOTATION || tok->tp > MAX_ANNOTATION) {
04089         first_nonannotation = i;
04090         break;
04091       }
04092     }
04093     if (first_nonannotation < 0) {
04094       log_warn(LD_DIR, "parse error: item contains only annotations");
04095       return -1;
04096     }
04097     for (i=first_nonannotation;  i < smartlist_len(out); ++i) {
04098       tok = smartlist_get(out, i);
04099       if (tok->tp >= MIN_ANNOTATION && tok->tp <= MAX_ANNOTATION) {
04100         log_warn(LD_DIR, "parse error: Annotations mixed with keywords");
04101         return -1;
04102       }
04103     }
04104     if ((flags & TS_NO_NEW_ANNOTATIONS)) {
04105       if (first_nonannotation != prev_len) {
04106         log_warn(LD_DIR, "parse error: Unexpected annotations.");
04107         return -1;
04108       }
04109     }
04110   } else {
04111     for (i=0;  i < smartlist_len(out); ++i) {
04112       tok = smartlist_get(out, i);
04113       if (tok->tp >= MIN_ANNOTATION && tok->tp <= MAX_ANNOTATION) {
04114         log_warn(LD_DIR, "parse error: no annotations allowed.");
04115         return -1;
04116       }
04117     }
04118     first_nonannotation = 0;
04119   }
04120   for (i = 0; table[i].t; ++i) {
04121     if (counts[table[i].v] < table[i].min_cnt) {
04122       log_warn(LD_DIR, "Parse error: missing %s element.", table[i].t);
04123       return -1;
04124     }
04125     if (counts[table[i].v] > table[i].max_cnt) {
04126       log_warn(LD_DIR, "Parse error: too many %s elements.", table[i].t);
04127       return -1;
04128     }
04129     if (table[i].pos & AT_START) {
04130       if (smartlist_len(out) < 1 ||
04131           (tok = smartlist_get(out, first_nonannotation))->tp != table[i].v) {
04132         log_warn(LD_DIR, "Parse error: first item is not %s.", table[i].t);
04133         return -1;
04134       }
04135     }
04136     if (table[i].pos & AT_END) {
04137       if (smartlist_len(out) < 1 ||
04138           (tok = smartlist_get(out, smartlist_len(out)-1))->tp != table[i].v) {
04139         log_warn(LD_DIR, "Parse error: last item is not %s.", table[i].t);
04140         return -1;
04141       }
04142     }
04143   }
04144   return 0;
04145 }
04146 
04150 static directory_token_t *
04151 find_opt_by_keyword(smartlist_t *s, directory_keyword keyword)
04152 {
04153   SMARTLIST_FOREACH(s, directory_token_t *, t, if (t->tp == keyword) return t);
04154   return NULL;
04155 }
04156 
04160 static directory_token_t *
04161 _find_by_keyword(smartlist_t *s, directory_keyword keyword,
04162                  const char *keyword_as_string)
04163 {
04164   directory_token_t *tok = find_opt_by_keyword(s, keyword);
04165   if (PREDICT_UNLIKELY(!tok)) {
04166     log_err(LD_BUG, "Missing %s [%d] in directory object that should have "
04167          "been validated. Internal error.", keyword_as_string, (int)keyword);
04168     tor_assert(tok);
04169   }
04170   return tok;
04171 }
04172 
04177 static smartlist_t *
04178 find_all_by_keyword(smartlist_t *s, directory_keyword k)
04179 {
04180   smartlist_t *out = NULL;
04181   SMARTLIST_FOREACH(s, directory_token_t *, t,
04182                     if (t->tp == k) {
04183                       if (!out)
04184                         out = smartlist_new();
04185                       smartlist_add(out, t);
04186                     });
04187   return out;
04188 }
04189 
04193 static smartlist_t *
04194 find_all_exitpolicy(smartlist_t *s)
04195 {
04196   smartlist_t *out = smartlist_new();
04197   SMARTLIST_FOREACH(s, directory_token_t *, t,
04198       if (t->tp == K_ACCEPT || t->tp == K_ACCEPT6 ||
04199           t->tp == K_REJECT || t->tp == K_REJECT6)
04200         smartlist_add(out,t));
04201   return out;
04202 }
04203 
04211 static int
04212 router_get_hash_impl_helper(const char *s, size_t s_len,
04213                             const char *start_str,
04214                             const char *end_str, char end_c,
04215                             const char **start_out, const char **end_out)
04216 {
04217   const char *start, *end;
04218   start = tor_memstr(s, s_len, start_str);
04219   if (!start) {
04220     log_warn(LD_DIR,"couldn't find start of hashed material \"%s\"",start_str);
04221     return -1;
04222   }
04223   if (start != s && *(start-1) != '\n') {
04224     log_warn(LD_DIR,
04225              "first occurrence of \"%s\" is not at the start of a line",
04226              start_str);
04227     return -1;
04228   }
04229   end = tor_memstr(start+strlen(start_str),
04230                    s_len - (start-s) - strlen(start_str), end_str);
04231   if (!end) {
04232     log_warn(LD_DIR,"couldn't find end of hashed material \"%s\"",end_str);
04233     return -1;
04234   }
04235   end = memchr(end+strlen(end_str), end_c, s_len - (end-s) - strlen(end_str));
04236   if (!end) {
04237     log_warn(LD_DIR,"couldn't find EOL");
04238     return -1;
04239   }
04240   ++end;
04241 
04242   *start_out = start;
04243   *end_out = end;
04244   return 0;
04245 }
04246 
04254 static int
04255 router_get_hash_impl(const char *s, size_t s_len, char *digest,
04256                      const char *start_str,
04257                      const char *end_str, char end_c,
04258                      digest_algorithm_t alg)
04259 {
04260   const char *start=NULL, *end=NULL;
04261   if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,
04262                                   &start,&end)<0)
04263     return -1;
04264 
04265   if (alg == DIGEST_SHA1) {
04266     if (crypto_digest(digest, start, end-start)) {
04267       log_warn(LD_BUG,"couldn't compute digest");
04268       return -1;
04269     }
04270   } else {
04271     if (crypto_digest256(digest, start, end-start, alg)) {
04272       log_warn(LD_BUG,"couldn't compute digest");
04273       return -1;
04274     }
04275   }
04276 
04277   return 0;
04278 }
04279 
04281 static int
04282 router_get_hashes_impl(const char *s, size_t s_len, digests_t *digests,
04283                        const char *start_str,
04284                        const char *end_str, char end_c)
04285 {
04286   const char *start=NULL, *end=NULL;
04287   if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,
04288                                   &start,&end)<0)
04289     return -1;
04290 
04291   if (crypto_digest_all(digests, start, end-start)) {
04292     log_warn(LD_BUG,"couldn't compute digests");
04293     return -1;
04294   }
04295 
04296   return 0;
04297 }
04298 
04301 static const char *
04302 find_start_of_next_microdesc(const char *s, const char *eos)
04303 {
04304   int started_with_annotations;
04305   s = eat_whitespace_eos(s, eos);
04306   if (!s)
04307     return NULL;
04308 
04309 #define CHECK_LENGTH() STMT_BEGIN \
04310     if (s+32 > eos)               \
04311       return NULL;                \
04312   STMT_END
04313 
04314 #define NEXT_LINE() STMT_BEGIN            \
04315     s = memchr(s, '\n', eos-s);           \
04316     if (!s || s+1 >= eos)                 \
04317       return NULL;                        \
04318     s++;                                  \
04319   STMT_END
04320 
04321   CHECK_LENGTH();
04322 
04323   started_with_annotations = (*s == '@');
04324 
04325   if (started_with_annotations) {
04326     /* Start by advancing to the first non-annotation line. */
04327     while (*s == '@')
04328       NEXT_LINE();
04329   }
04330   CHECK_LENGTH();
04331 
04332   /* Now we should be pointed at an onion-key line.  If we are, then skip
04333    * it. */
04334   if (!strcmpstart(s, "onion-key"))
04335     NEXT_LINE();
04336 
04337   /* Okay, now we're pointed at the first line of the microdescriptor which is
04338      not an annotation or onion-key.  The next line that _is_ an annotation or
04339      onion-key is the start of the next microdescriptor. */
04340   while (s+32 < eos) {
04341     if (*s == '@' || !strcmpstart(s, "onion-key"))
04342       return s;
04343     NEXT_LINE();
04344   }
04345   return NULL;
04346 
04347 #undef CHECK_LENGTH
04348 #undef NEXT_LINE
04349 }
04350 
04356 smartlist_t *
04357 microdescs_parse_from_string(const char *s, const char *eos,
04358                              int allow_annotations, int copy_body)
04359 {
04360   smartlist_t *tokens;
04361   smartlist_t *result;
04362   microdesc_t *md = NULL;
04363   memarea_t *area;
04364   const char *start = s;
04365   const char *start_of_next_microdesc;
04366   int flags = allow_annotations ? TS_ANNOTATIONS_OK : 0;
04367 
04368   directory_token_t *tok;
04369 
04370   if (!eos)
04371     eos = s + strlen(s);
04372 
04373   s = eat_whitespace_eos(s, eos);
04374   area = memarea_new();
04375   result = smartlist_new();
04376   tokens = smartlist_new();
04377 
04378   while (s < eos) {
04379     start_of_next_microdesc = find_start_of_next_microdesc(s, eos);
04380     if (!start_of_next_microdesc)
04381       start_of_next_microdesc = eos;
04382 
04383     if (tokenize_string(area, s, start_of_next_microdesc, tokens,
04384                         microdesc_token_table, flags)) {
04385       log_warn(LD_DIR, "Unparseable microdescriptor");
04386       goto next;
04387     }
04388 
04389     md = tor_malloc_zero(sizeof(microdesc_t));
04390     {
04391       const char *cp = tor_memstr(s, start_of_next_microdesc-s,
04392                                   "onion-key");
04393       tor_assert(cp);
04394 
04395       md->bodylen = start_of_next_microdesc - cp;
04396       if (copy_body)
04397         md->body = tor_strndup(cp, md->bodylen);
04398       else
04399         md->body = (char*)cp;
04400       md->off = cp - start;
04401     }
04402 
04403     if ((tok = find_opt_by_keyword(tokens, A_LAST_LISTED))) {
04404       if (parse_iso_time(tok->args[0], &md->last_listed)) {
04405         log_warn(LD_DIR, "Bad last-listed time in microdescriptor");
04406         goto next;
04407       }
04408     }
04409 
04410     tok = find_by_keyword(tokens, K_ONION_KEY);
04411     if (!crypto_pk_public_exponent_ok(tok->key)) {
04412       log_warn(LD_DIR,
04413                "Relay's onion key had invalid exponent.");
04414       goto next;
04415     }
04416     md->onion_pkey = tok->key;
04417     tok->key = NULL;
04418 
04419     if ((tok = find_opt_by_keyword(tokens, K_FAMILY))) {
04420       int i;
04421       md->family = smartlist_new();
04422       for (i=0;i<tok->n_args;++i) {
04423         if (!is_legal_nickname_or_hexdigest(tok->args[i])) {
04424           log_warn(LD_DIR, "Illegal nickname %s in family line",
04425                    escaped(tok->args[i]));
04426           goto next;
04427         }
04428         smartlist_add(md->family, tor_strdup(tok->args[i]));
04429       }
04430     }
04431 
04432     if ((tok = find_opt_by_keyword(tokens, K_P))) {
04433       md->exit_policy = parse_short_policy(tok->args[0]);
04434     }
04435 
04436     crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256);
04437 
04438     smartlist_add(result, md);
04439 
04440     md = NULL;
04441   next:
04442     microdesc_free(md);
04443     md = NULL;
04444 
04445     memarea_clear(area);
04446     smartlist_clear(tokens);
04447     s = start_of_next_microdesc;
04448   }
04449 
04450   memarea_drop_all(area);
04451   smartlist_free(tokens);
04452 
04453   return result;
04454 }
04455 
04458 int
04459 tor_version_supports_microdescriptors(const char *platform)
04460 {
04461   return tor_version_as_new_as(platform, "0.2.3.1-alpha");
04462 }
04463 
04468 int
04469 tor_version_as_new_as(const char *platform, const char *cutoff)
04470 {
04471   tor_version_t cutoff_version, router_version;
04472   char *s, *s2, *start;
04473   char tmp[128];
04474 
04475   tor_assert(platform);
04476 
04477   if (tor_version_parse(cutoff, &cutoff_version)<0) {
04478     log_warn(LD_BUG,"cutoff version '%s' unparseable.",cutoff);
04479     return 0;
04480   }
04481   if (strcmpstart(platform,"Tor ")) /* nonstandard Tor; be safe and say yes */
04482     return 1;
04483 
04484   start = (char *)eat_whitespace(platform+3);
04485   if (!*start) return 0;
04486   s = (char *)find_whitespace(start); /* also finds '\0', which is fine */
04487   s2 = (char*)eat_whitespace(s);
04488   if (!strcmpstart(s2, "(r") || !strcmpstart(s2, "(git-"))
04489     s = (char*)find_whitespace(s2);
04490 
04491   if ((size_t)(s-start+1) >= sizeof(tmp)) /* too big, no */
04492     return 0;
04493   strlcpy(tmp, start, s-start+1);
04494 
04495   if (tor_version_parse(tmp, &router_version)<0) {
04496     log_info(LD_DIR,"Router version '%s' unparseable.",tmp);
04497     return 1; /* be safe and say yes */
04498   }
04499 
04500   /* Here's why we don't need to do any special handling for svn revisions:
04501    * - If neither has an svn revision, we're fine.
04502    * - If the router doesn't have an svn revision, we can't assume that it
04503    *   is "at least" any svn revision, so we need to return 0.
04504    * - If the target version doesn't have an svn revision, any svn revision
04505    *   (or none at all) is good enough, so return 1.
04506    * - If both target and router have an svn revision, we compare them.
04507    */
04508 
04509   return tor_version_compare(&router_version, &cutoff_version) >= 0;
04510 }
04511 
04514 int
04515 tor_version_parse(const char *s, tor_version_t *out)
04516 {
04517   char *eos=NULL;
04518   const char *cp=NULL;
04519   /* Format is:
04520    *   "Tor " ? NUM dot NUM dot NUM [ ( pre | rc | dot ) NUM [ - tag ] ]
04521    */
04522   tor_assert(s);
04523   tor_assert(out);
04524 
04525   memset(out, 0, sizeof(tor_version_t));
04526 
04527   if (!strcasecmpstart(s, "Tor "))
04528     s += 4;
04529 
04530   /* Get major. */
04531   out->major = (int)strtol(s,&eos,10);
04532   if (!eos || eos==s || *eos != '.') return -1;
04533   cp = eos+1;
04534 
04535   /* Get minor */
04536   out->minor = (int) strtol(cp,&eos,10);
04537   if (!eos || eos==cp || *eos != '.') return -1;
04538   cp = eos+1;
04539 
04540   /* Get micro */
04541   out->micro = (int) strtol(cp,&eos,10);
04542   if (!eos || eos==cp) return -1;
04543   if (!*eos) {
04544     out->status = VER_RELEASE;
04545     out->patchlevel = 0;
04546     return 0;
04547   }
04548   cp = eos;
04549 
04550   /* Get status */
04551   if (*cp == '.') {
04552     out->status = VER_RELEASE;
04553     ++cp;
04554   } else if (0==strncmp(cp, "pre", 3)) {
04555     out->status = VER_PRE;
04556     cp += 3;
04557   } else if (0==strncmp(cp, "rc", 2)) {
04558     out->status = VER_RC;
04559     cp += 2;
04560   } else {
04561     return -1;
04562   }
04563 
04564   /* Get patchlevel */
04565   out->patchlevel = (int) strtol(cp,&eos,10);
04566   if (!eos || eos==cp) return -1;
04567   cp = eos;
04568 
04569   /* Get status tag. */
04570   if (*cp == '-' || *cp == '.')
04571     ++cp;
04572   eos = (char*) find_whitespace(cp);
04573   if (eos-cp >= (int)sizeof(out->status_tag))
04574     strlcpy(out->status_tag, cp, sizeof(out->status_tag));
04575   else {
04576     memcpy(out->status_tag, cp, eos-cp);
04577     out->status_tag[eos-cp] = 0;
04578   }
04579   cp = eat_whitespace(eos);
04580 
04581   if (!strcmpstart(cp, "(r")) {
04582     cp += 2;
04583     out->svn_revision = (int) strtol(cp,&eos,10);
04584   } else if (!strcmpstart(cp, "(git-")) {
04585     char *close_paren = strchr(cp, ')');
04586     int hexlen;
04587     char digest[DIGEST_LEN];
04588     if (! close_paren)
04589       return -1;
04590     cp += 5;
04591     if (close_paren-cp > HEX_DIGEST_LEN)
04592       return -1;
04593     hexlen = (int)(close_paren-cp);
04594     memset(digest, 0, sizeof(digest));
04595     if ( hexlen == 0 || (hexlen % 2) == 1)
04596       return -1;
04597     if (base16_decode(digest, hexlen/2, cp, hexlen))
04598       return -1;
04599     memcpy(out->git_tag, digest, hexlen/2);
04600     out->git_tag_len = hexlen/2;
04601   }
04602 
04603   return 0;
04604 }
04605 
04608 int
04609 tor_version_compare(tor_version_t *a, tor_version_t *b)
04610 {
04611   int i;
04612   tor_assert(a);
04613   tor_assert(b);
04614   if ((i = a->major - b->major))
04615     return i;
04616   else if ((i = a->minor - b->minor))
04617     return i;
04618   else if ((i = a->micro - b->micro))
04619     return i;
04620   else if ((i = a->status - b->status))
04621     return i;
04622   else if ((i = a->patchlevel - b->patchlevel))
04623     return i;
04624   else if ((i = strcmp(a->status_tag, b->status_tag)))
04625     return i;
04626   else if ((i = a->svn_revision - b->svn_revision))
04627     return i;
04628   else if ((i = a->git_tag_len - b->git_tag_len))
04629     return i;
04630   else if (a->git_tag_len)
04631     return fast_memcmp(a->git_tag, b->git_tag, a->git_tag_len);
04632   else
04633     return 0;
04634 }
04635 
04638 int
04639 tor_version_same_series(tor_version_t *a, tor_version_t *b)
04640 {
04641   tor_assert(a);
04642   tor_assert(b);
04643   return ((a->major == b->major) &&
04644           (a->minor == b->minor) &&
04645           (a->micro == b->micro));
04646 }
04647 
04651 static int
04652 _compare_tor_version_str_ptr(const void **_a, const void **_b)
04653 {
04654   const char *a = *_a, *b = *_b;
04655   int ca, cb;
04656   tor_version_t va, vb;
04657   ca = tor_version_parse(a, &va);
04658   cb = tor_version_parse(b, &vb);
04659   /* If they both parse, compare them. */
04660   if (!ca && !cb)
04661     return tor_version_compare(&va,&vb);
04662   /* If one parses, it comes first. */
04663   if (!ca && cb)
04664     return -1;
04665   if (ca && !cb)
04666     return 1;
04667   /* If neither parses, compare strings.  Also, the directory server admin
04668   ** needs to be smacked upside the head.  But Tor is tolerant and gentle. */
04669   return strcmp(a,b);
04670 }
04671 
04673 void
04674 sort_version_list(smartlist_t *versions, int remove_duplicates)
04675 {
04676   smartlist_sort(versions, _compare_tor_version_str_ptr);
04677 
04678   if (remove_duplicates)
04679     smartlist_uniq(versions, _compare_tor_version_str_ptr, _tor_free);
04680 }
04681 
04692 int
04693 rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
04694                                  char *desc_id_out,
04695                                  char **intro_points_encrypted_out,
04696                                  size_t *intro_points_encrypted_size_out,
04697                                  size_t *encoded_size_out,
04698                                  const char **next_out, const char *desc)
04699 {
04700   rend_service_descriptor_t *result =
04701                             tor_malloc_zero(sizeof(rend_service_descriptor_t));
04702   char desc_hash[DIGEST_LEN];
04703   const char *eos;
04704   smartlist_t *tokens = smartlist_new();
04705   directory_token_t *tok;
04706   char secret_id_part[DIGEST_LEN];
04707   int i, version, num_ok=1;
04708   smartlist_t *versions;
04709   char public_key_hash[DIGEST_LEN];
04710   char test_desc_id[DIGEST_LEN];
04711   memarea_t *area = NULL;
04712   tor_assert(desc);
04713   /* Check if desc starts correctly. */
04714   if (strncmp(desc, "rendezvous-service-descriptor ",
04715               strlen("rendezvous-service-descriptor "))) {
04716     log_info(LD_REND, "Descriptor does not start correctly.");
04717     goto err;
04718   }
04719   /* Compute descriptor hash for later validation. */
04720   if (router_get_hash_impl(desc, strlen(desc), desc_hash,
04721                            "rendezvous-service-descriptor ",
04722                            "\nsignature", '\n', DIGEST_SHA1) < 0) {
04723     log_warn(LD_REND, "Couldn't compute descriptor hash.");
04724     goto err;
04725   }
04726   /* Determine end of string. */
04727   eos = strstr(desc, "\nrendezvous-service-descriptor ");
04728   if (!eos)
04729     eos = desc + strlen(desc);
04730   else
04731     eos = eos + 1;
04732   /* Check length. */
04733   if (eos-desc > REND_DESC_MAX_SIZE) {
04734     /* XXX023 If we are parsing this descriptor as a server, this
04735      * should be a protocol warning. */
04736     log_warn(LD_REND, "Descriptor length is %d which exceeds "
04737              "maximum rendezvous descriptor size of %d bytes.",
04738              (int)(eos-desc), REND_DESC_MAX_SIZE);
04739     goto err;
04740   }
04741   /* Tokenize descriptor. */
04742   area = memarea_new();
04743   if (tokenize_string(area, desc, eos, tokens, desc_token_table, 0)) {
04744     log_warn(LD_REND, "Error tokenizing descriptor.");
04745     goto err;
04746   }
04747   /* Set next to next descriptor, if available. */
04748   *next_out = eos;
04749   /* Set length of encoded descriptor. */
04750   *encoded_size_out = eos - desc;
04751   /* Check min allowed length of token list. */
04752   if (smartlist_len(tokens) < 7) {
04753     log_warn(LD_REND, "Impossibly short descriptor.");
04754     goto err;
04755   }
04756   /* Parse base32-encoded descriptor ID. */
04757   tok = find_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR);
04758   tor_assert(tok == smartlist_get(tokens, 0));
04759   tor_assert(tok->n_args == 1);
04760   if (strlen(tok->args[0]) != REND_DESC_ID_V2_LEN_BASE32 ||
04761       strspn(tok->args[0], BASE32_CHARS) != REND_DESC_ID_V2_LEN_BASE32) {
04762     log_warn(LD_REND, "Invalid descriptor ID: '%s'", tok->args[0]);
04763     goto err;
04764   }
04765   if (base32_decode(desc_id_out, DIGEST_LEN,
04766                     tok->args[0], REND_DESC_ID_V2_LEN_BASE32) < 0) {
04767     log_warn(LD_REND, "Descriptor ID contains illegal characters: %s",
04768              tok->args[0]);
04769     goto err;
04770   }
04771   /* Parse descriptor version. */
04772   tok = find_by_keyword(tokens, R_VERSION);
04773   tor_assert(tok->n_args == 1);
04774   result->version =
04775     (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL);
04776   if (result->version != 2 || !num_ok) {
04777     /* If it's <2, it shouldn't be under this format.  If the number
04778      * is greater than 2, we bumped it because we broke backward
04779      * compatibility.  See how version numbers in our other formats
04780      * work. */
04781     log_warn(LD_REND, "Unrecognized descriptor version: %s",
04782              escaped(tok->args[0]));
04783     goto err;
04784   }
04785   /* Parse public key. */
04786   tok = find_by_keyword(tokens, R_PERMANENT_KEY);
04787   result->pk = tok->key;
04788   tok->key = NULL; /* Prevent free */
04789   /* Parse secret ID part. */
04790   tok = find_by_keyword(tokens, R_SECRET_ID_PART);
04791   tor_assert(tok->n_args == 1);
04792   if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 ||
04793       strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) {
04794     log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]);
04795     goto err;
04796   }
04797   if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) < 0) {
04798     log_warn(LD_REND, "Secret ID part contains illegal characters: %s",
04799              tok->args[0]);
04800     goto err;
04801   }
04802   /* Parse publication time -- up-to-date check is done when storing the
04803    * descriptor. */
04804   tok = find_by_keyword(tokens, R_PUBLICATION_TIME);
04805   tor_assert(tok->n_args == 1);
04806   if (parse_iso_time(tok->args[0], &result->timestamp) < 0) {
04807     log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]);
04808     goto err;
04809   }
04810   /* Parse protocol versions. */
04811   tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS);
04812   tor_assert(tok->n_args == 1);
04813   versions = smartlist_new();
04814   smartlist_split_string(versions, tok->args[0], ",",
04815                          SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
04816   for (i = 0; i < smartlist_len(versions); i++) {
04817     version = (int) tor_parse_long(smartlist_get(versions, i),
04818                                    10, 0, INT_MAX, &num_ok, NULL);
04819     if (!num_ok) /* It's a string; let's ignore it. */
04820       continue;
04821     result->protocols |= 1 << version;
04822   }
04823   SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp));
04824   smartlist_free(versions);
04825   /* Parse encrypted introduction points. Don't verify. */
04826   tok = find_opt_by_keyword(tokens, R_INTRODUCTION_POINTS);
04827   if (tok) {
04828     if (strcmp(tok->object_type, "MESSAGE")) {
04829       log_warn(LD_DIR, "Bad object type: introduction points should be of "
04830                "type MESSAGE");
04831       goto err;
04832     }
04833     *intro_points_encrypted_out = tor_memdup(tok->object_body,
04834                                              tok->object_size);
04835     *intro_points_encrypted_size_out = tok->object_size;
04836   } else {
04837     *intro_points_encrypted_out = NULL;
04838     *intro_points_encrypted_size_out = 0;
04839   }
04840   /* Parse and verify signature. */
04841   tok = find_by_keyword(tokens, R_SIGNATURE);
04842   note_crypto_pk_op(VERIFY_RTR);
04843   if (check_signature_token(desc_hash, DIGEST_LEN, tok, result->pk, 0,
04844                             "v2 rendezvous service descriptor") < 0)
04845     goto err;
04846   /* Verify that descriptor ID belongs to public key and secret ID part. */
04847   crypto_pk_get_digest(result->pk, public_key_hash);
04848   rend_get_descriptor_id_bytes(test_desc_id, public_key_hash,
04849                                secret_id_part);
04850   if (tor_memneq(desc_id_out, test_desc_id, DIGEST_LEN)) {
04851     log_warn(LD_REND, "Parsed descriptor ID does not match "
04852              "computed descriptor ID.");
04853     goto err;
04854   }
04855   goto done;
04856  err:
04857   rend_service_descriptor_free(result);
04858   result = NULL;
04859  done:
04860   if (tokens) {
04861     SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
04862     smartlist_free(tokens);
04863   }
04864   if (area)
04865     memarea_drop_all(area);
04866   *parsed_out = result;
04867   if (result)
04868     return 0;
04869   return -1;
04870 }
04871 
04877 int
04878 rend_decrypt_introduction_points(char **ipos_decrypted,
04879                                  size_t *ipos_decrypted_size,
04880                                  const char *descriptor_cookie,
04881                                  const char *ipos_encrypted,
04882                                  size_t ipos_encrypted_size)
04883 {
04884   tor_assert(ipos_encrypted);
04885   tor_assert(descriptor_cookie);
04886   if (ipos_encrypted_size < 2) {
04887     log_warn(LD_REND, "Size of encrypted introduction points is too "
04888                       "small.");
04889     return -1;
04890   }
04891   if (ipos_encrypted[0] == (int)REND_BASIC_AUTH) {
04892     char iv[CIPHER_IV_LEN], client_id[REND_BASIC_AUTH_CLIENT_ID_LEN],
04893          session_key[CIPHER_KEY_LEN], *dec;
04894     int declen, client_blocks;
04895     size_t pos = 0, len, client_entries_len;
04896     crypto_digest_t *digest;
04897     crypto_cipher_t *cipher;
04898     client_blocks = (int) ipos_encrypted[1];
04899     client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE *
04900                          REND_BASIC_AUTH_CLIENT_ENTRY_LEN;
04901     if (ipos_encrypted_size < 2 + client_entries_len + CIPHER_IV_LEN + 1) {
04902       log_warn(LD_REND, "Size of encrypted introduction points is too "
04903                         "small.");
04904       return -1;
04905     }
04906     memcpy(iv, ipos_encrypted + 2 + client_entries_len, CIPHER_IV_LEN);
04907     digest = crypto_digest_new();
04908     crypto_digest_add_bytes(digest, descriptor_cookie, REND_DESC_COOKIE_LEN);
04909     crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN);
04910     crypto_digest_get_digest(digest, client_id,
04911                              REND_BASIC_AUTH_CLIENT_ID_LEN);
04912     crypto_digest_free(digest);
04913     for (pos = 2; pos < 2 + client_entries_len;
04914          pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN) {
04915       if (tor_memeq(ipos_encrypted + pos, client_id,
04916                   REND_BASIC_AUTH_CLIENT_ID_LEN)) {
04917         /* Attempt to decrypt introduction points. */
04918         cipher = crypto_cipher_new(descriptor_cookie);
04919         if (crypto_cipher_decrypt(cipher, session_key, ipos_encrypted
04920                                   + pos + REND_BASIC_AUTH_CLIENT_ID_LEN,
04921                                   CIPHER_KEY_LEN) < 0) {
04922           log_warn(LD_REND, "Could not decrypt session key for client.");
04923           crypto_cipher_free(cipher);
04924           return -1;
04925         }
04926         crypto_cipher_free(cipher);
04927 
04928         len = ipos_encrypted_size - 2 - client_entries_len - CIPHER_IV_LEN;
04929         dec = tor_malloc(len);
04930         declen = crypto_cipher_decrypt_with_iv(session_key, dec, len,
04931             ipos_encrypted + 2 + client_entries_len,
04932             ipos_encrypted_size - 2 - client_entries_len);
04933 
04934         if (declen < 0) {
04935           log_warn(LD_REND, "Could not decrypt introduction point string.");
04936           tor_free(dec);
04937           return -1;
04938         }
04939         if (fast_memcmpstart(dec, declen, "introduction-point ")) {
04940           log_warn(LD_REND, "Decrypted introduction points don't "
04941                             "look like we could parse them.");
04942           tor_free(dec);
04943           continue;
04944         }
04945         *ipos_decrypted = dec;
04946         *ipos_decrypted_size = declen;
04947         return 0;
04948       }
04949     }
04950     log_warn(LD_REND, "Could not decrypt introduction points. Please "
04951              "check your authorization for this service!");
04952     return -1;
04953   } else if (ipos_encrypted[0] == (int)REND_STEALTH_AUTH) {
04954     char *dec;
04955     int declen;
04956     if (ipos_encrypted_size < CIPHER_IV_LEN + 2) {
04957       log_warn(LD_REND, "Size of encrypted introduction points is too "
04958                         "small.");
04959       return -1;
04960     }
04961     dec = tor_malloc_zero(ipos_encrypted_size - CIPHER_IV_LEN - 1);
04962 
04963     declen = crypto_cipher_decrypt_with_iv(descriptor_cookie, dec,
04964                                            ipos_encrypted_size -
04965                                                CIPHER_IV_LEN - 1,
04966                                            ipos_encrypted + 1,
04967                                            ipos_encrypted_size - 1);
04968 
04969     if (declen < 0) {
04970       log_warn(LD_REND, "Decrypting introduction points failed!");
04971       tor_free(dec);
04972       return -1;
04973     }
04974     *ipos_decrypted = dec;
04975     *ipos_decrypted_size = declen;
04976     return 0;
04977   } else {
04978     log_warn(LD_REND, "Unknown authorization type number: %d",
04979              ipos_encrypted[0]);
04980     return -1;
04981   }
04982 }
04983 
04988 int
04989 rend_parse_introduction_points(rend_service_descriptor_t *parsed,
04990                                const char *intro_points_encoded,
04991                                size_t intro_points_encoded_size)
04992 {
04993   const char *current_ipo, *end_of_intro_points;
04994   smartlist_t *tokens;
04995   directory_token_t *tok;
04996   rend_intro_point_t *intro;
04997   extend_info_t *info;
04998   int result, num_ok=1;
04999   memarea_t *area = NULL;
05000   tor_assert(parsed);
05002   tor_assert(!parsed->intro_nodes);
05003   tor_assert(intro_points_encoded);
05004   tor_assert(intro_points_encoded_size > 0);
05005   /* Consider one intro point after the other. */
05006   current_ipo = intro_points_encoded;
05007   end_of_intro_points = intro_points_encoded + intro_points_encoded_size;
05008   tokens = smartlist_new();
05009   parsed->intro_nodes = smartlist_new();
05010   area = memarea_new();
05011 
05012   while (!fast_memcmpstart(current_ipo, end_of_intro_points-current_ipo,
05013                       "introduction-point ")) {
05014     /* Determine end of string. */
05015     const char *eos = tor_memstr(current_ipo, end_of_intro_points-current_ipo,
05016                                  "\nintroduction-point ");
05017     if (!eos)
05018       eos = end_of_intro_points;
05019     else
05020       eos = eos+1;
05021     tor_assert(eos <= intro_points_encoded+intro_points_encoded_size);
05022     /* Free tokens and clear token list. */
05023     SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
05024     smartlist_clear(tokens);
05025     memarea_clear(area);
05026     /* Tokenize string. */
05027     if (tokenize_string(area, current_ipo, eos, tokens, ipo_token_table, 0)) {
05028       log_warn(LD_REND, "Error tokenizing introduction point");
05029       goto err;
05030     }
05031     /* Advance to next introduction point, if available. */
05032     current_ipo = eos;
05033     /* Check minimum allowed length of introduction point. */
05034     if (smartlist_len(tokens) < 5) {
05035       log_warn(LD_REND, "Impossibly short introduction point.");
05036       goto err;
05037     }
05038     /* Allocate new intro point and extend info. */
05039     intro = tor_malloc_zero(sizeof(rend_intro_point_t));
05040     info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
05041     /* Parse identifier. */
05042     tok = find_by_keyword(tokens, R_IPO_IDENTIFIER);
05043     if (base32_decode(info->identity_digest, DIGEST_LEN,
05044                       tok->args[0], REND_INTRO_POINT_ID_LEN_BASE32) < 0) {
05045       log_warn(LD_REND, "Identity digest contains illegal characters: %s",
05046                tok->args[0]);
05047       rend_intro_point_free(intro);
05048       goto err;
05049     }
05050     /* Write identifier to nickname. */
05051     info->nickname[0] = '$';
05052     base16_encode(info->nickname + 1, sizeof(info->nickname) - 1,
05053                   info->identity_digest, DIGEST_LEN);
05054     /* Parse IP address. */
05055     tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS);
05056     if (tor_addr_parse(&info->addr, tok->args[0])<0) {
05057       log_warn(LD_REND, "Could not parse introduction point address.");
05058       rend_intro_point_free(intro);
05059       goto err;
05060     }
05061     if (tor_addr_family(&info->addr) != AF_INET) {
05062       log_warn(LD_REND, "Introduction point address was not ipv4.");
05063       rend_intro_point_free(intro);
05064       goto err;
05065     }
05066 
05067     /* Parse onion port. */
05068     tok = find_by_keyword(tokens, R_IPO_ONION_PORT);
05069     info->port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535,
05070                                            &num_ok,NULL);
05071     if (!info->port || !num_ok) {
05072       log_warn(LD_REND, "Introduction point onion port %s is invalid",
05073                escaped(tok->args[0]));
05074       rend_intro_point_free(intro);
05075       goto err;
05076     }
05077     /* Parse onion key. */
05078     tok = find_by_keyword(tokens, R_IPO_ONION_KEY);
05079     if (!crypto_pk_public_exponent_ok(tok->key)) {
05080       log_warn(LD_REND,
05081                "Introduction point's onion key had invalid exponent.");
05082       rend_intro_point_free(intro);
05083       goto err;
05084     }
05085     info->onion_key = tok->key;
05086     tok->key = NULL; /* Prevent free */
05087     /* Parse service key. */
05088     tok = find_by_keyword(tokens, R_IPO_SERVICE_KEY);
05089     if (!crypto_pk_public_exponent_ok(tok->key)) {
05090       log_warn(LD_REND,
05091                "Introduction point key had invalid exponent.");
05092       rend_intro_point_free(intro);
05093       goto err;
05094     }
05095     intro->intro_key = tok->key;
05096     tok->key = NULL; /* Prevent free */
05097     /* Add extend info to list of introduction points. */
05098     smartlist_add(parsed->intro_nodes, intro);
05099   }
05100   result = smartlist_len(parsed->intro_nodes);
05101   goto done;
05102 
05103  err:
05104   result = -1;
05105 
05106  done:
05107   /* Free tokens and clear token list. */
05108   SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
05109   smartlist_free(tokens);
05110   if (area)
05111     memarea_drop_all(area);
05112 
05113   return result;
05114 }
05115 
05120 int
05121 rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr)
05122 {
05123   int result = -1;
05124   smartlist_t *tokens;
05125   directory_token_t *tok;
05126   const char *current_entry = NULL;
05127   memarea_t *area = NULL;
05128   if (!ckstr || strlen(ckstr) == 0)
05129     return -1;
05130   tokens = smartlist_new();
05131   /* Begin parsing with first entry, skipping comments or whitespace at the
05132    * beginning. */
05133   area = memarea_new();
05134   current_entry = eat_whitespace(ckstr);
05135   while (!strcmpstart(current_entry, "client-name ")) {
05136     rend_authorized_client_t *parsed_entry;
05137     size_t len;
05138     char descriptor_cookie_tmp[REND_DESC_COOKIE_LEN+2];
05139     /* Determine end of string. */
05140     const char *eos = strstr(current_entry, "\nclient-name ");
05141     if (!eos)
05142       eos = current_entry + strlen(current_entry);
05143     else
05144       eos = eos + 1;
05145     /* Free tokens and clear token list. */
05146     SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
05147     smartlist_clear(tokens);
05148     memarea_clear(area);
05149     /* Tokenize string. */
05150     if (tokenize_string(area, current_entry, eos, tokens,
05151                         client_keys_token_table, 0)) {
05152       log_warn(LD_REND, "Error tokenizing client keys file.");
05153       goto err;
05154     }
05155     /* Advance to next entry, if available. */
05156     current_entry = eos;
05157     /* Check minimum allowed length of token list. */
05158     if (smartlist_len(tokens) < 2) {
05159       log_warn(LD_REND, "Impossibly short client key entry.");
05160       goto err;
05161     }
05162     /* Parse client name. */
05163     tok = find_by_keyword(tokens, C_CLIENT_NAME);
05164     tor_assert(tok == smartlist_get(tokens, 0));
05165     tor_assert(tok->n_args == 1);
05166 
05167     len = strlen(tok->args[0]);
05168     if (len < 1 || len > 19 ||
05169       strspn(tok->args[0], REND_LEGAL_CLIENTNAME_CHARACTERS) != len) {
05170       log_warn(LD_CONFIG, "Illegal client name: %s. (Length must be "
05171                "between 1 and 19, and valid characters are "
05172                "[A-Za-z0-9+-_].)", tok->args[0]);
05173       goto err;
05174     }
05175     /* Check if client name is duplicate. */
05176     if (strmap_get(parsed_clients, tok->args[0])) {
05177       log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains a "
05178                "duplicate client name: '%s'. Ignoring.", tok->args[0]);
05179       goto err;
05180     }
05181     parsed_entry = tor_malloc_zero(sizeof(rend_authorized_client_t));
05182     parsed_entry->client_name = tor_strdup(tok->args[0]);
05183     strmap_set(parsed_clients, parsed_entry->client_name, parsed_entry);
05184     /* Parse client key. */
05185     tok = find_opt_by_keyword(tokens, C_CLIENT_KEY);
05186     if (tok) {
05187       parsed_entry->client_key = tok->key;
05188       tok->key = NULL; /* Prevent free */
05189     }
05190 
05191     /* Parse descriptor cookie. */
05192     tok = find_by_keyword(tokens, C_DESCRIPTOR_COOKIE);
05193     tor_assert(tok->n_args == 1);
05194     if (strlen(tok->args[0]) != REND_DESC_COOKIE_LEN_BASE64 + 2) {
05195       log_warn(LD_REND, "Descriptor cookie has illegal length: %s",
05196                escaped(tok->args[0]));
05197       goto err;
05198     }
05199     /* The size of descriptor_cookie_tmp needs to be REND_DESC_COOKIE_LEN+2,
05200      * because a base64 encoding of length 24 does not fit into 16 bytes in all
05201      * cases. */
05202     if (base64_decode(descriptor_cookie_tmp, sizeof(descriptor_cookie_tmp),
05203                       tok->args[0], strlen(tok->args[0]))
05204         != REND_DESC_COOKIE_LEN) {
05205       log_warn(LD_REND, "Descriptor cookie contains illegal characters: "
05206                "%s", escaped(tok->args[0]));
05207       goto err;
05208     }
05209     memcpy(parsed_entry->descriptor_cookie, descriptor_cookie_tmp,
05210            REND_DESC_COOKIE_LEN);
05211   }
05212   result = strmap_size(parsed_clients);
05213   goto done;
05214  err:
05215   result = -1;
05216  done:
05217   /* Free tokens and clear token list. */
05218   SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
05219   smartlist_free(tokens);
05220   if (area)
05221     memarea_drop_all(area);
05222   return result;
05223 }
05224