tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

test_microdesc.c (38315B)


      1 /* Copyright (c) 2010-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 #include "orconfig.h"
      5 #include "core/or/or.h"
      6 
      7 #define DIRVOTE_PRIVATE
      8 #include "app/config/config.h"
      9 #include "feature/dirauth/dirvote.h"
     10 #include "feature/dirparse/microdesc_parse.h"
     11 #include "feature/dirparse/routerparse.h"
     12 #include "feature/nodelist/microdesc.h"
     13 #include "feature/nodelist/networkstatus.h"
     14 #include "feature/nodelist/nodefamily.h"
     15 #include "feature/nodelist/routerlist.h"
     16 #include "feature/nodelist/torcert.h"
     17 
     18 #include "feature/nodelist/microdesc_st.h"
     19 #include "feature/nodelist/networkstatus_st.h"
     20 #include "feature/nodelist/routerinfo_st.h"
     21 #include "feature/nodelist/routerstatus_st.h"
     22 
     23 #include "test/test.h"
     24 #include "test/log_test_helpers.h"
     25 
     26 #ifdef HAVE_SYS_STAT_H
     27 #include <sys/stat.h>
     28 #endif
     29 
     30 #ifdef _WIN32
     31 /* For mkdir() */
     32 #include <direct.h>
     33 #else
     34 #include <dirent.h>
     35 #endif /* defined(_WIN32) */
     36 
     37 static const char test_md1[] =
     38  "onion-key\n"
     39  "-----BEGIN RSA PUBLIC KEY-----\n"
     40  "MIGJAoGBAMjlHH/daN43cSVRaHBwgUfnszzAhg98EvivJ9Qxfv51mvQUxPjQ07es\n"
     41  "gV/3n8fyh3Kqr/ehi9jxkdgSRfSnmF7giaHL1SLZ29kA7KtST+pBvmTpDtHa3ykX\n"
     42  "Xorc7hJvIyTZoc1HU+5XSynj3gsBE5IGK1ZRzrNS688LnuZMVp1tAgMBAAE=\n"
     43  "-----END RSA PUBLIC KEY-----\n"
     44  "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n";
     45 
     46 static const char test_md2[] =
     47  "onion-key\n"
     48  "-----BEGIN RSA PUBLIC KEY-----\n"
     49  "MIGJAoGBAMIixIowh2DyPmDNMDwBX2DHcYcqdcH1zdIQJZkyV6c6rQHnvbcaDoSg\n"
     50  "jgFSLJKpnGmh71FVRqep+yVB0zI1JY43kuEnXry2HbZCD9UDo3d3n7t015X5S7ON\n"
     51  "bSSYtQGPwOr6Epf96IF6DoQxy4iDnPUAlejuhAG51s1y6/rZQ3zxAgMBAAE=\n"
     52  "-----END RSA PUBLIC KEY-----\n"
     53  "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n";
     54 
     55 static const char test_md3[] =
     56  "@last-listed 2009-06-22\n"
     57  "onion-key\n"
     58  "-----BEGIN RSA PUBLIC KEY-----\n"
     59  "MIGJAoGBAMH3340d4ENNGrqx7UxT+lB7x6DNUKOdPEOn4teceE11xlMyZ9TPv41c\n"
     60  "qj2fRZzfxlc88G/tmiaHshmdtEpklZ740OFqaaJVj4LjPMKFNE+J7Xc1142BE9Ci\n"
     61  "KgsbjGYe2RY261aADRWLetJ8T9QDMm+JngL4288hc8pq1uB/3TAbAgMBAAE=\n"
     62  "-----END RSA PUBLIC KEY-----\n"
     63  "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n"
     64  "p accept 1-700,800-1000\n"
     65  "family nodeX nodeY nodeZ\n";
     66 
     67 static void
     68 test_md_cache(void *data)
     69 {
     70  or_options_t *options = NULL;
     71  microdesc_cache_t *mc = NULL ;
     72  smartlist_t *added = NULL, *wanted = NULL;
     73  microdesc_t *md1, *md2, *md3;
     74  char d1[DIGEST256_LEN], d2[DIGEST256_LEN], d3[DIGEST256_LEN];
     75  const char *test_md3_noannotation = strchr(test_md3, '\n')+1;
     76  time_t time1, time2, time3;
     77  char *fn = NULL, *s = NULL;
     78  char *encoded_family = NULL;
     79  (void)data;
     80 
     81  options = get_options_mutable();
     82  tt_assert(options);
     83 
     84  time1 = time(NULL);
     85  time2 = time(NULL) - 2*24*60*60;
     86  time3 = time(NULL) - 15*24*60*60;
     87 
     88  /* Possibly, turn this into a test setup/cleanup pair */
     89  tor_free(options->CacheDirectory);
     90  options->CacheDirectory = tor_strdup(get_fname("md_datadir_test"));
     91 #ifdef _WIN32
     92  tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory));
     93 #else
     94  tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory, 0700));
     95 #endif
     96 
     97  tt_assert(!strcmpstart(test_md3_noannotation, "onion-key"));
     98 
     99  crypto_digest256(d1, test_md1, strlen(test_md1), DIGEST_SHA256);
    100  crypto_digest256(d2, test_md2, strlen(test_md1), DIGEST_SHA256);
    101  crypto_digest256(d3, test_md3_noannotation, strlen(test_md3_noannotation),
    102                   DIGEST_SHA256);
    103 
    104  mc = get_microdesc_cache();
    105 
    106  added = microdescs_add_to_cache(mc, test_md1, NULL, SAVED_NOWHERE, 0,
    107                                  time1, NULL);
    108  tt_int_op(1, OP_EQ, smartlist_len(added));
    109  md1 = smartlist_get(added, 0);
    110  smartlist_free(added);
    111  added = NULL;
    112 
    113  wanted = smartlist_new();
    114  added = microdescs_add_to_cache(mc, test_md2, NULL, SAVED_NOWHERE, 0,
    115                                  time2, wanted);
    116  /* Should fail, since we didn't list test_md2's digest in wanted */
    117  tt_int_op(0, OP_EQ, smartlist_len(added));
    118  smartlist_free(added);
    119  added = NULL;
    120 
    121  smartlist_add(wanted, tor_memdup(d2, DIGEST256_LEN));
    122  smartlist_add(wanted, tor_memdup(d3, DIGEST256_LEN));
    123  added = microdescs_add_to_cache(mc, test_md2, NULL, SAVED_NOWHERE, 0,
    124                                  time2, wanted);
    125  /* Now it can work. md2 should have been added */
    126  tt_int_op(1, OP_EQ, smartlist_len(added));
    127  md2 = smartlist_get(added, 0);
    128  /* And it should have gotten removed from 'wanted' */
    129  tt_int_op(smartlist_len(wanted), OP_EQ, 1);
    130  tt_mem_op(smartlist_get(wanted, 0), OP_EQ, d3, DIGEST256_LEN);
    131  smartlist_free(added);
    132  added = NULL;
    133 
    134  added = microdescs_add_to_cache(mc, test_md3, NULL,
    135                                  SAVED_NOWHERE, 0, -1, NULL);
    136  /* Must fail, since SAVED_NOWHERE precludes annotations */
    137  tt_int_op(0, OP_EQ, smartlist_len(added));
    138  smartlist_free(added);
    139  added = NULL;
    140 
    141  added = microdescs_add_to_cache(mc, test_md3_noannotation, NULL,
    142                                  SAVED_NOWHERE, 0, time3, NULL);
    143  /* Now it can work */
    144  tt_int_op(1, OP_EQ, smartlist_len(added));
    145  md3 = smartlist_get(added, 0);
    146  smartlist_free(added);
    147  added = NULL;
    148 
    149  /* Okay.  We added 1...3.  Let's poke them to see how they look, and make
    150   * sure they're really in the journal. */
    151  tt_ptr_op(md1, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d1));
    152  tt_ptr_op(md2, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d2));
    153  tt_ptr_op(md3, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d3));
    154 
    155  tt_int_op(md1->last_listed, OP_EQ, time1);
    156  tt_int_op(md2->last_listed, OP_EQ, time2);
    157  tt_int_op(md3->last_listed, OP_EQ, time3);
    158 
    159  tt_int_op(md1->saved_location, OP_EQ, SAVED_IN_JOURNAL);
    160  tt_int_op(md2->saved_location, OP_EQ, SAVED_IN_JOURNAL);
    161  tt_int_op(md3->saved_location, OP_EQ, SAVED_IN_JOURNAL);
    162 
    163  tt_int_op(md1->bodylen, OP_EQ, strlen(test_md1));
    164  tt_int_op(md2->bodylen, OP_EQ, strlen(test_md2));
    165  tt_int_op(md3->bodylen, OP_EQ, strlen(test_md3_noannotation));
    166  tt_mem_op(md1->body, OP_EQ, test_md1, strlen(test_md1));
    167  tt_mem_op(md2->body, OP_EQ, test_md2, strlen(test_md2));
    168  tt_mem_op(md3->body, OP_EQ, test_md3_noannotation,
    169              strlen(test_md3_noannotation));
    170 
    171  tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs.new",
    172               options->CacheDirectory);
    173  s = read_file_to_str(fn, RFTS_BIN, NULL);
    174  tt_assert(s);
    175  tt_mem_op(md1->body, OP_EQ, s + md1->off, md1->bodylen);
    176  tt_mem_op(md2->body, OP_EQ, s + md2->off, md2->bodylen);
    177  tt_mem_op(md3->body, OP_EQ, s + md3->off, md3->bodylen);
    178 
    179  tt_ptr_op(md1->family, OP_EQ, NULL);
    180  tt_ptr_op(md3->family, OP_NE, NULL);
    181 
    182  encoded_family = nodefamily_format(md3->family);
    183  tt_str_op(encoded_family, OP_EQ, "nodex nodey nodez");
    184 
    185  /* Now rebuild the cache! */
    186  tt_int_op(microdesc_cache_rebuild(mc, 1), OP_EQ, 0);
    187 
    188  tt_int_op(md1->saved_location, OP_EQ, SAVED_IN_CACHE);
    189  tt_int_op(md2->saved_location, OP_EQ, SAVED_IN_CACHE);
    190  tt_int_op(md3->saved_location, OP_EQ, SAVED_IN_CACHE);
    191 
    192  /* The journal should be empty now */
    193  tor_free(s);
    194  s = read_file_to_str(fn, RFTS_BIN, NULL);
    195  tt_str_op(s, OP_EQ, "");
    196  tor_free(s);
    197  tor_free(fn);
    198 
    199  /* read the cache. */
    200  tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs",
    201               options->CacheDirectory);
    202  s = read_file_to_str(fn, RFTS_BIN, NULL);
    203  tt_mem_op(md1->body, OP_EQ, s + md1->off, strlen(test_md1));
    204  tt_mem_op(md2->body, OP_EQ, s + md2->off, strlen(test_md2));
    205  tt_mem_op(md3->body, OP_EQ, s + md3->off, strlen(test_md3_noannotation));
    206 
    207  /* Okay, now we are going to forget about the cache entirely, and reload it
    208   * from the disk. */
    209  microdesc_free_all();
    210  mc = get_microdesc_cache();
    211  md1 = microdesc_cache_lookup_by_digest256(mc, d1);
    212  md2 = microdesc_cache_lookup_by_digest256(mc, d2);
    213  md3 = microdesc_cache_lookup_by_digest256(mc, d3);
    214  tt_assert(md1);
    215  tt_assert(md2);
    216  tt_assert(md3);
    217  tt_mem_op(md1->body, OP_EQ, s + md1->off, strlen(test_md1));
    218  tt_mem_op(md2->body, OP_EQ, s + md2->off, strlen(test_md2));
    219  tt_mem_op(md3->body, OP_EQ, s + md3->off, strlen(test_md3_noannotation));
    220 
    221  tt_int_op(md1->last_listed, OP_EQ, time1);
    222  tt_int_op(md2->last_listed, OP_EQ, time2);
    223  tt_int_op(md3->last_listed, OP_EQ, time3);
    224 
    225  /* Okay, now we are going to clear out everything older than a week old.
    226   * In practice, that means md3 */
    227  microdesc_cache_clean(mc, time(NULL)-7*24*60*60, 1/*force*/);
    228  tt_ptr_op(md1, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d1));
    229  tt_ptr_op(md2, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d2));
    230  tt_ptr_op(NULL, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d3));
    231  md3 = NULL; /* it's history now! */
    232 
    233  /* rebuild again, make sure it stays gone. */
    234  tt_int_op(microdesc_cache_rebuild(mc, 1), OP_EQ, 0);
    235  tt_ptr_op(md1, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d1));
    236  tt_ptr_op(md2, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d2));
    237  tt_ptr_op(NULL, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d3));
    238 
    239  /* Re-add md3, and make sure we can rebuild the cache. */
    240  added = microdescs_add_to_cache(mc, test_md3_noannotation, NULL,
    241                                  SAVED_NOWHERE, 0, time3, NULL);
    242  tt_int_op(1, OP_EQ, smartlist_len(added));
    243  md3 = smartlist_get(added, 0);
    244  smartlist_free(added);
    245  added = NULL;
    246  tt_int_op(md1->saved_location, OP_EQ, SAVED_IN_CACHE);
    247  tt_int_op(md2->saved_location, OP_EQ, SAVED_IN_CACHE);
    248  tt_int_op(md3->saved_location, OP_EQ, SAVED_IN_JOURNAL);
    249 
    250  tt_int_op(microdesc_cache_rebuild(mc, 1), OP_EQ, 0);
    251  tt_int_op(md3->saved_location, OP_EQ, SAVED_IN_CACHE);
    252 
    253 done:
    254  if (options)
    255    tor_free(options->CacheDirectory);
    256  microdesc_free_all();
    257 
    258  smartlist_free(added);
    259  if (wanted)
    260    SMARTLIST_FOREACH(wanted, char *, cp, tor_free(cp));
    261  smartlist_free(wanted);
    262  tor_free(s);
    263  tor_free(fn);
    264  tor_free(encoded_family);
    265 }
    266 
    267 static const char truncated_md[] =
    268  "@last-listed 2013-08-08 19:02:59\n"
    269  "onion-key\n"
    270  "-----BEGIN RSA PUBLIC KEY-----\n"
    271  "MIGJAoGBAM91vLFNaM+gGhnRIdz2Cm/Kl7Xz0cOobIdVzhS3cKUJfk867hCuTipS\n"
    272  "NveLBzNopvgXKruAAzEj3cACxk6Q8lv5UWOGCD1UolkgsWSE62RBjap44g+oc9J1\n"
    273  "RI9968xOTZw0VaBQg9giEILNXl0djoikQ+5tQRUvLDDa67gpa5Q1AgMBAAE=\n"
    274  "-----END RSA PUBLIC KEY-----\n"
    275  "family @\n";
    276 
    277 static void
    278 test_md_cache_broken(void *data)
    279 {
    280  or_options_t *options;
    281  char *fn=NULL;
    282  microdesc_cache_t *mc = NULL;
    283 
    284  (void)data;
    285 
    286  options = get_options_mutable();
    287  tt_assert(options);
    288  tor_free(options->CacheDirectory);
    289  options->CacheDirectory = tor_strdup(get_fname("md_datadir_test2"));
    290 
    291 #ifdef _WIN32
    292  tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory));
    293 #else
    294  tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory, 0700));
    295 #endif
    296 
    297  tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs",
    298               options->CacheDirectory);
    299 
    300  write_str_to_file(fn, truncated_md, 1);
    301 
    302  mc = get_microdesc_cache();
    303  tt_assert(mc);
    304 
    305 done:
    306  if (options)
    307    tor_free(options->CacheDirectory);
    308  tor_free(fn);
    309  microdesc_free_all();
    310 }
    311 
    312 /* Generated by chutney. */
    313 static const char test_ri[] =
    314  "router test005r 127.0.0.1 5005 0 7005\n"
    315  "identity-ed25519\n"
    316  "-----BEGIN ED25519 CERT-----\n"
    317  "AQQABs1eAfTuBhu6ypB5/9avDiY3qBzulkCvfYqbFN/ABk/o4xFcAQAgBAAnmWRG\n"
    318  "rIvqpb4Kk3cThEiWAll4uDCO2Y46uNm9WG7AtPt4LG+XfktG3GAxv6aVQimwlyHc\n"
    319  "1x2Lfm9KG3mWWj+hxnum4Z7873OE0B9l2Hg0YQZCW/PuHSWN0rspTvY5SgA=\n"
    320  "-----END ED25519 CERT-----\n"
    321  "master-key-ed25519 J5lkRqyL6qW+CpN3E4RIlgJZeLgwjtmOOrjZvVhuwLQ\n"
    322  "or-address [::]:5005\n"
    323  "platform Tor 0.4.5.0-alpha-dev on Linux\n"
    324  "proto Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 "
    325      "HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-3\n"
    326  "published 2020-10-13 13:27:34\n"
    327  "fingerprint D219 590A C951 3BCD EBBA 9AB7 2100 7A4C C01B BAE3\n"
    328  "uptime 324451\n"
    329  "bandwidth 1073741824 1073741824 637796\n"
    330  "extra-info-digest 78E6D382BC826B95B4111554EEE7D541A32AAAA3 "
    331       "c61Onjpq+1S0TrdvoaOvGAxew6yfO+uHNhipbemQmgA\n"
    332  "onion-key\n"
    333  "-----BEGIN RSA PUBLIC KEY-----\n"
    334  "MIGJAoGBAMvEJ/JVNK7I38PPWhQMuCgkET/ki4WIas4tj5Kmqfb9kHqxMR+EunRD\n"
    335  "83k4pel1yB7QdV+iTd/4SZOI8RpZP+BO1KnOTWfpztAU1lDGr19/PwdwcHaILpBD\n"
    336  "nNzm6otk4/bKUQ0vqpOfJljtg0DfAm4uMAQ6BMFy6uEAF7+JupuPAgMBAAE=\n"
    337  "-----END RSA PUBLIC KEY-----\n"
    338  "signing-key\n"
    339  "-----BEGIN RSA PUBLIC KEY-----\n"
    340  "MIGJAoGBANBzejGAwyPTPq2Gm03wpg3qICo0uDQau8opude2mW3eyxAqOqHzC8De\n"
    341  "gRgbmn040vqe9gwvH4iaHpVeTxyDwQefbfULdq6bETmX3aSUj6LKBCqqcyuOJFQu\n"
    342  "7M2QfNSfHtldUABpIaqFvEA3AV8qjOoUtauoFNJKMy7Wj2//S70VAgMBAAE=\n"
    343  "-----END RSA PUBLIC KEY-----\n"
    344  "onion-key-crosscert\n"
    345  "-----BEGIN CROSSCERT-----\n"
    346  "pD3Nkkunt8zP6PO6H3uHT0t7xnorC7cY/KfF75mFB+90pHCD9f0Xdu3Pjrur/q23\n"
    347  "PIKV3hdtdsODoJuoh8LPGNAjS5rO6HMCtHNDNunNOs69bvfaO0jThnurXmOpY0sW\n"
    348  "eRfBeYN2KNgrN0B1eDejfPSr03dkFY48yoUDROv9EJQ=\n"
    349  "-----END CROSSCERT-----\n"
    350  "ntor-onion-key-crosscert 0\n"
    351  "-----BEGIN ED25519 CERT-----\n"
    352  "AQoABs2OASeZZEasi+qlvgqTdxOESJYCWXi4MI7Zjjq42b1YbsC0AKc5y5qYUYvw\n"
    353  "VATtWkV9DVIZbZSb9mQP5pmNaqmX+DbmINCYt8j7l+U7g3ftUyh0Wlrgevx0pFUI\n"
    354  "RcIU0HKHZQA=\n"
    355  "-----END ED25519 CERT-----\n"
    356  "hidden-service-dir\n"
    357  "ntor-onion-key FChIfm77vrWB7JsxQ+jMbN6VSSp1P0DYbw/2aqey4iA\n"
    358  "accept *:*\n"
    359  "tunnelled-dir-server\n"
    360  "router-sig-ed25519 Xm56dYbo/hCHWyzcdUPmfTeZ4qly2TYf1/2Q1lXKQDMJyBti"
    361      "8ZE8R2TTYsYimr+UtAapbzBItccZLze505nhBw\n"
    362  "router-signature\n"
    363  "-----BEGIN SIGNATURE-----\n"
    364  "bbeN0lq6nCfJQXGcKa1M9TQ6b2upig7clrlVXuzKeR0JhGwnDCXUAFxDtrw3vkVo\n"
    365  "ExBXXvJeBPyustFOQkdiAEWHHSW5CwEgeVCBYZeEnaiySIgDVKuu+9B53ezFdC0Y\n"
    366  "iFJkKxxDx7ksxX0zdl7aPT4ORFEuRhCYS6el7YJmoyg=\n"
    367  "-----END SIGNATURE-----\n";
    368 
    369 static const char test_md2_withfamily_33[] =
    370  "onion-key\n"
    371  "-----BEGIN RSA PUBLIC KEY-----\n"
    372  "MIGJAoGBAMvEJ/JVNK7I38PPWhQMuCgkET/ki4WIas4tj5Kmqfb9kHqxMR+EunRD\n"
    373  "83k4pel1yB7QdV+iTd/4SZOI8RpZP+BO1KnOTWfpztAU1lDGr19/PwdwcHaILpBD\n"
    374  "nNzm6otk4/bKUQ0vqpOfJljtg0DfAm4uMAQ6BMFy6uEAF7+JupuPAgMBAAE=\n"
    375  "-----END RSA PUBLIC KEY-----\n"
    376  "ntor-onion-key FChIfm77vrWB7JsxQ+jMbN6VSSp1P0DYbw/2aqey4iA\n"
    377  "family !Strange $D219590AC9513BCDEBBA9AB721007A4CC01BBAE3 othernode\n"
    378  "p accept 1-65535\n"
    379  "id ed25519 J5lkRqyL6qW+CpN3E4RIlgJZeLgwjtmOOrjZvVhuwLQ\n";
    380 
    381 static const char test_md2_withfamilyids_35[] =
    382  "onion-key\n"
    383  "-----BEGIN RSA PUBLIC KEY-----\n"
    384  "MIGJAoGBAMvEJ/JVNK7I38PPWhQMuCgkET/ki4WIas4tj5Kmqfb9kHqxMR+EunRD\n"
    385  "83k4pel1yB7QdV+iTd/4SZOI8RpZP+BO1KnOTWfpztAU1lDGr19/PwdwcHaILpBD\n"
    386  "nNzm6otk4/bKUQ0vqpOfJljtg0DfAm4uMAQ6BMFy6uEAF7+JupuPAgMBAAE=\n"
    387  "-----END RSA PUBLIC KEY-----\n"
    388  "ntor-onion-key FChIfm77vrWB7JsxQ+jMbN6VSSp1P0DYbw/2aqey4iA\n"
    389  "family !Strange $D219590AC9513BCDEBBA9AB721007A4CC01BBAE3 othernode\n"
    390  "family-ids "
    391       "ed25519:YWxsIGhhcHB5IGZhbWlsaWVzIGFyZSBhbGlrZSAtTFQ "
    392       "rlwe:0YHRh9Cw0YHRgtC70LjQstGL0LUg0YHQtdC80YzQuC0\n"
    393  "p accept 1-65535\n"
    394  "id ed25519 J5lkRqyL6qW+CpN3E4RIlgJZeLgwjtmOOrjZvVhuwLQ\n";
    395 
    396 static void
    397 test_md_generate(void *arg)
    398 {
    399  routerinfo_t *ri;
    400  microdesc_t *md = NULL;
    401  (void)arg;
    402 
    403  ri = router_parse_entry_from_string(test_ri, NULL, 0, 0, NULL, NULL);
    404  tt_assert(ri);
    405 
    406  // Try family encoding.
    407  microdesc_free(md);
    408  ri->declared_family = smartlist_new();
    409  smartlist_add_strdup(ri->declared_family, "OtherNode !Strange");
    410  md = dirvote_create_microdescriptor(ri, 33);
    411  tt_str_op(md->body, OP_EQ, test_md2_withfamily_33);
    412 
    413  // Try family-ids.
    414  microdesc_free(md);
    415  ri->family_ids = smartlist_new();
    416  smartlist_add_strdup(ri->family_ids,
    417                       "ed25519:YWxsIGhhcHB5IGZhbWlsaWVzIGFyZSBhbGlrZSAtTFQ");
    418  smartlist_add_strdup(ri->family_ids,
    419                       "rlwe:0YHRh9Cw0YHRgtC70LjQstGL0LUg0YHQtdC80YzQuC0");
    420  md = dirvote_create_microdescriptor(ri, 35);
    421  tt_str_op(md->body, OP_EQ, test_md2_withfamilyids_35);
    422 
    423 done:
    424  microdesc_free(md);
    425  routerinfo_free(ri);
    426 }
    427 
    428 #ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
    429 DISABLE_GCC_WARNING("-Woverlength-strings")
    430 /* We allow huge string constants in the unit tests, but not in the code
    431 * at large. */
    432 #endif
    433 /* Taken at random from my ~/.tor/cached-microdescs file and then
    434 * hand-munged */
    435 static const char MD_PARSE_TEST_DATA[] =
    436  /* Good 0 */
    437  "onion-key\n"
    438  "-----BEGIN RSA PUBLIC KEY-----\n"
    439  "MIGJAoGBANsKd1GRfOuSR1MkcwKqs6SVy4Gi/JXplt/bHDkIGm6Q96TeJ5uyVgUL\n"
    440  "DBr/ij6+JqgVFeriuiMzHKREytzjdaTuKsKBFFpLwb+Ppcjr5nMIH/AR6/aHO8hW\n"
    441  "T3B9lx5T6Kl7CqZ4yqXxYRHzn50EPTIZuz0y9se4J4gi9mLmL+pHAgMBAAE=\n"
    442  "-----END RSA PUBLIC KEY-----\n"
    443  "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n"
    444  "p accept 20-23,43,53,79-81,88,110,143,194,220,443,464,531,543-544\n"
    445  "id rsa1024 GEo59/iR1GWSIWZDzXTd5QxtqnU\n"
    446  /* Bad 0: I've messed with the onion-key in the second one. */
    447  "onion-key\n"
    448  "-----BEGIN RSA PUBLIC KEY-----\n"
    449  "MIGJAoGBAMr4o/pflVwscx11vC1AKEADlKEqnhpvCIjAEzNEenMhvGQHRlA0EXLC\n"
    450  "7G7O5bhnCwEHqK8Pvg8cuX/fD8v08TF1EVPhwPa0UI6ab8KnPP2F!!!!!!b92DG7EQIk3q\n"
    451  "d68Uxp7E9/t3v1WWZjzDqvEe0par6ul+DKW6HMlTGebFo5Q4e8R1AgMBAAE=\n"
    452  "-----END RSA PUBLIC KEY-----\n"
    453  "ntor-onion-key 761Dmm27via7lXygNHM3l+oJLrYU2Nye0Uz4pkpipyY=\n"
    454  "p accept 53\n"
    455  "id rsa1024 3Y4fwXhtgkdGDZ5ef5mtb6TJRQQ\n"
    456  /* Good 1 */
    457  "onion-key\n"
    458  "-----BEGIN RSA PUBLIC KEY-----\n"
    459  "MIGJAoGBANsMSjVi3EX8ZHfm/dvPF6KdVR66k1tVul7Jp+dDbDajBYNhgKRzVCxy\n"
    460  "Yac1CBuQjOqK89tKap9PQBnhF087eDrfaZDqYTLwB2W2sBJncVej15WEPXPRBifo\n"
    461  "iFZ8337kgczkaY+IOfSuhtbOUyDOoDpRJheIKBNq0ZiTqtLbbadVAgMBAAE=\n"
    462  "-----END RSA PUBLIC KEY-----\n"
    463  "ntor-onion-key ncfiHJjSgdDEW/gc6q6/7idac7j+x7ejQrRm6i75pGA=\n"
    464  "p accept 443,6660-6669,6697,7000-7001\n"
    465  "id rsa1024 XXuLzw3mfBELEq3veXoNhdehwD4\n"
    466  /* Good 2 */
    467  "onion-key\n"
    468  "-----BEGIN RSA PUBLIC KEY-----\n"
    469  "MIGJAoGBANQfBlrHrh9F/CAOytrNFgi0ikWMW/HZxuoszF9X+AQ+MudR8bcxxOGl\n"
    470  "1RFwb74s8E3uuzrCkNFvSw9Ar1L02F2DOX0gLsxEGuYC4Ave9NUteGqSqDyEJQUJ\n"
    471  "KlfxCPn2qC9nvNT7wR/Dg2WRvAEKnJmkpb57N3+WSAOPLjKOFEz3AgMBAAE=\n"
    472  "-----END RSA PUBLIC KEY-----\n"
    473  "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n"
    474  "id rsa1024 6y60AEI9a1PUUlRPO0YQT9WzrjI\n"
    475  /* Bad 1: Here I've messed with the ntor key */
    476  "onion-key\n"
    477  "-----BEGIN RSA PUBLIC KEY-----\n"
    478  "MIGJAoGBAPjy2HacU3jDNO5nTOFGSwNa0qKCNn4yhtrDVcAJ5alIQeBWZZGJLZ0q\n"
    479  "Cqylw1vYqxu8E09g+QXXFbAgBv1U9TICaATxrIJhIJzc8TJPhqJemp1kq0DvHLDx\n"
    480  "mxwlkNnCD/P5NS+JYB3EjOlU9EnSKUWNU61+Co344m2JqhEau40vAgMBAAE=\n"
    481  "-----END RSA PUBLIC KEY-----\n"
    482  "ntor-onion-key 4i2Fp9JHTUr1uQs0pxD5j5spl4/RG56S2P0gQxU=\n"
    483  "id rsa1024 nMRmNEGysA0NmlALVaUmI7D5jLU\n"
    484  /* Good 3: I've added a weird token in this one. This shouldn't prevent
    485   * it parsing */
    486  "onion-key\n"
    487  "-----BEGIN RSA PUBLIC KEY-----\n"
    488  "MIGJAoGBAKmosxudyNA/yJNz3S890VqV/ebylzoD11Sc0b/d5tyNNaNZjcYy5vRD\n"
    489  "kwyxFRMbP2TLZQ1zRfNwY7IDnYjU2SbW0pxuM6M8WRtsmx/YOE3kHMVAFJNrTUqU\n"
    490  "6D1zB3IiRDS5q5+NoRxwqo+hYUck60O3WTwEoqb+l3lvXeu7z9rFAgMBAAE=\n"
    491  "-----END RSA PUBLIC KEY-----\n"
    492  "flux-capacitor 1.21 GW\n"
    493  "ntor-onion-key MWBoEkl+RlBiGX44XKIvTSqbznTNZStOmUYtcYRQQyY=\n"
    494  "id rsa1024 R+A5O9qRvRac4FT3C4L2QnFyxsc\n"
    495  /* Good 4: Here I've made the 'id rsa' token odd.  It should still parse
    496   * just fine. */
    497  "onion-key\n"
    498  "-----BEGIN RSA PUBLIC KEY-----\n"
    499  "MIGJAoGBAOh+WMkdNe/Pkjb8UjQyfLOlFgpuVFrxAIGnJsmWWx0yBE97DQxGyh2n\n"
    500  "h8G5OJZHRarJQyCIf7vpZQAi0oP0OkGGaCaDQsM+D8TnqhnU++RWGnMqY/cXxPrL\n"
    501  "MEq+n6aGiLmzkO7ah8yorZpoREk4GqLUIN89/tHHGOhJL3c4CPGjAgMBAAE=\n"
    502  "-----END RSA PUBLIC KEY-----\n"
    503  "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n"
    504  "p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999\n"
    505  "id rsa1234 jlqAKFD2E7uMKv+8TmKSeo7NBho\n"
    506  /* Good 5: Extra id type. */
    507  "onion-key\n"
    508  "-----BEGIN RSA PUBLIC KEY-----\n"
    509  "MIGJAoGBAMdgPPc5uaw4y/q+SUTN/I8Y+Gvdx9kKgWV4dmDGJ0mxsVZmo1v6+v3F\n"
    510  "12M2f9m99G3WB8F8now29C+9XyEv8MBHj1lHRdUFHSQes3YTFvDNlgj+FjLqO5TJ\n"
    511  "adOOmfu4DCUUtUEDyQKbNVL4EkMTXY73omTVsjcH3xxFjTx5wixhAgMBAAE=\n"
    512  "-----END RSA PUBLIC KEY-----\n"
    513  "ntor-onion-key AAVnWZcnDbxasdZwKqb4fL6O9sZV+XsRNHTpNd1YMz8=\n"
    514  "id rsa1024 72EfBL11QuwX2vU8y+p9ExGfGEg\n"
    515  "id expolding hedgehog 0+A5O9qRvRac4FT3C4L2QnFyxsc\n"
    516  /* Good 6: I've given this a bogus policy. It should parse. */
    517  "onion-key\n"
    518  "-----BEGIN RSA PUBLIC KEY-----\n"
    519  "MIGJAoGBALNuufwhPMF8BooxYMNvhYJMPqUB8hQDt8wGmPKphJcD1sVD1i4gAZM2\n"
    520  "HIo+zUBlljDrRWL5NzVzd1yxUJAiQxvXS5dRRFY3B70M7wTVpXw53xe0/BM5t1AX\n"
    521  "n0MFk7Jl6XIKMlzRalZvmMvE/odtyWXkP4Nd1MyZ1QcIwrQ2iwyrAgMBAAE=\n"
    522  "-----END RSA PUBLIC KEY-----\n"
    523  "p condone 1-10\n"
    524  "ntor-onion-key 2/nMJ+L4dd/2GpMyTYjz3zC59MvQy4MIzJZhdzKHekg=\n"
    525  "id rsa1024 FHyh10glEMA6MCmBb5R9Y+X/MhQ\n"
    526  /* Good 7: I've given this one another sort of odd policy. Should parse. */
    527  "onion-key\n"
    528  "-----BEGIN RSA PUBLIC KEY-----\n"
    529  "MIGJAoGBAKcd3FmQ8iAADghyvX8eca0ePqtJ2w1IDdUdTlf5Y/8+OMdp//sD01yC\n"
    530  "YmiX45LK5ge1O3AzcakYCO6fb3pyIqvXdvm24OjyYZELQ40cmKSLjdhcSf4Fr/N9\n"
    531  "uR/CkknR9cEePu1wZ5WBIGmGdXI6s7t3LB+e7XFyBYAx6wMGlnX7AgMBAAE=\n"
    532  "-----END RSA PUBLIC KEY-----\n"
    533  "p accept frogs-mice\n"
    534  "ntor-onion-key AMxvhaQ1Qg7jBJFoyHuPRgETvLbFmJ194hExV24FuAI=\n"
    535  "family $D8CFEA0D996F5D1473D2063C041B7910DB23981E\n"
    536  "id rsa1024 d0VVZC/cHh1P3y4MMbfKlQHFycc\n"
    537  /* Good 8: This one has the ntor-onion-key without terminating =. That's
    538   * allowed. */
    539  "onion-key\n"
    540  "-----BEGIN RSA PUBLIC KEY-----\n"
    541  "MIGJAoGBAL438YfjrJE2SPqkkXeQwICygu8KNO54Juj6sjqk5hgsiazIWMOBgbaX\n"
    542  "LIRqPNGaiSq01xSqwjwCBCfwZYT/nSdDBqj1h9aoR8rnjxZjyQ+m3rWpdDqeCDMx\n"
    543  "I3NgZ5w4bNX4poRb42lrV6NmQiFdjzpqszVbv5Lpn2CSKu32CwKVAgMBAAE=\n"
    544  "-----END RSA PUBLIC KEY-----\n"
    545  "ntor-onion-key UKL6Dnj2KwYsFlkCvOkXVatxvOPB4MaxqwPQQgZMTwI\n"
    546  "id rsa1024 FPIXc6k++JnKCtSKWUxaR6oXEKs\n"
    547  /* Good 9: Another totally normal one.*/
    548  "onion-key\n"
    549  "-----BEGIN RSA PUBLIC KEY-----\n"
    550  "MIGJAoGBANNGIKRd8PFNXkJ2JPV1ohDMFNbJwKbwybeieaQFjtU9KWedHCbr+QD4\n"
    551  "B6zNY5ysguNjHNnlq2f6D09+uhnfDBON8tAz0mPQH/6JqnOXm+EiUn+8bN0E8Nke\n"
    552  "/i3GEgDeaxJJMNQcpsJvmmSmKFOlYy9Fy7ejAjTGqtAnqOte7BnTAgMBAAE=\n"
    553  "-----END RSA PUBLIC KEY-----\n"
    554  "ntor-onion-key gUsq3e5iYgsQQvyxINtLzBpHxmIt5rtuFlEbKfI4gFk=\n"
    555  "id rsa1024 jv+LdatDzsMfEW6pLBeL/5uzwCc\n"
    556  /* Bad 2: RSA key has bad exponent of 3. */
    557  "onion-key\n"
    558  "-----BEGIN RSA PUBLIC KEY-----\n"
    559  "MIGHAoGBAMMTWtvPxYnUNJ5Y7B+XENcpxzPoGstrdiUszCBS+/42xvluLJ+JDSdR\n"
    560  "qJaMD6ax8vKAeLS5C6O17MNdG2VldlPRbtgl41MXsOoUqEJ+nY9e3WG9Snjp47xC\n"
    561  "zmWIfeduXSavIsb3a43/MLIz/9qO0TkgAAiuQr79JlwKhLdzCqTLAgED\n"
    562  "-----END RSA PUBLIC KEY-----\n"
    563  "ntor-onion-key NkRB4wTUFogiVp5jYmjGORe2ffb/y5Kk8Itw8jdzMjA=\n"
    564  "p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999\n"
    565  "id rsa1024 fKvYjP7TAjCC1FzYee5bYAwYkoDg\n"
    566  /* Bad 3: Bogus annotation */
    567  "@last-listed with strange aeons\n"
    568  "onion-key\n"
    569  "-----BEGIN RSA PUBLIC KEY-----\n"
    570  "MIGJAoGBALcRBFNCZtpd2TFJysU77/fJMFzKisRQEBOtDGtTZ2Bg4aEGosssa0Id\n"
    571  "YtUagRLYle08QVGvGB+EHBI5qf6Ah2yPH7k5QiN2a3Sq+nyh85dXKPazBGBBbM+C\n"
    572  "DOfDauV02CAnADNMLJEf1voY3oBVvYyIsmHxn5i1R19ZYIiR8NX5AgMBAAE=\n"
    573  "-----END RSA PUBLIC KEY-----\n"
    574  "ntor-onion-key m4xcFXMWMjCvZDXq8FT3XmS0EHYseGOeu+fV+6FYDlk=\n"
    575  "p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544\n"
    576  "id rsa1024 SSbfNE9vmaiwRKH+eqNAkiKQhds\n"
    577  /* Good 10: Normal, with added ipv6 address and added other address */
    578  "onion-key\n"
    579  "-----BEGIN RSA PUBLIC KEY-----\n"
    580  "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
    581  "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
    582  "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
    583  "-----END RSA PUBLIC KEY-----\n"
    584  "a [::1:2:3:4]:9090\n"
    585  "a 18.0.0.1:9999\n"
    586  "ntor-onion-key k2yFqTU2vzMCQDEiE/j9UcEHxKrXMLpB3IL0or09sik=\n"
    587  "id rsa1024 2A8wYpHxnkKJ92orocvIQBzeHlE\n"
    588  "p6 allow 80\n"
    589  /* Good 11: Normal, non-exit relay with ipv6 address */
    590  "onion-key\n"
    591  "-----BEGIN RSA PUBLIC KEY-----\n"
    592  "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
    593  "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
    594  "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
    595  "-----END RSA PUBLIC KEY-----\n"
    596  "a [::1:2:3:4]:9090\n"
    597  "a 18.0.0.1:9999\n"
    598  "ntor-onion-key k2yFqTU2vzMCQDEiE/j9UcEHxKrXMLpB3IL0or09sik=\n"
    599  "id rsa1024 2A8wYpHxnkKJ92orocvIQBzeHlE\n"
    600  /* Good 12: Normal, exit relay with ipv6 address */
    601  "onion-key\n"
    602  "-----BEGIN RSA PUBLIC KEY-----\n"
    603  "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
    604  "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
    605  "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
    606  "-----END RSA PUBLIC KEY-----\n"
    607  "a [::1:2:3:4]:9090\n"
    608  "a 18.0.0.1:9999\n"
    609  "ntor-onion-key k2yFqTU2vzMCQDEiE/j9UcEHxKrXMLpB3IL0or09sik=\n"
    610  "p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544\n"
    611  "id rsa1024 2A8wYpHxnkKJ92orocvIQBzeHlE\n"
    612  /* Good 13: Normal, exit relay with only ipv6 exit policy */
    613  "onion-key\n"
    614  "-----BEGIN RSA PUBLIC KEY-----\n"
    615  "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
    616  "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
    617  "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
    618  "-----END RSA PUBLIC KEY-----\n"
    619  "a [::1:2:3:4]:9090\n"
    620  "a 18.0.0.1:9999\n"
    621  "ntor-onion-key k2yFqTU2vzMCQDEiE/j9UcEHxKrXMLpB3IL0or09sik=\n"
    622  "p6 accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544\n"
    623  "id rsa1024 2A8wYpHxnkKJ92orocvIQBzeHlE\n"
    624  ;
    625 #ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
    626 ENABLE_GCC_WARNING("-Woverlength-strings")
    627 #endif
    628 
    629 /** More tests for parsing different kinds of microdescriptors, and getting
    630 * invalid digests trackd from them. */
    631 static void
    632 test_md_parse(void *arg)
    633 {
    634  (void) arg;
    635  char *mem_op_hex_tmp = NULL;
    636  smartlist_t *invalid = smartlist_new();
    637 
    638  smartlist_t *mds = microdescs_parse_from_string(MD_PARSE_TEST_DATA,
    639                                                  NULL, 1, SAVED_NOWHERE,
    640                                                  invalid);
    641  tt_int_op(smartlist_len(mds), OP_EQ, 14);
    642  tt_int_op(smartlist_len(invalid), OP_EQ, 4);
    643 
    644  test_memeq_hex(smartlist_get(invalid,0),
    645                 "5d76bf1c6614e885614a1e0ad074e1ab"
    646                 "4ea14655ebeefb1736a71b5ed8a15a51");
    647  test_memeq_hex(smartlist_get(invalid,1),
    648                 "2fde0ee3343669c2444cd9d53cbd39c6"
    649                 "a7d1fc0513513e840ca7f6e68864b36c");
    650  test_memeq_hex(smartlist_get(invalid,2),
    651                 "20d1576c5ab11bbcff0dedb1db4a3cfc"
    652                 "c8bc8dd839d8cbfef92d00a1a7d7b294");
    653  test_memeq_hex(smartlist_get(invalid,3),
    654                 "074770f394c73dbde7b44412e9692add"
    655                 "691a478d4727f9804b77646c95420a96");
    656 
    657  /* Spot-check the valid ones. */
    658  const microdesc_t *md = smartlist_get(mds, 5);
    659  test_memeq_hex(md->digest,
    660                 "54bb6d733ddeb375d2456c79ae103961"
    661                 "da0cae29620375ac4cf13d54da4d92b3");
    662  tt_int_op(md->last_listed, OP_EQ, 0);
    663  tt_int_op(md->saved_location, OP_EQ, SAVED_NOWHERE);
    664  tt_int_op(md->no_save, OP_EQ, 0);
    665  tt_uint_op(md->held_in_map, OP_EQ, 0);
    666  tt_uint_op(md->held_by_nodes, OP_EQ, 0);
    667  tt_assert(md->onion_curve25519_pkey);
    668 
    669  md = smartlist_get(mds, 6);
    670  test_memeq_hex(md->digest,
    671                 "53f740bd222ab37f19f604b1d3759aa6"
    672                 "5eff1fbce9ac254bd0fa50d4af9b1bae");
    673  tt_assert(! md->exit_policy);
    674 
    675  md = smartlist_get(mds, 8);
    676  test_memeq_hex(md->digest,
    677                 "a0a155562d8093d8fd0feb7b93b7226e"
    678                 "17f056c2142aab7a4ea8c5867a0376d5");
    679  tt_assert(md->onion_curve25519_pkey);
    680 
    681  md = smartlist_get(mds, 10);
    682  test_memeq_hex(md->digest,
    683                 "409ebd87d23925a2732bd467a92813c9"
    684                 "21ca378fcb9ca193d354c51550b6d5e9");
    685  tt_assert(tor_addr_family(&md->ipv6_addr) == AF_INET6);
    686  tt_int_op(md->ipv6_orport, OP_EQ, 9090);
    687 
    688  md = smartlist_get(mds, 11);
    689  tt_assert(tor_addr_family(&md->ipv6_addr) == AF_INET6);
    690  tt_int_op(md->ipv6_orport, OP_EQ, 9090);
    691  tt_int_op(md->policy_is_reject_star, OP_EQ, 1);
    692 
    693  md = smartlist_get(mds, 12);
    694  tt_assert(tor_addr_family(&md->ipv6_addr) == AF_INET6);
    695  tt_int_op(md->ipv6_orport, OP_EQ, 9090);
    696  tt_int_op(md->policy_is_reject_star, OP_EQ, 0);
    697 
    698  md = smartlist_get(mds, 13);
    699  tt_assert(tor_addr_family(&md->ipv6_addr) == AF_INET6);
    700  tt_int_op(md->ipv6_orport, OP_EQ, 9090);
    701  tt_int_op(md->policy_is_reject_star, OP_EQ, 0);
    702 
    703 done:
    704  SMARTLIST_FOREACH(mds, microdesc_t *, mdsc, microdesc_free(mdsc));
    705  smartlist_free(mds);
    706  SMARTLIST_FOREACH(invalid, char *, cp, tor_free(cp));
    707  smartlist_free(invalid);
    708  tor_free(mem_op_hex_tmp);
    709 }
    710 
    711 static void
    712 test_md_parse_id_ed25519(void *arg)
    713 {
    714  (void)arg;
    715 
    716  /* A correct MD with an ed25519 ID ... and an unspecified ID type,
    717   * which is permitted. */
    718  const char GOOD_MD[] =
    719    "onion-key\n"
    720    "-----BEGIN RSA PUBLIC KEY-----\n"
    721    "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
    722    "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
    723    "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
    724    "-----END RSA PUBLIC KEY-----\n"
    725    "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n"
    726    "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyBrZXk\n"
    727    "id wumpus dodecahedron\n";
    728 
    729  smartlist_t *mds = NULL;
    730  const microdesc_t *md;
    731 
    732  mds = microdescs_parse_from_string(GOOD_MD,
    733                                     NULL, 1, SAVED_NOWHERE, NULL);
    734  tt_assert(mds);
    735  tt_int_op(smartlist_len(mds), OP_EQ, 1);
    736  md = smartlist_get(mds, 0);
    737  tt_mem_op(md->ed25519_identity_pkey, OP_EQ,
    738            "This isn't actually a public key", ED25519_PUBKEY_LEN);
    739  SMARTLIST_FOREACH(mds, microdesc_t *, m, microdesc_free(m));
    740  smartlist_free(mds);
    741 
    742  /* As above, but ed25519 ID key appears twice. */
    743  const char DUPLICATE_KEY[] =
    744    "onion-key\n"
    745    "-----BEGIN RSA PUBLIC KEY-----\n"
    746    "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
    747    "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
    748    "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
    749    "-----END RSA PUBLIC KEY-----\n"
    750    "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs\n"
    751    "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyBrZXk\n"
    752    "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyBrZXk\n";
    753 
    754  setup_capture_of_logs(LOG_WARN);
    755  mds = microdescs_parse_from_string(DUPLICATE_KEY,
    756                                     NULL, 1, SAVED_NOWHERE, NULL);
    757  tt_assert(mds);
    758  tt_int_op(smartlist_len(mds), OP_EQ, 0); // no entries.
    759  expect_single_log_msg_containing("Extra ed25519 key");
    760  mock_clean_saved_logs();
    761  smartlist_free(mds);
    762 
    763  /* As above, but ed25519 ID key is invalid. */
    764  const char BOGUS_KEY[] =
    765    "onion-key\n"
    766    "-----BEGIN RSA PUBLIC KEY-----\n"
    767    "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
    768    "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
    769    "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
    770    "-----END RSA PUBLIC KEY-----\n"
    771    "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs\n"
    772    "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyZZZZZZZZZZZ\n";
    773 
    774  mds = microdescs_parse_from_string(BOGUS_KEY,
    775                                     NULL, 1, SAVED_NOWHERE, NULL);
    776  tt_assert(mds);
    777  tt_int_op(smartlist_len(mds), OP_EQ, 0); // no entries.
    778  expect_single_log_msg_containing("Bogus ed25519 key");
    779 
    780 done:
    781  if (mds) {
    782    SMARTLIST_FOREACH(mds, microdesc_t *, m, microdesc_free(m));
    783    smartlist_free(mds);
    784  }
    785  teardown_capture_of_logs();
    786 }
    787 
    788 static void
    789 test_md_parse_no_onion_key(void *arg)
    790 {
    791  (void)arg;
    792 
    793  /* A correct MD with no onion key. */
    794  const char GOOD_MD[] =
    795    "onion-key\n"
    796    "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n"
    797    "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyBrZXk\n";
    798 
    799  smartlist_t *mds = NULL;
    800 
    801  mds = microdescs_parse_from_string(GOOD_MD,
    802                                     NULL, 1, SAVED_NOWHERE, NULL);
    803  tt_assert(mds);
    804  tt_int_op(smartlist_len(mds), OP_EQ, 1);
    805  const microdesc_t *md = smartlist_get(mds, 0);
    806  tt_mem_op(md->ed25519_identity_pkey, OP_EQ,
    807            "This isn't actually a public key", ED25519_PUBKEY_LEN);
    808 
    809 done:
    810  if (mds) {
    811    SMARTLIST_FOREACH(mds, microdesc_t *, m, microdesc_free(m));
    812    smartlist_free(mds);
    813  }
    814  teardown_capture_of_logs();
    815 }
    816 
    817 static void
    818 test_md_parse_family_ids(void *arg)
    819 {
    820  (void)arg;
    821 
    822  const char GOOD_MDS[] =
    823    "onion-key\n"
    824    "ntor-onion-key VHlycmFueSwgbGlrZSBoZWxsLCBpcyBub3QgZWFzaWw\n"
    825    "id ed25519 eSBjb25xdWVyZWQ7IHlldCB3ZSBoYXZlIHRoaXMgY28\n"
    826    "family-ids\n"
    827    "onion-key\n"
    828    "ntor-onion-key bnNvbGF0aW9uIHdpdGggdXMsIHRoYXQgdGhlIGhhcmQ\n"
    829    "id ed25519 ZXIgdGhlIGNvbmZsaWN0LCB0aGUgbW9yZSBnbG9yaW8\n"
    830    "family-ids ed25519:dXMgdGhlIHRyaXVtcGguICAgIC1UaG9tYXMgUGFpbmU "
    831       "other:Example\n";
    832  smartlist_t *mds = NULL;
    833  mds = microdescs_parse_from_string(GOOD_MDS, NULL, 1, SAVED_NOWHERE, NULL);
    834  tt_assert(mds);
    835  tt_int_op(smartlist_len(mds), OP_EQ, 2);
    836 
    837  const microdesc_t *md1 = smartlist_get(mds, 0);
    838  tt_ptr_op(md1->family_ids, OP_EQ, NULL);
    839 
    840  const microdesc_t *md2 = smartlist_get(mds, 1);
    841  tt_ptr_op(md2->family_ids, OP_NE, NULL);
    842  tt_int_op(smartlist_len(md2->family_ids), OP_EQ, 2);
    843  tt_str_op(smartlist_get(md2->family_ids, 0), OP_EQ,
    844            "ed25519:dXMgdGhlIHRyaXVtcGguICAgIC1UaG9tYXMgUGFpbmU");
    845  tt_str_op(smartlist_get(md2->family_ids, 1), OP_EQ,
    846            "other:Example");
    847 
    848 done:
    849  if (mds) {
    850    SMARTLIST_FOREACH(mds, microdesc_t *, m, microdesc_free(m));
    851    smartlist_free(mds);
    852  }
    853 }
    854 
    855 static int mock_rgsbd_called = 0;
    856 static routerstatus_t *mock_rgsbd_val_a = NULL;
    857 static routerstatus_t *mock_rgsbd_val_b = NULL;
    858 static routerstatus_t *
    859 mock_router_get_status_by_digest(networkstatus_t *c, const char *d)
    860 {
    861  (void) c;
    862  ++mock_rgsbd_called;
    863 
    864  if (fast_memeq(d, "\x5d\x76", 2)) {
    865    memcpy(mock_rgsbd_val_a->descriptor_digest, d, 32);
    866    return mock_rgsbd_val_a;
    867  } else if (fast_memeq(d, "\x20\xd1", 2)) {
    868    memcpy(mock_rgsbd_val_b->descriptor_digest, d, 32);
    869    return mock_rgsbd_val_b;
    870  } else {
    871    return NULL;
    872  }
    873 }
    874 
    875 static networkstatus_t *mock_ns_val = NULL;
    876 static networkstatus_t *
    877 mock_ns_get_by_flavor(consensus_flavor_t f)
    878 {
    879  (void)f;
    880  return mock_ns_val;
    881 }
    882 
    883 static void
    884 test_md_reject_cache(void *arg)
    885 {
    886  (void) arg;
    887  microdesc_cache_t *mc = NULL ;
    888  smartlist_t *added = NULL, *wanted = smartlist_new();
    889  or_options_t *options = get_options_mutable();
    890  char buf[DIGEST256_LEN];
    891 
    892  tor_free(options->CacheDirectory);
    893  options->CacheDirectory = tor_strdup(get_fname("md_datadir_test_rej"));
    894  mock_rgsbd_val_a = tor_malloc_zero(sizeof(routerstatus_t));
    895  mock_rgsbd_val_b = tor_malloc_zero(sizeof(routerstatus_t));
    896  mock_ns_val = tor_malloc_zero(sizeof(networkstatus_t));
    897 
    898  mock_ns_val->valid_after = time(NULL) - 86400;
    899  mock_ns_val->valid_until = time(NULL) + 86400;
    900  mock_ns_val->flavor = FLAV_MICRODESC;
    901 
    902 #ifdef _WIN32
    903  tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory));
    904 #else
    905  tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory, 0700));
    906 #endif
    907 
    908  MOCK(router_get_mutable_consensus_status_by_descriptor_digest,
    909       mock_router_get_status_by_digest);
    910  MOCK(networkstatus_get_latest_consensus_by_flavor, mock_ns_get_by_flavor);
    911 
    912  mc = get_microdesc_cache();
    913 #define ADD(hex)                                                        \
    914  do {                                                                  \
    915    tt_int_op(sizeof(buf),OP_EQ,base16_decode(buf,sizeof(buf),          \
    916                hex,strlen(hex)));\
    917    smartlist_add(wanted, tor_memdup(buf, DIGEST256_LEN));              \
    918  } while (0)
    919 
    920  /* invalid,0 */
    921  ADD("5d76bf1c6614e885614a1e0ad074e1ab4ea14655ebeefb1736a71b5ed8a15a51");
    922  /* invalid,2 */
    923  ADD("20d1576c5ab11bbcff0dedb1db4a3cfcc8bc8dd839d8cbfef92d00a1a7d7b294");
    924  /* valid, 6 */
    925  ADD("53f740bd222ab37f19f604b1d3759aa65eff1fbce9ac254bd0fa50d4af9b1bae");
    926  /* valid, 8 */
    927  ADD("a0a155562d8093d8fd0feb7b93b7226e17f056c2142aab7a4ea8c5867a0376d5");
    928 
    929  added = microdescs_add_to_cache(mc, MD_PARSE_TEST_DATA, NULL,
    930                                  SAVED_NOWHERE, 0, time(NULL), wanted);
    931 
    932  tt_int_op(smartlist_len(added), OP_EQ, 2);
    933  tt_int_op(mock_rgsbd_called, OP_EQ, 2);
    934  tt_int_op(mock_rgsbd_val_a->dl_status.n_download_failures, OP_EQ, 255);
    935  tt_int_op(mock_rgsbd_val_b->dl_status.n_download_failures, OP_EQ, 255);
    936 
    937 done:
    938  UNMOCK(networkstatus_get_latest_consensus_by_flavor);
    939  UNMOCK(router_get_mutable_consensus_status_by_descriptor_digest);
    940  tor_free(options->CacheDirectory);
    941  microdesc_free_all();
    942  smartlist_free(added);
    943  SMARTLIST_FOREACH(wanted, char *, cp, tor_free(cp));
    944  smartlist_free(wanted);
    945  tor_free(mock_rgsbd_val_a);
    946  tor_free(mock_rgsbd_val_b);
    947  tor_free(mock_ns_val);
    948 }
    949 
    950 static void
    951 test_md_corrupt_desc(void *arg)
    952 {
    953  char *cp = NULL;
    954  smartlist_t *sl = NULL;
    955  (void) arg;
    956 
    957  sl = microdescs_add_to_cache(get_microdesc_cache(),
    958                               "@last-listed 2015-06-22 10:00:00\n"
    959                               "onion-k\n",
    960                               NULL, SAVED_IN_JOURNAL, 0, time(NULL), NULL);
    961  tt_int_op(smartlist_len(sl), OP_EQ, 0);
    962  smartlist_free(sl);
    963 
    964  sl = microdescs_add_to_cache(get_microdesc_cache(),
    965                               "@last-listed 2015-06-22 10:00:00\n"
    966                               "wiggly\n",
    967                               NULL, SAVED_IN_JOURNAL, 0, time(NULL), NULL);
    968  tt_int_op(smartlist_len(sl), OP_EQ, 0);
    969  smartlist_free(sl);
    970 
    971  tor_asprintf(&cp, "%s\n%s", test_md1, "@foobar\nonion-wobble\n");
    972 
    973  sl = microdescs_add_to_cache(get_microdesc_cache(),
    974                               cp, cp+strlen(cp),
    975                               SAVED_IN_JOURNAL, 0, time(NULL), NULL);
    976  tt_int_op(smartlist_len(sl), OP_EQ, 0);
    977 
    978 done:
    979  tor_free(cp);
    980  smartlist_free(sl);
    981 }
    982 
    983 struct testcase_t microdesc_tests[] = {
    984  { "cache", test_md_cache, TT_FORK, NULL, NULL },
    985  { "broken_cache", test_md_cache_broken, TT_FORK, NULL, NULL },
    986  { "generate", test_md_generate, 0, NULL, NULL },
    987  { "parse", test_md_parse, 0, NULL, NULL },
    988  { "parse_id_ed25519", test_md_parse_id_ed25519, 0, NULL, NULL },
    989  { "parse_no_onion_key", test_md_parse_no_onion_key, 0, NULL, NULL },
    990  { "parse_family_ids", test_md_parse_family_ids, 0, NULL, NULL },
    991  { "reject_cache", test_md_reject_cache, TT_FORK, NULL, NULL },
    992  { "corrupt_desc", test_md_corrupt_desc, TT_FORK, NULL, NULL },
    993  END_OF_TESTCASES
    994 };