diff options
author | Nick Mathewson <nickm@torproject.org> | 2013-04-18 11:13:36 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2013-04-18 11:13:36 -0400 |
commit | 8362f8854aa3e36b766724226a3baec4d325c1c0 (patch) | |
tree | d309eb1c3b9502b4323405f1a312f04dd868077c /src/or | |
parent | cd1cdae0fac33bca359b34dae4062fe87a351661 (diff) | |
parent | 4b15606fa2848f5112599865eb7b15ef2178e66a (diff) | |
download | tor-8362f8854aa3e36b766724226a3baec4d325c1c0.tar tor-8362f8854aa3e36b766724226a3baec4d325c1c0.tar.gz |
Merge branch 'less_charbuf_rebased' into maint-0.2.4
Conflicts:
src/or/dirserv.c
src/or/dirserv.h
src/test/test_dir.c
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/dirserv.c | 153 | ||||
-rw-r--r-- | src/or/dirserv.h | 25 | ||||
-rw-r--r-- | src/or/dirvote.c | 200 | ||||
-rw-r--r-- | src/or/networkstatus.c | 4 | ||||
-rw-r--r-- | src/or/or.h | 3 | ||||
-rw-r--r-- | src/or/router.c | 148 | ||||
-rw-r--r-- | src/or/router.h | 4 | ||||
-rw-r--r-- | src/or/routerparse.c | 72 | ||||
-rw-r--r-- | src/or/routerparse.h | 5 |
9 files changed, 243 insertions, 371 deletions
diff --git a/src/or/dirserv.c b/src/or/dirserv.c index e4533b773..375572050 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -2311,11 +2311,10 @@ version_from_platform(const char *platform) return NULL; } -/** Helper: write the router-status information in <b>rs</b> into <b>buf</b>, - * which has at least <b>buf_len</b> free characters. Do NUL-termination. - * Use the same format as in network-status documents. If <b>version</b> is - * non-NULL, add a "v" line for the platform. Return 0 on success, -1 on - * failure. +/** Helper: write the router-status information in <b>rs</b> into a newly + * allocated character buffer. Use the same format as in network-status + * documents. If <b>version</b> is non-NULL, add a "v" line for the platform. + * Return 0 on success, -1 on failure. * * The format argument has one of the following values: * NS_V2 - Output an entry suitable for a V2 NS opinion document @@ -2326,25 +2325,25 @@ version_from_platform(const char *platform) * it contains additional information for the vote. * NS_CONTROL_PORT - Output a NS document for the control port */ -int -routerstatus_format_entry(char *buf, size_t buf_len, - const routerstatus_t *rs, const char *version, +char * +routerstatus_format_entry(const routerstatus_t *rs, const char *version, routerstatus_format_type_t format, const vote_routerstatus_t *vrs) { - int r; - char *cp; char *summary; + char *result = NULL; char published[ISO_TIME_LEN+1]; char identity64[BASE64_DIGEST_LEN+1]; char digest64[BASE64_DIGEST_LEN+1]; + smartlist_t *chunks = NULL; format_iso_time(published, rs->published_on); digest_to_base64(identity64, rs->identity_digest); digest_to_base64(digest64, rs->descriptor_digest); - r = tor_snprintf(buf, buf_len, + chunks = smartlist_new(); + smartlist_add_asprintf(chunks, "r %s %s %s%s%s %s %d %d\n", rs->nickname, identity64, @@ -2354,11 +2353,6 @@ routerstatus_format_entry(char *buf, size_t buf_len, fmt_addr32(rs->addr), (int)rs->or_port, (int)rs->dir_port); - if (r<0) { - log_warn(LD_BUG, "Not enough space in buffer."); - return -1; - } - cp = buf + strlen(buf); /* TODO: Maybe we want to pass in what we need to build the rest of * this here, instead of in the caller. Then we could use the @@ -2367,25 +2361,18 @@ routerstatus_format_entry(char *buf, size_t buf_len, /* V3 microdesc consensuses don't have "a" lines. */ if (format == NS_V3_CONSENSUS_MICRODESC) - return 0; + goto done; /* Possible "a" line. At most one for now. */ if (!tor_addr_is_null(&rs->ipv6_addr)) { - r = tor_snprintf(cp, buf_len - (cp-buf), - "a %s\n", - fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport)); - if (r<0) { - log_warn(LD_BUG, "Not enough space in buffer."); - return -1; - } - cp += strlen(cp); + smartlist_add_asprintf(chunks, "a %s\n", + fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport)); } if (format == NS_V3_CONSENSUS) - return 0; + goto done; - /* NOTE: Whenever this list expands, be sure to increase MAX_FLAG_LINE_LEN*/ - r = tor_snprintf(cp, buf_len - (cp-buf), + smartlist_add_asprintf(chunks, "s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", /* These must stay in alphabetical order. */ rs->is_authority?" Authority":"", @@ -2401,20 +2388,11 @@ routerstatus_format_entry(char *buf, size_t buf_len, rs->is_unnamed?" Unnamed":"", rs->is_v2_dir?" V2Dir":"", rs->is_valid?" Valid":""); - if (r<0) { - log_warn(LD_BUG, "Not enough space in buffer."); - return -1; - } - cp += strlen(cp); /* length of "opt v \n" */ #define V_LINE_OVERHEAD 7 if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) { - if (tor_snprintf(cp, buf_len - (cp-buf), "v %s\n", version)<0) { - log_warn(LD_BUG, "Unable to print router version."); - return -1; - } - cp += strlen(cp); + smartlist_add_asprintf(chunks, "v %s\n", version); } if (format != NS_V2) { @@ -2434,7 +2412,7 @@ routerstatus_format_entry(char *buf, size_t buf_len, log_warn(LD_BUG, "Cannot get any descriptor for %s " "(wanted descriptor %s).", id, dd); - return -1; + goto err; } /* This assert could fire for the control port, because @@ -2469,39 +2447,32 @@ routerstatus_format_entry(char *buf, size_t buf_len, tor_assert(desc); bw_kb = router_get_advertised_bandwidth_capped(desc) / 1000; } - r = tor_snprintf(cp, buf_len - (cp-buf), - "w Bandwidth=%d\n", bw_kb); + smartlist_add_asprintf(chunks, + "w Bandwidth=%d", bw_kb); - if (r<0) { - log_warn(LD_BUG, "Not enough space in buffer."); - return -1; - } - cp += strlen(cp); if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) { - *--cp = '\0'; /* Kill "\n" */ - r = tor_snprintf(cp, buf_len - (cp-buf), - " Measured=%d\n", vrs->measured_bw_kb); - if (r<0) { - log_warn(LD_BUG, "Not enough space in buffer for weight line."); - return -1; - } - cp += strlen(cp); + smartlist_add_asprintf(chunks, + " Measured=%d", vrs->measured_bw_kb); } + smartlist_add(chunks, tor_strdup("\n")); if (desc) { summary = policy_summarize(desc->exit_policy, AF_INET); - r = tor_snprintf(cp, buf_len - (cp-buf), "p %s\n", summary); - if (r<0) { - log_warn(LD_BUG, "Not enough space in buffer."); - tor_free(summary); - return -1; - } - cp += strlen(cp); + smartlist_add_asprintf(chunks, "p %s\n", summary); tor_free(summary); } } - return 0; + done: + result = smartlist_join_strings(chunks, "", 0, NULL); + + err: + if (chunks) { + SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); + smartlist_free(chunks); + } + + return result; } /** Helper for sorting: compares two routerinfos first by address, and then by @@ -3191,14 +3162,13 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, /** For v2 authoritative directories only: Replace the contents of * <b>the_v2_networkstatus</b> with a newly generated network status * object. */ -static cached_dir_t * +cached_dir_t * generate_v2_networkstatus_opinion(void) { cached_dir_t *r = NULL; - size_t len, identity_pkey_len; + size_t identity_pkey_len; char *status = NULL, *client_versions = NULL, *server_versions = NULL, *identity_pkey = NULL, *hostname = NULL; - char *outp, *endp; const or_options_t *options = get_options(); char fingerprint[FINGERPRINT_LEN+1]; char published[ISO_TIME_LEN+1]; @@ -3217,6 +3187,7 @@ generate_v2_networkstatus_opinion(void) char *version_lines = NULL; smartlist_t *routers = NULL; digestmap_t *omit_as_sybil = NULL; + smartlist_t *chunks = NULL; private_key = get_server_identity_key(); @@ -3255,12 +3226,8 @@ generate_v2_networkstatus_opinion(void) version_lines = tor_strdup(""); } - len = 4096+strlen(client_versions)+strlen(server_versions); - len += identity_pkey_len*2; - len += (RS_ENTRY_LEN)*smartlist_len(rl->routers); - - status = tor_malloc(len); - tor_snprintf(status, len, + chunks = smartlist_new(); + smartlist_add_asprintf(chunks, "network-status-version 2\n" "dir-source %s %s %d\n" "fingerprint %s\n" @@ -3280,8 +3247,6 @@ generate_v2_networkstatus_opinion(void) versioning ? " Versions" : "", version_lines, identity_pkey); - outp = status + strlen(status); - endp = status + len; /* precompute this part, since we need it to decide what "stable" * means. */ @@ -3312,35 +3277,33 @@ generate_v2_networkstatus_opinion(void) if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest)) clear_status_flags_on_sybil(&rs); - if (routerstatus_format_entry(outp, endp-outp, &rs, version, NS_V2, - NULL)) { - log_warn(LD_BUG, "Unable to print router status."); - tor_free(version); - goto done; + { + char *rsf = routerstatus_format_entry(&rs, version, NS_V2, NULL); + if (rsf) + smartlist_add(chunks, rsf); } tor_free(version); - outp += strlen(outp); } } SMARTLIST_FOREACH_END(ri); - if (tor_snprintf(outp, endp-outp, "directory-signature %s\n", - options->Nickname)<0) { - log_warn(LD_BUG, "Unable to write signature line."); - goto done; - } - if (router_get_networkstatus_v2_hash(status, digest)<0) { - log_warn(LD_BUG, "Unable to hash network status"); - goto done; - } - outp += strlen(outp); + smartlist_add_asprintf(chunks, "directory-signature %s\n", + options->Nickname); + + crypto_digest_smartlist(digest, DIGEST_LEN, chunks, "", DIGEST_SHA1); note_crypto_pk_op(SIGN_DIR); - if (router_append_dirobj_signature(outp,endp-outp,digest,DIGEST_LEN, - private_key)<0) { - log_warn(LD_BUG, "Unable to sign router status."); - goto done; + { + char *sig; + if (!(sig = router_get_dirobj_signature(digest,DIGEST_LEN, + private_key))) { + log_warn(LD_BUG, "Unable to sign router status."); + goto done; + } + smartlist_add(chunks, sig); } + status = smartlist_join_strings(chunks, "", 0, NULL); + { networkstatus_v2_t *ns; if (!(ns = networkstatus_v2_parse_from_string(status))) { @@ -3362,6 +3325,10 @@ generate_v2_networkstatus_opinion(void) } done: + if (chunks) { + SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); + smartlist_free(chunks); + } tor_free(client_versions); tor_free(server_versions); tor_free(version_lines); diff --git a/src/or/dirserv.h b/src/or/dirserv.h index d6eb4ab77..f9d36d760 100644 --- a/src/or/dirserv.h +++ b/src/or/dirserv.h @@ -29,28 +29,6 @@ /** Maximum allowable length of a version line in a networkstatus. */ #define MAX_V_LINE_LEN 128 -/** Length of "r Authority BadDirectory BadExit Exit Fast Guard HSDir Named - * Running Stable Unnamed V2Dir Valid\n". */ -#define MAX_FLAG_LINE_LEN 96 -/** Length of "w" line for weighting. Currently at most - * "w Bandwidth=<uint32t> Measured=<uint32t>\n" */ -#define MAX_WEIGHT_LINE_LEN (12+10+10+10+1) -/** Maximum length of an exit policy summary line. */ -#define MAX_POLICY_LINE_LEN (3+MAX_EXITPOLICY_SUMMARY_LEN) -/** Amount of space to allocate for each entry: r, s, and v lines. */ -#define RS_ENTRY_LEN \ - ( /* first line */ \ - MAX_NICKNAME_LEN+BASE64_DIGEST_LEN*2+ISO_TIME_LEN+INET_NTOA_BUF_LEN+ \ - 5*2 /* ports */ + 10 /* punctuation */ + \ - /* second line */ \ - MAX_FLAG_LINE_LEN + \ - /* weight line */ \ - MAX_WEIGHT_LINE_LEN + \ - /* p line. */ \ - MAX_POLICY_LINE_LEN + \ - /* v line. */ \ - MAX_V_LINE_LEN \ - ) int connection_dirserv_flushed_some(dir_connection_t *conn); @@ -128,7 +106,7 @@ size_t dirserv_estimate_data_size(smartlist_t *fps, int is_serverdescs, int compressed); size_t dirserv_estimate_microdesc_size(const smartlist_t *fps, int compressed); -int routerstatus_format_entry(char *buf, size_t buf_len, +char *routerstatus_format_entry( const routerstatus_t *rs, const char *platform, routerstatus_format_type_t format, const vote_routerstatus_t *vrs); @@ -154,6 +132,7 @@ int dirserv_get_measured_bw_cache_size(void); int dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_out, time_t *as_of_out); int dirserv_has_measured_bw(const char *node_id); +cached_dir_t *generate_v2_networkstatus_opinion(void); #endif int dirserv_read_measured_bandwidths(const char *from_file, diff --git a/src/or/dirvote.c b/src/or/dirvote.c index 417721dc3..b02434c89 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -57,9 +57,6 @@ static char *make_consensus_method_list(int low, int high, const char *sep); * Voting * =====*/ -/* Overestimated. */ -#define MICRODESC_LINE_LEN 80 - /** Return a new string containing the string representation of the vote in * <b>v3_ns</b>, signed with our v3 signing key <b>private_signing_key</b>. * For v3 authorities. */ @@ -67,17 +64,14 @@ char * format_networkstatus_vote(crypto_pk_t *private_signing_key, networkstatus_t *v3_ns) { - size_t len; - char *status = NULL; + smartlist_t *chunks; const char *client_versions = NULL, *server_versions = NULL; - char *outp, *endp; char fingerprint[FINGERPRINT_LEN+1]; char digest[DIGEST_LEN]; uint32_t addr; - routerlist_t *rl = router_get_routerlist(); - char *version_lines = NULL; - int r; + char *client_versions_line = NULL, *server_versions_line = NULL; networkstatus_voter_info_t *voter; + char *status = NULL; tor_assert(private_signing_key); tor_assert(v3_ns->type == NS_TYPE_VOTE || v3_ns->type == NS_TYPE_OPINION); @@ -91,43 +85,20 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, client_versions = v3_ns->client_versions; server_versions = v3_ns->server_versions; - if (client_versions || server_versions) { - size_t v_len = 64; - char *cp; - if (client_versions) - v_len += strlen(client_versions); - if (server_versions) - v_len += strlen(server_versions); - version_lines = tor_malloc(v_len); - cp = version_lines; - if (client_versions) { - r = tor_snprintf(cp, v_len-(cp-version_lines), - "client-versions %s\n", client_versions); - if (r < 0) { - log_err(LD_BUG, "Insufficient memory for client-versions line"); - tor_assert(0); - } - cp += strlen(cp); - } - if (server_versions) { - r = tor_snprintf(cp, v_len-(cp-version_lines), - "server-versions %s\n", server_versions); - if (r < 0) { - log_err(LD_BUG, "Insufficient memory for server-versions line"); - tor_assert(0); - } - } + if (client_versions) { + tor_asprintf(&client_versions_line, "client-versions %s\n", + client_versions); } else { - version_lines = tor_strdup(""); + client_versions_line = tor_strdup(""); + } + if (server_versions) { + tor_asprintf(&server_versions_line, "server-versions %s\n", + server_versions); + } else { + server_versions_line = tor_strdup(""); } - len = 8192; - len += strlen(version_lines); - len += (RS_ENTRY_LEN+MICRODESC_LINE_LEN)*smartlist_len(rl->routers); - len += strlen("\ndirectory-footer\n"); - len += v3_ns->cert->cache_info.signed_descriptor_len; - - status = tor_malloc(len); + chunks = smartlist_new(); { char published[ISO_TIME_LEN+1]; char va[ISO_TIME_LEN+1]; @@ -151,7 +122,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, params = tor_strdup(""); tor_assert(cert); - r = tor_snprintf(status, len, + smartlist_add_asprintf(chunks, "network-status-version 3\n" "vote-status %s\n" "consensus-methods %s\n" @@ -160,7 +131,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, "fresh-until %s\n" "valid-until %s\n" "voting-delay %d %d\n" - "%s" /* versions */ + "%s%s" /* versions */ "known-flags %s\n" "flag-thresholds %s\n" "params %s\n" @@ -170,7 +141,8 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, methods, published, va, fu, vu, v3_ns->vote_seconds, v3_ns->dist_seconds, - version_lines, + client_versions_line, + server_versions_line, flags, flag_thresholds, params, @@ -178,93 +150,67 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, fmt_addr32(addr), voter->dir_port, voter->or_port, voter->contact); - if (r < 0) { - log_err(LD_BUG, "Insufficient memory for network status line"); - tor_assert(0); - } - tor_free(params); tor_free(flags); tor_free(flag_thresholds); tor_free(methods); - outp = status + strlen(status); - endp = status + len; if (!tor_digest_is_zero(voter->legacy_id_digest)) { char fpbuf[HEX_DIGEST_LEN+1]; base16_encode(fpbuf, sizeof(fpbuf), voter->legacy_id_digest, DIGEST_LEN); - r = tor_snprintf(outp, endp-outp, "legacy-dir-key %s\n", fpbuf); - if (r < 0) { - log_err(LD_BUG, "Insufficient memory for legacy-dir-key line"); - tor_assert(0); - } - outp += strlen(outp); + smartlist_add_asprintf(chunks, "legacy-dir-key %s\n", fpbuf); } - tor_assert(outp + cert->cache_info.signed_descriptor_len < endp); - memcpy(outp, cert->cache_info.signed_descriptor_body, - cert->cache_info.signed_descriptor_len); - - outp += cert->cache_info.signed_descriptor_len; + smartlist_add(chunks, tor_strndup(cert->cache_info.signed_descriptor_body, + cert->cache_info.signed_descriptor_len)); } SMARTLIST_FOREACH_BEGIN(v3_ns->routerstatus_list, vote_routerstatus_t *, vrs) { + char *rsf; vote_microdesc_hash_t *h; - if (routerstatus_format_entry(outp, endp-outp, &vrs->status, - vrs->version, NS_V3_VOTE, vrs) < 0) { - log_warn(LD_BUG, "Unable to print router status."); - goto err; - } - outp += strlen(outp); + rsf = routerstatus_format_entry(&vrs->status, + vrs->version, NS_V3_VOTE, vrs); + if (rsf) + smartlist_add(chunks, rsf); for (h = vrs->microdesc; h; h = h->next) { - size_t mlen = strlen(h->microdesc_hash_line); - if (outp+mlen >= endp) { - log_warn(LD_BUG, "Can't fit microdesc line in vote."); - } - memcpy(outp, h->microdesc_hash_line, mlen+1); - outp += strlen(outp); + smartlist_add(chunks, tor_strdup(h->microdesc_hash_line)); } } SMARTLIST_FOREACH_END(vrs); - r = tor_snprintf(outp, endp-outp, "directory-footer\n"); - if (r < 0) { - log_err(LD_BUG, "Insufficient memory for directory-footer line"); - tor_assert(0); - } - outp += strlen(outp); + smartlist_add(chunks, tor_strdup("directory-footer\n")); + + /* The digest includes everything up through the space after + * directory-signature. (Yuck.) */ + crypto_digest_smartlist(digest, DIGEST_LEN, chunks, + "directory-signature ", DIGEST_SHA1); { char signing_key_fingerprint[FINGERPRINT_LEN+1]; - if (tor_snprintf(outp, endp-outp, "directory-signature ")<0) { - log_warn(LD_BUG, "Unable to start signature line."); - goto err; - } - outp += strlen(outp); - if (crypto_pk_get_fingerprint(private_signing_key, signing_key_fingerprint, 0)<0) { log_warn(LD_BUG, "Unable to get fingerprint for signing key"); goto err; } - if (tor_snprintf(outp, endp-outp, "%s %s\n", fingerprint, - signing_key_fingerprint)<0) { - log_warn(LD_BUG, "Unable to end signature line."); - goto err; - } - outp += strlen(outp); + + smartlist_add_asprintf(chunks, "directory-signature %s %s\n", fingerprint, + signing_key_fingerprint); } - if (router_get_networkstatus_v3_hash(status, digest, DIGEST_SHA1)<0) - goto err; note_crypto_pk_op(SIGN_DIR); - if (router_append_dirobj_signature(outp,endp-outp,digest, DIGEST_LEN, - private_signing_key)<0) { - log_warn(LD_BUG, "Unable to sign networkstatus vote."); - goto err; + { + char *sig = router_get_dirobj_signature(digest, DIGEST_LEN, + private_signing_key); + if (!sig) { + log_warn(LD_BUG, "Unable to sign networkstatus vote."); + goto err; + } + smartlist_add(chunks, sig); } + status = smartlist_join_strings(chunks, "", 0, NULL); + { networkstatus_t *v; if (!(v = networkstatus_parse_vote_from_string(status, NULL, @@ -282,7 +228,12 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, err: tor_free(status); done: - tor_free(version_lines); + tor_free(client_versions_line); + tor_free(server_versions_line); + if (chunks) { + SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); + smartlist_free(chunks); + } return status; } @@ -526,24 +477,6 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method, return most; } -/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest - * at <b>digest_out</b> to the hash of the concatenation of those strings, - * computed with the algorithm <b>alg</b>. */ -static void -hash_list_members(char *digest_out, size_t len_out, - smartlist_t *lst, digest_algorithm_t alg) -{ - crypto_digest_t *d; - if (alg == DIGEST_SHA1) - d = crypto_digest_new(); - else - d = crypto_digest256_new(alg); - SMARTLIST_FOREACH(lst, const char *, cp, - crypto_digest_add_bytes(d, cp, strlen(cp))); - crypto_digest_get_digest(d, digest_out, len_out); - crypto_digest_free(d); -} - /** Sorting helper: compare two strings based on their values as base-ten * positive integers. (Non-integers are treated as prior to all integers, and * compared lexically.) */ @@ -2027,12 +1960,12 @@ networkstatus_compute_consensus(smartlist_t *votes, } { - char buf[4096]; + char *buf; /* Okay!! Now we can write the descriptor... */ /* First line goes into "buf". */ - routerstatus_format_entry(buf, sizeof(buf), &rs_out, NULL, - rs_format, NULL); - smartlist_add(chunks, tor_strdup(buf)); + buf = routerstatus_format_entry(&rs_out, NULL, rs_format, NULL); + if (buf) + smartlist_add(chunks, buf); } /* Now an m line, if applicable. */ if (flavor == FLAV_MICRODESC && @@ -2144,12 +2077,12 @@ networkstatus_compute_consensus(smartlist_t *votes, size_t digest_len = flavor == FLAV_NS ? DIGEST_LEN : DIGEST256_LEN; const char *algname = crypto_digest_algorithm_get_name(digest_alg); - char sigbuf[4096]; + char *signature; smartlist_add(chunks, tor_strdup("directory-signature ")); /* Compute the hash of the chunks. */ - hash_list_members(digest, digest_len, chunks, digest_alg); + crypto_digest_smartlist(digest, digest_len, chunks, "", digest_alg); /* Get the fingerprints */ crypto_pk_get_fingerprint(identity_key, fingerprint, 0); @@ -2165,14 +2098,12 @@ networkstatus_compute_consensus(smartlist_t *votes, signing_key_fingerprint); } /* And the signature. */ - sigbuf[0] = '\0'; - if (router_append_dirobj_signature(sigbuf, sizeof(sigbuf), - digest, digest_len, - signing_key)) { + if (!(signature = router_get_dirobj_signature(digest, digest_len, + signing_key))) { log_warn(LD_BUG, "Couldn't sign consensus networkstatus."); goto done; } - smartlist_add(chunks, tor_strdup(sigbuf)); + smartlist_add(chunks, signature); if (legacy_id_key_digest && legacy_signing_key && consensus_method >= 3) { smartlist_add(chunks, tor_strdup("directory-signature ")); @@ -2188,14 +2119,13 @@ networkstatus_compute_consensus(smartlist_t *votes, algname, fingerprint, signing_key_fingerprint); } - sigbuf[0] = '\0'; - if (router_append_dirobj_signature(sigbuf, sizeof(sigbuf), - digest, digest_len, - legacy_signing_key)) { + + if (!(signature = router_get_dirobj_signature(digest, digest_len, + legacy_signing_key))) { log_warn(LD_BUG, "Couldn't sign consensus networkstatus."); goto done; } - smartlist_add(chunks, tor_strdup(sigbuf)); + smartlist_add(chunks, signature); } } diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 8846cd063..f5428f165 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -2115,9 +2115,7 @@ signed_descs_update_status_from_consensus_networkstatus(smartlist_t *descs) char * networkstatus_getinfo_helper_single(const routerstatus_t *rs) { - char buf[RS_ENTRY_LEN+1]; - routerstatus_format_entry(buf, sizeof(buf), rs, NULL, NS_CONTROL_PORT, NULL); - return tor_strdup(buf); + return routerstatus_format_entry(rs, NULL, NS_CONTROL_PORT, NULL); } /** Alloc and return a string describing routerstatuses for the most diff --git a/src/or/or.h b/src/or/or.h index d7142e298..f2f27eea5 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2329,7 +2329,8 @@ typedef struct networkstatus_v2_t { typedef struct vote_microdesc_hash_t { /** Next element in the list, or NULL. */ struct vote_microdesc_hash_t *next; - /** The raw contents of the microdesc hash line, excluding the "m". */ + /** The raw contents of the microdesc hash line, from the "m" through the + * newline. */ char *microdesc_hash_line; } vote_microdesc_hash_t; diff --git a/src/or/router.c b/src/or/router.c index c8c9ce1a4..b9d5b7b54 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1944,9 +1944,8 @@ router_rebuild_descriptor(int force) /* ri was allocated with tor_malloc_zero, so there is no need to * zero ri->cache_info.extra_info_digest here. */ } - ri->cache_info.signed_descriptor_body = tor_malloc(8192); - if (router_dump_router_to_string(ri->cache_info.signed_descriptor_body, 8192, - ri, get_server_identity_key()) < 0) { + if (! (ri->cache_info.signed_descriptor_body = router_dump_router_to_string( + ri, get_server_identity_key()))) { log_warn(LD_BUG, "Couldn't generate router descriptor."); routerinfo_free(ri); extrainfo_free(ei); @@ -2246,54 +2245,54 @@ get_platform_str(char *platform, size_t len) #define DEBUG_ROUTER_DUMP_ROUTER_TO_STRING /** OR only: Given a routerinfo for this router, and an identity key to sign - * with, encode the routerinfo as a signed server descriptor and write the - * result into <b>s</b>, using at most <b>maxlen</b> bytes. Return -1 on - * failure, and the number of bytes used on success. + * with, encode the routerinfo as a signed server descriptor and return a new + * string encoding the result, or NULL on failure. */ -int -router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, +char * +router_dump_router_to_string(routerinfo_t *router, crypto_pk_t *ident_key) { - char *onion_pkey; /* Onion key, PEM-encoded. */ - char *identity_pkey; /* Identity key, PEM-encoded. */ + /* XXXX025 Make this look entirely at its arguments, and not at globals. + */ + char *onion_pkey = NULL; /* Onion key, PEM-encoded. */ + char *identity_pkey = NULL; /* Identity key, PEM-encoded. */ char digest[DIGEST_LEN]; char published[ISO_TIME_LEN+1]; char fingerprint[FINGERPRINT_LEN+1]; int has_extra_info_digest; char extra_info_digest[HEX_DIGEST_LEN+1]; size_t onion_pkeylen, identity_pkeylen; - size_t written; - int result=0; - char *family_line; + char *family_line = NULL; char *extra_or_address = NULL; const or_options_t *options = get_options(); + smartlist_t *chunks = NULL; + char *output = NULL; /* Make sure the identity key matches the one in the routerinfo. */ if (!crypto_pk_eq_keys(ident_key, router->identity_pkey)) { log_warn(LD_BUG,"Tried to sign a router with a private key that didn't " "match router's public key!"); - return -1; + goto err; } /* record our fingerprint, so we can include it in the descriptor */ if (crypto_pk_get_fingerprint(router->identity_pkey, fingerprint, 1)<0) { log_err(LD_BUG,"Error computing fingerprint"); - return -1; + goto err; } /* PEM-encode the onion key */ if (crypto_pk_write_public_key_to_string(router->onion_pkey, &onion_pkey,&onion_pkeylen)<0) { log_warn(LD_BUG,"write onion_pkey to string failed!"); - return -1; + goto err; } /* PEM-encode the identity key */ if (crypto_pk_write_public_key_to_string(router->identity_pkey, &identity_pkey,&identity_pkeylen)<0) { log_warn(LD_BUG,"write identity_pkey to string failed!"); - tor_free(onion_pkey); - return -1; + goto err; } /* Encode the publication time. */ @@ -2328,8 +2327,9 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, } } + chunks = smartlist_new(); /* Generate the easy portion of the router descriptor. */ - result = tor_snprintf(s, maxlen, + smartlist_add_asprintf(chunks, "router %s %s %d 0 %d\n" "%s" "platform %s\n" @@ -2364,28 +2364,11 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, options->HidServDirectoryV2 ? "hidden-service-dir\n" : "", options->AllowSingleHopExits ? "allow-single-hop-exits\n" : ""); - tor_free(family_line); - tor_free(onion_pkey); - tor_free(identity_pkey); - tor_free(extra_or_address); - - if (result < 0) { - log_warn(LD_BUG,"descriptor snprintf #1 ran out of room!"); - return -1; - } - /* From now on, we use 'written' to remember the current length of 's'. */ - written = result; - if (options->ContactInfo && strlen(options->ContactInfo)) { const char *ci = options->ContactInfo; if (strchr(ci, '\n') || strchr(ci, '\r')) ci = escaped(ci); - result = tor_snprintf(s+written,maxlen-written, "contact %s\n", ci); - if (result<0) { - log_warn(LD_BUG,"descriptor snprintf #2 ran out of room!"); - return -1; - } - written += result; + smartlist_add_asprintf(chunks, "contact %s\n", ci); } #ifdef CURVE25519_ENABLED @@ -2394,105 +2377,92 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, base64_encode(kbuf, sizeof(kbuf), (const char *)router->onion_curve25519_pkey->public_key, CURVE25519_PUBKEY_LEN); - result = tor_snprintf(s+written,maxlen-written, "ntor-onion-key %s", - kbuf); - if (result<0) { - log_warn(LD_BUG,"descriptor snprintf ran out of room!"); - return -1; - } - written += result; + smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf); } #endif /* Write the exit policy to the end of 's'. */ if (!router->exit_policy || !smartlist_len(router->exit_policy)) { - strlcat(s+written, "reject *:*\n", maxlen-written); - written += strlen("reject *:*\n"); + smartlist_add(chunks, tor_strdup("reject *:*\n")); } else if (router->exit_policy) { int i; for (i = 0; i < smartlist_len(router->exit_policy); ++i) { + char pbuf[POLICY_BUF_LEN]; addr_policy_t *tmpe = smartlist_get(router->exit_policy, i); + int result; if (tor_addr_family(&tmpe->addr) == AF_INET6) continue; /* Don't include IPv6 parts of address policy */ - result = policy_write_item(s+written, maxlen-written, tmpe, 1); + result = policy_write_item(pbuf, POLICY_BUF_LEN, tmpe, 1); if (result < 0) { log_warn(LD_BUG,"descriptor policy_write_item ran out of room!"); - return -1; - } - tor_assert(result == (int)strlen(s+written)); - written += result; - if (written+2 > maxlen) { - log_warn(LD_BUG,"descriptor policy_write_item ran out of room (2)!"); - return -1; + goto err; } - s[written++] = '\n'; + smartlist_add_asprintf(chunks, "%s\n", pbuf); } } if (router->ipv6_exit_policy) { char *p6 = write_short_policy(router->ipv6_exit_policy); if (p6 && strcmp(p6, "reject 1-65535")) { - result = tor_snprintf(s+written, maxlen-written, + smartlist_add_asprintf(chunks, "ipv6-policy %s\n", p6); - if (result<0) { - log_warn(LD_BUG,"Descriptor printf of policy ran out of room"); - tor_free(p6); - return -1; - } - written += result; } tor_free(p6); } - if (written + DIROBJ_MAX_SIG_LEN > maxlen) { - /* Not enough room for signature. */ - log_warn(LD_BUG,"not enough room left in descriptor for signature!"); - return -1; - } - /* Sign the descriptor */ - strlcpy(s+written, "router-signature\n", maxlen-written); - written += strlen(s+written); - s[written] = '\0'; - if (router_get_router_hash(s, strlen(s), digest) < 0) { - return -1; - } + smartlist_add(chunks, tor_strdup("router-signature\n")); + + crypto_digest_smartlist(digest, DIGEST_LEN, chunks, "", DIGEST_SHA1); note_crypto_pk_op(SIGN_RTR); - if (router_append_dirobj_signature(s+written,maxlen-written, - digest,DIGEST_LEN,ident_key)<0) { - log_warn(LD_BUG, "Couldn't sign router descriptor"); - return -1; + { + char *sig; + if (!(sig = router_get_dirobj_signature(digest, DIGEST_LEN, ident_key))) { + log_warn(LD_BUG, "Couldn't sign router descriptor"); + goto err; + } + smartlist_add(chunks, sig); } - written += strlen(s+written); - if (written+2 > maxlen) { - log_warn(LD_BUG,"Not enough room to finish descriptor."); - return -1; - } /* include a last '\n' */ - s[written] = '\n'; - s[written+1] = 0; + smartlist_add(chunks, tor_strdup("\n")); + + output = smartlist_join_strings(chunks, "", 0, NULL); #ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING { char *s_dup; const char *cp; routerinfo_t *ri_tmp; - cp = s_dup = tor_strdup(s); + cp = s_dup = tor_strdup(output); ri_tmp = router_parse_entry_from_string(cp, NULL, 1, 0, NULL); if (!ri_tmp) { log_err(LD_BUG, "We just generated a router descriptor we can't parse."); - log_err(LD_BUG, "Descriptor was: <<%s>>", s); - return -1; + log_err(LD_BUG, "Descriptor was: <<%s>>", output); + goto err; } tor_free(s_dup); routerinfo_free(ri_tmp); } #endif - return (int)written+1; + goto done; + + err: + tor_free(output); /* sets output to NULL */ + done: + if (chunks) { + SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp)); + smartlist_free(chunks); + } + tor_free(family_line); + tor_free(onion_pkey); + tor_free(identity_pkey); + tor_free(extra_or_address); + + return output; } /** Copy the primary (IPv4) OR port (IP address and TCP port) for diff --git a/src/or/router.h b/src/or/router.h index 96749b53c..93ca22a93 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -90,8 +90,8 @@ int router_is_me(const routerinfo_t *router); int router_fingerprint_is_me(const char *fp); int router_pick_published_address(const or_options_t *options, uint32_t *addr); int router_rebuild_descriptor(int force); -int router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, - crypto_pk_t *ident_key); +char *router_dump_router_to_string(routerinfo_t *router, + crypto_pk_t *ident_key); void router_get_prim_orport(const routerinfo_t *router, tor_addr_port_t *addr_port_out); void router_get_pref_orport(const routerinfo_t *router, diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 0d535a6c3..890d59660 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -662,18 +662,6 @@ router_get_networkstatus_v3_hashes(const char *s, digests_t *digests) ' '); } -/** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status - * string in <b>s</b>. Return 0 on success, -1 on failure. */ -int -router_get_networkstatus_v3_hash(const char *s, char *digest, - digest_algorithm_t alg) -{ - return router_get_hash_impl(s, strlen(s), digest, - "network-status-version", - "\ndirectory-signature", - ' ', alg); -} - /** Set <b>digest</b> to the SHA-1 digest of the hash of the <b>s_len</b>-byte * extrainfo string at <b>s</b>. Return 0 on success, -1 on failure. */ int @@ -684,19 +672,23 @@ router_get_extrainfo_hash(const char *s, size_t s_len, char *digest) } /** Helper: used to generate signatures for routers, directories and - * network-status objects. Given a digest in <b>digest</b> and a secret - * <b>private_key</b>, generate an PKCS1-padded signature, BASE64-encode it, - * surround it with -----BEGIN/END----- pairs, and write it to the - * <b>buf_len</b>-byte buffer at <b>buf</b>. Return 0 on success, -1 on - * failure. + * network-status objects. Given a <b>digest_len</b>-byte digest in + * <b>digest</b> and a secret <b>private_key</b>, generate an PKCS1-padded + * signature, BASE64-encode it, surround it with -----BEGIN/END----- pairs, + * and return the new signature on success or NULL on failure. */ -int -router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest, - size_t digest_len, crypto_pk_t *private_key) +char * +router_get_dirobj_signature(const char *digest, + size_t digest_len, + crypto_pk_t *private_key) { char *signature; size_t i, keysize; int siglen; + char *buf = NULL; + size_t buf_len; + /* overestimate of BEGIN/END lines total len. */ +#define BEGIN_END_OVERHEAD_LEN 64 keysize = crypto_pk_keysize(private_key); signature = tor_malloc(keysize); @@ -706,7 +698,12 @@ router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest, log_warn(LD_BUG,"Couldn't sign digest."); goto err; } - if (strlcat(buf, "-----BEGIN SIGNATURE-----\n", buf_len) >= buf_len) + + /* The *2 here is a ridiculous overestimate of base-64 overhead. */ + buf_len = (siglen * 2) + BEGIN_END_OVERHEAD_LEN; + buf = tor_malloc(buf_len); + + if (strlcpy(buf, "-----BEGIN SIGNATURE-----\n", buf_len) >= buf_len) goto truncated; i = strlen(buf); @@ -719,13 +716,42 @@ router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest, goto truncated; tor_free(signature); - return 0; + return buf; truncated: log_warn(LD_BUG,"tried to exceed string length."); err: tor_free(signature); - return -1; + tor_free(buf); + return NULL; +} + +/** Helper: used to generate signatures for routers, directories and + * network-status objects. Given a digest in <b>digest</b> and a secret + * <b>private_key</b>, generate an PKCS1-padded signature, BASE64-encode it, + * surround it with -----BEGIN/END----- pairs, and write it to the + * <b>buf_len</b>-byte buffer at <b>buf</b>. Return 0 on success, -1 on + * failure. + */ +int +router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest, + size_t digest_len, crypto_pk_t *private_key) +{ + size_t sig_len, s_len; + char *sig = router_get_dirobj_signature(digest, digest_len, private_key); + if (!sig) { + log_warn(LD_BUG, "No signature generated"); + return -1; + } + sig_len = strlen(sig); + s_len = strlen(buf); + if (sig_len + s_len + 1 > buf_len) { + log_warn(LD_BUG, "Not enough room for signature"); + tor_free(sig); + return -1; + } + memcpy(buf+s_len, sig, sig_len+1); + return 0; } /** Return VS_RECOMMENDED if <b>myversion</b> is contained in diff --git a/src/or/routerparse.h b/src/or/routerparse.h index 7bf7d7907..c65cdc996 100644 --- a/src/or/routerparse.h +++ b/src/or/routerparse.h @@ -16,11 +16,12 @@ int router_get_router_hash(const char *s, size_t s_len, char *digest); int router_get_dir_hash(const char *s, char *digest); int router_get_runningrouters_hash(const char *s, char *digest); int router_get_networkstatus_v2_hash(const char *s, char *digest); -int router_get_networkstatus_v3_hash(const char *s, char *digest, - digest_algorithm_t algorithm); int router_get_networkstatus_v3_hashes(const char *s, digests_t *digests); int router_get_extrainfo_hash(const char *s, size_t s_len, char *digest); #define DIROBJ_MAX_SIG_LEN 256 +char *router_get_dirobj_signature(const char *digest, + size_t digest_len, + crypto_pk_t *private_key); int router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest, size_t digest_len, |