Loading changes/ticket31675 0 → 100644 +3 −0 Original line number Diff line number Diff line o Code simplification and refactoring: - Refactor the microdescs_parse_from_string() function into smaller pieces, for better comprehensibility. Closes ticket 31675. scripts/maint/practracker/exceptions.txt +0 −1 Original line number Diff line number Diff line Loading @@ -227,7 +227,6 @@ problem function-size /src/feature/dirclient/dirclient.c:handle_response_fetch_c problem function-size /src/feature/dircommon/consdiff.c:gen_ed_diff() 203 problem function-size /src/feature/dircommon/consdiff.c:apply_ed_diff() 158 problem function-size /src/feature/dirparse/authcert_parse.c:authority_cert_parse_from_string() 181 problem function-size /src/feature/dirparse/microdesc_parse.c:microdescs_parse_from_string() 166 problem function-size /src/feature/dirparse/ns_parse.c:routerstatus_parse_entry_from_string() 280 problem function-size /src/feature/dirparse/ns_parse.c:networkstatus_verify_bw_weights() 389 problem function-size /src/feature/dirparse/ns_parse.c:networkstatus_parse_vote_from_string() 635 Loading src/feature/dirparse/microdesc_parse.c +192 −128 Original line number Diff line number Diff line Loading @@ -98,54 +98,53 @@ policy_is_reject_star_or_null(struct short_policy_t *policy) return !policy || short_policy_is_reject_star(policy); } /** Parse as many microdescriptors as are found from the string starting at * <b>s</b> and ending at <b>eos</b>. If allow_annotations is set, read any * annotations we recognize and ignore ones we don't. * * If <b>saved_location</b> isn't SAVED_IN_CACHE, make a local copy of each * descriptor in the body field of each microdesc_t. * * Return all newly parsed microdescriptors in a newly allocated * smartlist_t. If <b>invalid_disgests_out</b> is provided, add a SHA256 * microdesc digest to it for every microdesc that we found to be badly * formed. (This may cause duplicates) */ smartlist_t * microdescs_parse_from_string(const char *s, const char *eos, int allow_annotations, saved_location_t where, smartlist_t *invalid_digests_out) /** * Return a human-readable description of a given saved_location_t. * Never returns NULL. **/ static const char * saved_location_to_string(saved_location_t where) { smartlist_t *tokens; smartlist_t *result; microdesc_t *md = NULL; memarea_t *area; const char *start = s; const char *start_of_next_microdesc; int flags = allow_annotations ? TS_ANNOTATIONS_OK : 0; const int copy_body = (where != SAVED_IN_CACHE); directory_token_t *tok; if (!eos) eos = s + strlen(s); s = eat_whitespace_eos(s, eos); area = memarea_new(); result = smartlist_new(); tokens = smartlist_new(); const char *location; switch (where) { case SAVED_NOWHERE: location = "download or generated string"; break; case SAVED_IN_CACHE: location = "cache"; break; case SAVED_IN_JOURNAL: location = "journal"; break; default: location = "unknown location"; break; } return location; } while (s < eos) { int okay = 0; /** * Given a microdescriptor stored in <b>where</b> which starts at <b>s</b>, * which ends at <b>start_of_next_microdescriptor</b>, and which is located * within a larger document beginning at <b>start</b>: Fill in the body, * bodylen, bodylen, saved_location, off, and digest fields of <b>md</b> as * appropriate. * * The body field will be an alias within <b>s</b> if <b>saved_location</b> * is SAVED_IN_CACHE, and will be copied into body and nul-terminated * otherwise. **/ static int microdesc_extract_body(microdesc_t *md, const char *start, const char *s, const char *start_of_next_microdesc, saved_location_t where) { const bool copy_body = (where != SAVED_IN_CACHE); start_of_next_microdesc = find_start_of_next_microdesc(s, eos); if (!start_of_next_microdesc) start_of_next_microdesc = eos; const char *cp = tor_memstr(s, start_of_next_microdesc-s, "onion-key"); md = tor_malloc_zero(sizeof(microdesc_t)); { const char *cp = tor_memstr(s, start_of_next_microdesc-s, "onion-key"); const int no_onion_key = (cp == NULL); const bool no_onion_key = (cp == NULL); if (no_onion_key) { cp = s; /* So that we have *some* junk to put in the body */ } Loading @@ -157,38 +156,44 @@ microdescs_parse_from_string(const char *s, const char *eos, else md->body = (char*)cp; md->off = cp - start; crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256); if (no_onion_key) { log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Malformed or truncated descriptor"); goto next; } return no_onion_key ? -1 : 0; } /** * Parse a microdescriptor which begins at <b>s</b> and ends at * <b>start_of_next_microdesc. Store its fields into <b>md</b>. Use * <b>where</b> for generating log information. If <b>allow_annotations</b> * is true, then one or more annotations may precede the microdescriptor body * proper. Use <b>area</b> for memory management, clearing it when done. * * On success, return 0; otherwise return -1. **/ static int microdesc_parse_fields(microdesc_t *md, memarea_t *area, const char *s, const char *start_of_next_microdesc, int allow_annotations, saved_location_t where) { smartlist_t *tokens = smartlist_new(); int rv = -1; int flags = allow_annotations ? TS_ANNOTATIONS_OK : 0; directory_token_t *tok; if (tokenize_string(area, s, start_of_next_microdesc, tokens, microdesc_token_table, flags)) { const char *location; switch (where) { case SAVED_NOWHERE: location = "download or generated string"; break; case SAVED_IN_CACHE: location = "cache"; break; case SAVED_IN_JOURNAL: location = "journal"; break; default: location = "unknown location"; break; } log_warn(LD_DIR, "Unparseable microdescriptor found in %s", location); goto next; log_warn(LD_DIR, "Unparseable microdescriptor found in %s", saved_location_to_string(where)); goto err; } if ((tok = find_opt_by_keyword(tokens, A_LAST_LISTED))) { if (parse_iso_time(tok->args[0], &md->last_listed)) { log_warn(LD_DIR, "Bad last-listed time in microdescriptor"); goto next; goto err; } } Loading @@ -196,7 +201,7 @@ microdescs_parse_from_string(const char *s, const char *eos, if (!crypto_pk_public_exponent_ok(tok->key)) { log_warn(LD_DIR, "Relay's onion key had invalid exponent."); goto next; goto err; } md->onion_pkey = tor_memdup(tok->object_body, tok->object_size); md->onion_pkey_len = tok->object_size; Loading @@ -207,7 +212,7 @@ microdescs_parse_from_string(const char *s, const char *eos, tor_assert(tok->n_args >= 1); if (curve25519_public_from_base64(&k, tok->args[0]) < 0) { log_warn(LD_DIR, "Bogus ntor-onion-key in microdesc"); goto next; goto err; } md->onion_curve25519_pkey = tor_memdup(&k, sizeof(curve25519_public_key_t)); Loading @@ -221,13 +226,13 @@ microdescs_parse_from_string(const char *s, const char *eos, if (md->ed25519_identity_pkey) { log_warn(LD_DIR, "Extra ed25519 key in microdesc"); smartlist_free(id_lines); goto next; goto err; } ed25519_public_key_t k; if (ed25519_public_from_base64(&k, t->args[1])<0) { log_warn(LD_DIR, "Bogus ed25519 key in microdesc"); smartlist_free(id_lines); goto next; goto err; } md->ed25519_identity_pkey = tor_memdup(&k, sizeof(k)); } Loading Loading @@ -261,27 +266,86 @@ microdescs_parse_from_string(const char *s, const char *eos, md->policy_is_reject_star = 1; } rv = 0; err: SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); memarea_clear(area); smartlist_free(tokens); return rv; } /** Parse as many microdescriptors as are found from the string starting at * <b>s</b> and ending at <b>eos</b>. If allow_annotations is set, read any * annotations we recognize and ignore ones we don't. * * If <b>saved_location</b> isn't SAVED_IN_CACHE, make a local copy of each * descriptor in the body field of each microdesc_t. * * Return all newly parsed microdescriptors in a newly allocated * smartlist_t. If <b>invalid_disgests_out</b> is provided, add a SHA256 * microdesc digest to it for every microdesc that we found to be badly * formed. (This may cause duplicates) */ smartlist_t * microdescs_parse_from_string(const char *s, const char *eos, int allow_annotations, saved_location_t where, smartlist_t *invalid_digests_out) { smartlist_t *result; microdesc_t *md = NULL; memarea_t *area; const char *start = s; const char *start_of_next_microdesc; if (!eos) eos = s + strlen(s); s = eat_whitespace_eos(s, eos); area = memarea_new(); result = smartlist_new(); while (s < eos) { bool okay = false; start_of_next_microdesc = find_start_of_next_microdesc(s, eos); if (!start_of_next_microdesc) start_of_next_microdesc = eos; md = tor_malloc_zero(sizeof(microdesc_t)); uint8_t md_digest[DIGEST256_LEN]; { const bool body_not_found = microdesc_extract_body(md, start, s, start_of_next_microdesc, where) < 0; memcpy(md_digest, md->digest, DIGEST256_LEN); if (body_not_found) { log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Malformed or truncated descriptor"); goto next; } } if (microdesc_parse_fields(md, area, s, start_of_next_microdesc, allow_annotations, where) == 0) { smartlist_add(result, md); okay = 1; md = NULL; // prevent free okay = true; } md = NULL; next: if (! okay && invalid_digests_out) { smartlist_add(invalid_digests_out, tor_memdup(md->digest, DIGEST256_LEN)); tor_memdup(md_digest, DIGEST256_LEN)); } microdesc_free(md); md = NULL; SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); memarea_clear(area); smartlist_clear(tokens); s = start_of_next_microdesc; } SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); memarea_drop_all(area); smartlist_free(tokens); return result; } src/test/test_microdesc.c +76 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include "feature/nodelist/routerstatus_st.h" #include "test/test.h" #include "test/log_test_helpers.h" #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> Loading Loading @@ -770,6 +771,80 @@ test_md_parse(void *arg) tor_free(mem_op_hex_tmp); } static void test_md_parse_id_ed25519(void *arg) { (void)arg; /* A correct MD with an ed25519 ID ... and an unspecified ID type, * which is permitted. */ const char GOOD_MD[] = "onion-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n" "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n" "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyBrZXk\n" "id wumpus dodecahedron\n"; smartlist_t *mds = NULL; const microdesc_t *md; mds = microdescs_parse_from_string(GOOD_MD, NULL, 1, SAVED_NOWHERE, NULL); tt_assert(mds); tt_int_op(smartlist_len(mds), OP_EQ, 1); md = smartlist_get(mds, 0); tt_mem_op(md->ed25519_identity_pkey, OP_EQ, "This isn't actually a public key", ED25519_PUBKEY_LEN); SMARTLIST_FOREACH(mds, microdesc_t *, m, microdesc_free(m)); smartlist_free(mds); /* As above, but ed25519 ID key appears twice. */ const char DUPLICATE_KEY[] = "onion-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n" "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n" "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyBrZXk\n" "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyBrZXk\n"; setup_capture_of_logs(LOG_WARN); mds = microdescs_parse_from_string(DUPLICATE_KEY, NULL, 1, SAVED_NOWHERE, NULL); tt_assert(mds); tt_int_op(smartlist_len(mds), OP_EQ, 0); // no entries. expect_single_log_msg_containing("Extra ed25519 key"); mock_clean_saved_logs(); smartlist_free(mds); /* As above, but ed25519 ID key is invalid. */ const char BOGUS_KEY[] = "onion-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n" "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n" "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyZZZZZZZZZZZ\n"; mds = microdescs_parse_from_string(BOGUS_KEY, NULL, 1, SAVED_NOWHERE, NULL); tt_assert(mds); tt_int_op(smartlist_len(mds), OP_EQ, 0); // no entries. expect_single_log_msg_containing("Bogus ed25519 key"); done: if (mds) { SMARTLIST_FOREACH(mds, microdesc_t *, m, microdesc_free(m)); smartlist_free(mds); } teardown_capture_of_logs(); } static int mock_rgsbd_called = 0; static routerstatus_t *mock_rgsbd_val_a = NULL; static routerstatus_t *mock_rgsbd_val_b = NULL; Loading Loading @@ -903,6 +978,7 @@ struct testcase_t microdesc_tests[] = { { "broken_cache", test_md_cache_broken, TT_FORK, NULL, NULL }, { "generate", test_md_generate, 0, NULL, NULL }, { "parse", test_md_parse, 0, NULL, NULL }, { "parse_id_ed25519", test_md_parse_id_ed25519, 0, NULL, NULL }, { "reject_cache", test_md_reject_cache, TT_FORK, NULL, NULL }, { "corrupt_desc", test_md_corrupt_desc, TT_FORK, NULL, NULL }, END_OF_TESTCASES Loading Loading
changes/ticket31675 0 → 100644 +3 −0 Original line number Diff line number Diff line o Code simplification and refactoring: - Refactor the microdescs_parse_from_string() function into smaller pieces, for better comprehensibility. Closes ticket 31675.
scripts/maint/practracker/exceptions.txt +0 −1 Original line number Diff line number Diff line Loading @@ -227,7 +227,6 @@ problem function-size /src/feature/dirclient/dirclient.c:handle_response_fetch_c problem function-size /src/feature/dircommon/consdiff.c:gen_ed_diff() 203 problem function-size /src/feature/dircommon/consdiff.c:apply_ed_diff() 158 problem function-size /src/feature/dirparse/authcert_parse.c:authority_cert_parse_from_string() 181 problem function-size /src/feature/dirparse/microdesc_parse.c:microdescs_parse_from_string() 166 problem function-size /src/feature/dirparse/ns_parse.c:routerstatus_parse_entry_from_string() 280 problem function-size /src/feature/dirparse/ns_parse.c:networkstatus_verify_bw_weights() 389 problem function-size /src/feature/dirparse/ns_parse.c:networkstatus_parse_vote_from_string() 635 Loading
src/feature/dirparse/microdesc_parse.c +192 −128 Original line number Diff line number Diff line Loading @@ -98,54 +98,53 @@ policy_is_reject_star_or_null(struct short_policy_t *policy) return !policy || short_policy_is_reject_star(policy); } /** Parse as many microdescriptors as are found from the string starting at * <b>s</b> and ending at <b>eos</b>. If allow_annotations is set, read any * annotations we recognize and ignore ones we don't. * * If <b>saved_location</b> isn't SAVED_IN_CACHE, make a local copy of each * descriptor in the body field of each microdesc_t. * * Return all newly parsed microdescriptors in a newly allocated * smartlist_t. If <b>invalid_disgests_out</b> is provided, add a SHA256 * microdesc digest to it for every microdesc that we found to be badly * formed. (This may cause duplicates) */ smartlist_t * microdescs_parse_from_string(const char *s, const char *eos, int allow_annotations, saved_location_t where, smartlist_t *invalid_digests_out) /** * Return a human-readable description of a given saved_location_t. * Never returns NULL. **/ static const char * saved_location_to_string(saved_location_t where) { smartlist_t *tokens; smartlist_t *result; microdesc_t *md = NULL; memarea_t *area; const char *start = s; const char *start_of_next_microdesc; int flags = allow_annotations ? TS_ANNOTATIONS_OK : 0; const int copy_body = (where != SAVED_IN_CACHE); directory_token_t *tok; if (!eos) eos = s + strlen(s); s = eat_whitespace_eos(s, eos); area = memarea_new(); result = smartlist_new(); tokens = smartlist_new(); const char *location; switch (where) { case SAVED_NOWHERE: location = "download or generated string"; break; case SAVED_IN_CACHE: location = "cache"; break; case SAVED_IN_JOURNAL: location = "journal"; break; default: location = "unknown location"; break; } return location; } while (s < eos) { int okay = 0; /** * Given a microdescriptor stored in <b>where</b> which starts at <b>s</b>, * which ends at <b>start_of_next_microdescriptor</b>, and which is located * within a larger document beginning at <b>start</b>: Fill in the body, * bodylen, bodylen, saved_location, off, and digest fields of <b>md</b> as * appropriate. * * The body field will be an alias within <b>s</b> if <b>saved_location</b> * is SAVED_IN_CACHE, and will be copied into body and nul-terminated * otherwise. **/ static int microdesc_extract_body(microdesc_t *md, const char *start, const char *s, const char *start_of_next_microdesc, saved_location_t where) { const bool copy_body = (where != SAVED_IN_CACHE); start_of_next_microdesc = find_start_of_next_microdesc(s, eos); if (!start_of_next_microdesc) start_of_next_microdesc = eos; const char *cp = tor_memstr(s, start_of_next_microdesc-s, "onion-key"); md = tor_malloc_zero(sizeof(microdesc_t)); { const char *cp = tor_memstr(s, start_of_next_microdesc-s, "onion-key"); const int no_onion_key = (cp == NULL); const bool no_onion_key = (cp == NULL); if (no_onion_key) { cp = s; /* So that we have *some* junk to put in the body */ } Loading @@ -157,38 +156,44 @@ microdescs_parse_from_string(const char *s, const char *eos, else md->body = (char*)cp; md->off = cp - start; crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256); if (no_onion_key) { log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Malformed or truncated descriptor"); goto next; } return no_onion_key ? -1 : 0; } /** * Parse a microdescriptor which begins at <b>s</b> and ends at * <b>start_of_next_microdesc. Store its fields into <b>md</b>. Use * <b>where</b> for generating log information. If <b>allow_annotations</b> * is true, then one or more annotations may precede the microdescriptor body * proper. Use <b>area</b> for memory management, clearing it when done. * * On success, return 0; otherwise return -1. **/ static int microdesc_parse_fields(microdesc_t *md, memarea_t *area, const char *s, const char *start_of_next_microdesc, int allow_annotations, saved_location_t where) { smartlist_t *tokens = smartlist_new(); int rv = -1; int flags = allow_annotations ? TS_ANNOTATIONS_OK : 0; directory_token_t *tok; if (tokenize_string(area, s, start_of_next_microdesc, tokens, microdesc_token_table, flags)) { const char *location; switch (where) { case SAVED_NOWHERE: location = "download or generated string"; break; case SAVED_IN_CACHE: location = "cache"; break; case SAVED_IN_JOURNAL: location = "journal"; break; default: location = "unknown location"; break; } log_warn(LD_DIR, "Unparseable microdescriptor found in %s", location); goto next; log_warn(LD_DIR, "Unparseable microdescriptor found in %s", saved_location_to_string(where)); goto err; } if ((tok = find_opt_by_keyword(tokens, A_LAST_LISTED))) { if (parse_iso_time(tok->args[0], &md->last_listed)) { log_warn(LD_DIR, "Bad last-listed time in microdescriptor"); goto next; goto err; } } Loading @@ -196,7 +201,7 @@ microdescs_parse_from_string(const char *s, const char *eos, if (!crypto_pk_public_exponent_ok(tok->key)) { log_warn(LD_DIR, "Relay's onion key had invalid exponent."); goto next; goto err; } md->onion_pkey = tor_memdup(tok->object_body, tok->object_size); md->onion_pkey_len = tok->object_size; Loading @@ -207,7 +212,7 @@ microdescs_parse_from_string(const char *s, const char *eos, tor_assert(tok->n_args >= 1); if (curve25519_public_from_base64(&k, tok->args[0]) < 0) { log_warn(LD_DIR, "Bogus ntor-onion-key in microdesc"); goto next; goto err; } md->onion_curve25519_pkey = tor_memdup(&k, sizeof(curve25519_public_key_t)); Loading @@ -221,13 +226,13 @@ microdescs_parse_from_string(const char *s, const char *eos, if (md->ed25519_identity_pkey) { log_warn(LD_DIR, "Extra ed25519 key in microdesc"); smartlist_free(id_lines); goto next; goto err; } ed25519_public_key_t k; if (ed25519_public_from_base64(&k, t->args[1])<0) { log_warn(LD_DIR, "Bogus ed25519 key in microdesc"); smartlist_free(id_lines); goto next; goto err; } md->ed25519_identity_pkey = tor_memdup(&k, sizeof(k)); } Loading Loading @@ -261,27 +266,86 @@ microdescs_parse_from_string(const char *s, const char *eos, md->policy_is_reject_star = 1; } rv = 0; err: SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); memarea_clear(area); smartlist_free(tokens); return rv; } /** Parse as many microdescriptors as are found from the string starting at * <b>s</b> and ending at <b>eos</b>. If allow_annotations is set, read any * annotations we recognize and ignore ones we don't. * * If <b>saved_location</b> isn't SAVED_IN_CACHE, make a local copy of each * descriptor in the body field of each microdesc_t. * * Return all newly parsed microdescriptors in a newly allocated * smartlist_t. If <b>invalid_disgests_out</b> is provided, add a SHA256 * microdesc digest to it for every microdesc that we found to be badly * formed. (This may cause duplicates) */ smartlist_t * microdescs_parse_from_string(const char *s, const char *eos, int allow_annotations, saved_location_t where, smartlist_t *invalid_digests_out) { smartlist_t *result; microdesc_t *md = NULL; memarea_t *area; const char *start = s; const char *start_of_next_microdesc; if (!eos) eos = s + strlen(s); s = eat_whitespace_eos(s, eos); area = memarea_new(); result = smartlist_new(); while (s < eos) { bool okay = false; start_of_next_microdesc = find_start_of_next_microdesc(s, eos); if (!start_of_next_microdesc) start_of_next_microdesc = eos; md = tor_malloc_zero(sizeof(microdesc_t)); uint8_t md_digest[DIGEST256_LEN]; { const bool body_not_found = microdesc_extract_body(md, start, s, start_of_next_microdesc, where) < 0; memcpy(md_digest, md->digest, DIGEST256_LEN); if (body_not_found) { log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Malformed or truncated descriptor"); goto next; } } if (microdesc_parse_fields(md, area, s, start_of_next_microdesc, allow_annotations, where) == 0) { smartlist_add(result, md); okay = 1; md = NULL; // prevent free okay = true; } md = NULL; next: if (! okay && invalid_digests_out) { smartlist_add(invalid_digests_out, tor_memdup(md->digest, DIGEST256_LEN)); tor_memdup(md_digest, DIGEST256_LEN)); } microdesc_free(md); md = NULL; SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); memarea_clear(area); smartlist_clear(tokens); s = start_of_next_microdesc; } SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); memarea_drop_all(area); smartlist_free(tokens); return result; }
src/test/test_microdesc.c +76 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include "feature/nodelist/routerstatus_st.h" #include "test/test.h" #include "test/log_test_helpers.h" #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> Loading Loading @@ -770,6 +771,80 @@ test_md_parse(void *arg) tor_free(mem_op_hex_tmp); } static void test_md_parse_id_ed25519(void *arg) { (void)arg; /* A correct MD with an ed25519 ID ... and an unspecified ID type, * which is permitted. */ const char GOOD_MD[] = "onion-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n" "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n" "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyBrZXk\n" "id wumpus dodecahedron\n"; smartlist_t *mds = NULL; const microdesc_t *md; mds = microdescs_parse_from_string(GOOD_MD, NULL, 1, SAVED_NOWHERE, NULL); tt_assert(mds); tt_int_op(smartlist_len(mds), OP_EQ, 1); md = smartlist_get(mds, 0); tt_mem_op(md->ed25519_identity_pkey, OP_EQ, "This isn't actually a public key", ED25519_PUBKEY_LEN); SMARTLIST_FOREACH(mds, microdesc_t *, m, microdesc_free(m)); smartlist_free(mds); /* As above, but ed25519 ID key appears twice. */ const char DUPLICATE_KEY[] = "onion-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n" "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n" "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyBrZXk\n" "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyBrZXk\n"; setup_capture_of_logs(LOG_WARN); mds = microdescs_parse_from_string(DUPLICATE_KEY, NULL, 1, SAVED_NOWHERE, NULL); tt_assert(mds); tt_int_op(smartlist_len(mds), OP_EQ, 0); // no entries. expect_single_log_msg_containing("Extra ed25519 key"); mock_clean_saved_logs(); smartlist_free(mds); /* As above, but ed25519 ID key is invalid. */ const char BOGUS_KEY[] = "onion-key\n" "-----BEGIN RSA PUBLIC KEY-----\n" "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n" "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n" "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n" "-----END RSA PUBLIC KEY-----\n" "id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyZZZZZZZZZZZ\n"; mds = microdescs_parse_from_string(BOGUS_KEY, NULL, 1, SAVED_NOWHERE, NULL); tt_assert(mds); tt_int_op(smartlist_len(mds), OP_EQ, 0); // no entries. expect_single_log_msg_containing("Bogus ed25519 key"); done: if (mds) { SMARTLIST_FOREACH(mds, microdesc_t *, m, microdesc_free(m)); smartlist_free(mds); } teardown_capture_of_logs(); } static int mock_rgsbd_called = 0; static routerstatus_t *mock_rgsbd_val_a = NULL; static routerstatus_t *mock_rgsbd_val_b = NULL; Loading Loading @@ -903,6 +978,7 @@ struct testcase_t microdesc_tests[] = { { "broken_cache", test_md_cache_broken, TT_FORK, NULL, NULL }, { "generate", test_md_generate, 0, NULL, NULL }, { "parse", test_md_parse, 0, NULL, NULL }, { "parse_id_ed25519", test_md_parse_id_ed25519, 0, NULL, NULL }, { "reject_cache", test_md_reject_cache, TT_FORK, NULL, NULL }, { "corrupt_desc", test_md_corrupt_desc, TT_FORK, NULL, NULL }, END_OF_TESTCASES Loading