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 };