[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [tor/master] Split the authority-cert and signature/hash code from routerparse
commit 430ca38f706be08e0df0c1cf025786cb25e46172
Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
Date: Sun Sep 30 23:08:25 2018 -0500
Split the authority-cert and signature/hash code from routerparse
---
src/core/include.am | 7 +
src/feature/dirauth/dirvote.c | 1 +
src/feature/dirparse/authcert_members.i | 13 +
src/feature/dirparse/authcert_parse.c | 207 +++++++++++++
src/feature/dirparse/authcert_parse.h | 18 ++
src/feature/dirparse/routerparse.c | 498 +-------------------------------
src/feature/dirparse/routerparse.h | 17 +-
src/feature/dirparse/sigcommon.c | 185 ++++++++++++
src/feature/dirparse/sigcommon.h | 48 +++
src/feature/dirparse/signing.c | 98 +++++++
src/feature/dirparse/signing.h | 23 ++
src/feature/dirparse/unparseable.h | 12 +
src/feature/nodelist/authcert.c | 2 +-
src/feature/relay/router.c | 2 +
src/feature/rend/rendcommon.c | 1 +
src/test/fuzz/fuzz_consensus.c | 3 +-
src/test/fuzz/fuzz_descriptor.c | 3 +-
src/test/fuzz/fuzz_extrainfo.c | 3 +-
src/test/test_dir.c | 1 +
src/test/test_dir_common.c | 1 +
src/test/test_dir_handle_get.c | 1 +
src/test/test_routerlist.c | 1 +
src/test/test_shared_random.c | 1 +
23 files changed, 631 insertions(+), 515 deletions(-)
diff --git a/src/core/include.am b/src/core/include.am
index c1f63c751..a295e6ca3 100644
--- a/src/core/include.am
+++ b/src/core/include.am
@@ -73,8 +73,11 @@ LIBTOR_APP_A_SOURCES = \
src/feature/dircommon/directory.c \
src/feature/dircommon/fp_pair.c \
src/feature/dircommon/voting_schedule.c \
+ src/feature/dirparse/authcert_parse.c \
src/feature/dirparse/parsecommon.c \
src/feature/dirparse/routerparse.c \
+ src/feature/dirparse/sigcommon.c \
+ src/feature/dirparse/signing.c \
src/feature/dirparse/unparseable.c \
src/feature/hibernate/hibernate.c \
src/feature/hs/hs_cache.c \
@@ -288,8 +291,12 @@ noinst_HEADERS += \
src/feature/dircommon/fp_pair.h \
src/feature/dircommon/vote_timing_st.h \
src/feature/dircommon/voting_schedule.h \
+ src/feature/dirparse/authcert_members.i \
+ src/feature/dirparse/authcert_parse.h \
src/feature/dirparse/parsecommon.h \
src/feature/dirparse/routerparse.h \
+ src/feature/dirparse/sigcommon.h \
+ src/feature/dirparse/signing.h \
src/feature/dirparse/unparseable.h \
src/feature/hibernate/hibernate.h \
src/feature/hs/hs_cache.h \
diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c
index badb6dc4e..f5546abd4 100644
--- a/src/feature/dirauth/dirvote.c
+++ b/src/feature/dirauth/dirvote.c
@@ -28,6 +28,7 @@
#include "feature/nodelist/dirlist.h"
#include "feature/nodelist/routerlist.h"
#include "feature/dirparse/routerparse.h"
+#include "feature/dirparse/signing.h"
#include "feature/nodelist/fmt_routerstatus.h"
#include "feature/client/entrynodes.h" /* needed for guardfraction methods */
#include "feature/nodelist/torcert.h"
diff --git a/src/feature/dirparse/authcert_members.i b/src/feature/dirparse/authcert_members.i
new file mode 100644
index 000000000..08cffca97
--- /dev/null
+++ b/src/feature/dirparse/authcert_members.i
@@ -0,0 +1,13 @@
+/*
+ * List of tokens common to V3 authority certificates and V3 consensuses.
+ */
+ T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION,
+ GE(1), NO_OBJ ),
+ T1("dir-identity-key", K_DIR_IDENTITY_KEY, NO_ARGS, NEED_KEY ),
+ T1("dir-key-published",K_DIR_KEY_PUBLISHED, CONCAT_ARGS, NO_OBJ),
+ T1("dir-key-expires", K_DIR_KEY_EXPIRES, CONCAT_ARGS, NO_OBJ),
+ T1("dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY ),
+ T1("dir-key-crosscert", K_DIR_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ),
+ T1("dir-key-certification", K_DIR_KEY_CERTIFICATION,
+ NO_ARGS, NEED_OBJ),
+ T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ),
diff --git a/src/feature/dirparse/authcert_parse.c b/src/feature/dirparse/authcert_parse.c
new file mode 100644
index 000000000..2ba46bb8f
--- /dev/null
+++ b/src/feature/dirparse/authcert_parse.c
@@ -0,0 +1,207 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "core/or/or.h"
+#include "feature/dirparse/authcert_parse.h"
+#include "feature/dirparse/parsecommon.h"
+#include "feature/dirparse/sigcommon.h"
+#include "feature/dirparse/unparseable.h"
+#include "feature/nodelist/authcert.h"
+#include "lib/memarea/memarea.h"
+
+#include "feature/nodelist/authority_cert_st.h"
+
+/** List of tokens recognized in V3 authority certificates. */
+static token_rule_t dir_key_certificate_table[] = {
+#include "feature/dirparse/authcert_members.i"
+ T1("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
+ END_OF_TABLE
+};
+
+/** Parse a key certificate from <b>s</b>; point <b>end-of-string</b> to
+ * the first character after the certificate. */
+authority_cert_t *
+authority_cert_parse_from_string(const char *s, const char **end_of_string)
+{
+ /** Reject any certificate at least this big; it is probably an overflow, an
+ * attack, a bug, or some other nonsense. */
+#define MAX_CERT_SIZE (128*1024)
+
+ authority_cert_t *cert = NULL, *old_cert;
+ smartlist_t *tokens = NULL;
+ char digest[DIGEST_LEN];
+ directory_token_t *tok;
+ char fp_declared[DIGEST_LEN];
+ char *eos;
+ size_t len;
+ int found;
+ memarea_t *area = NULL;
+ const char *s_dup = s;
+
+ s = eat_whitespace(s);
+ eos = strstr(s, "\ndir-key-certification");
+ if (! eos) {
+ log_warn(LD_DIR, "No signature found on key certificate");
+ return NULL;
+ }
+ eos = strstr(eos, "\n-----END SIGNATURE-----\n");
+ if (! eos) {
+ log_warn(LD_DIR, "No end-of-signature found on key certificate");
+ return NULL;
+ }
+ eos = strchr(eos+2, '\n');
+ tor_assert(eos);
+ ++eos;
+ len = eos - s;
+
+ if (len > MAX_CERT_SIZE) {
+ log_warn(LD_DIR, "Certificate is far too big (at %lu bytes long); "
+ "rejecting", (unsigned long)len);
+ return NULL;
+ }
+
+ tokens = smartlist_new();
+ area = memarea_new();
+ if (tokenize_string(area,s, eos, tokens, dir_key_certificate_table, 0) < 0) {
+ log_warn(LD_DIR, "Error tokenizing key certificate");
+ goto err;
+ }
+ if (router_get_hash_impl(s, strlen(s), digest, "dir-key-certificate-version",
+ "\ndir-key-certification", '\n', DIGEST_SHA1) < 0)
+ goto err;
+ tok = smartlist_get(tokens, 0);
+ if (tok->tp != K_DIR_KEY_CERTIFICATE_VERSION || strcmp(tok->args[0], "3")) {
+ log_warn(LD_DIR,
+ "Key certificate does not begin with a recognized version (3).");
+ goto err;
+ }
+
+ cert = tor_malloc_zero(sizeof(authority_cert_t));
+ memcpy(cert->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
+
+ tok = find_by_keyword(tokens, K_DIR_SIGNING_KEY);
+ tor_assert(tok->key);
+ cert->signing_key = tok->key;
+ tok->key = NULL;
+ if (crypto_pk_get_digest(cert->signing_key, cert->signing_key_digest))
+ goto err;
+
+ tok = find_by_keyword(tokens, K_DIR_IDENTITY_KEY);
+ tor_assert(tok->key);
+ cert->identity_key = tok->key;
+ tok->key = NULL;
+
+ tok = find_by_keyword(tokens, K_FINGERPRINT);
+ tor_assert(tok->n_args);
+ if (base16_decode(fp_declared, DIGEST_LEN, tok->args[0],
+ strlen(tok->args[0])) != DIGEST_LEN) {
+ log_warn(LD_DIR, "Couldn't decode key certificate fingerprint %s",
+ escaped(tok->args[0]));
+ goto err;
+ }
+
+ if (crypto_pk_get_digest(cert->identity_key,
+ cert->cache_info.identity_digest))
+ goto err;
+
+ if (tor_memneq(cert->cache_info.identity_digest, fp_declared, DIGEST_LEN)) {
+ log_warn(LD_DIR, "Digest of certificate key didn't match declared "
+ "fingerprint");
+ goto err;
+ }
+
+ tok = find_opt_by_keyword(tokens, K_DIR_ADDRESS);
+ if (tok) {
+ struct in_addr in;
+ char *address = NULL;
+ tor_assert(tok->n_args);
+ /* XXX++ use some tor_addr parse function below instead. -RD */
+ if (tor_addr_port_split(LOG_WARN, tok->args[0], &address,
+ &cert->dir_port) < 0 ||
+ tor_inet_aton(address, &in) == 0) {
+ log_warn(LD_DIR, "Couldn't parse dir-address in certificate");
+ tor_free(address);
+ goto err;
+ }
+ cert->addr = ntohl(in.s_addr);
+ tor_free(address);
+ }
+
+ tok = find_by_keyword(tokens, K_DIR_KEY_PUBLISHED);
+ if (parse_iso_time(tok->args[0], &cert->cache_info.published_on) < 0) {
+ goto err;
+ }
+ tok = find_by_keyword(tokens, K_DIR_KEY_EXPIRES);
+ if (parse_iso_time(tok->args[0], &cert->expires) < 0) {
+ goto err;
+ }
+
+ tok = smartlist_get(tokens, smartlist_len(tokens)-1);
+ if (tok->tp != K_DIR_KEY_CERTIFICATION) {
+ log_warn(LD_DIR, "Certificate didn't end with dir-key-certification.");
+ goto err;
+ }
+
+ /* If we already have this cert, don't bother checking the signature. */
+ old_cert = authority_cert_get_by_digests(
+ cert->cache_info.identity_digest,
+ cert->signing_key_digest);
+ found = 0;
+ if (old_cert) {
+ /* XXXX We could just compare signed_descriptor_digest, but that wouldn't
+ * buy us much. */
+ if (old_cert->cache_info.signed_descriptor_len == len &&
+ old_cert->cache_info.signed_descriptor_body &&
+ tor_memeq(s, old_cert->cache_info.signed_descriptor_body, len)) {
+ log_debug(LD_DIR, "We already checked the signature on this "
+ "certificate; no need to do so again.");
+ found = 1;
+ }
+ }
+ if (!found) {
+ if (check_signature_token(digest, DIGEST_LEN, tok, cert->identity_key, 0,
+ "key certificate")) {
+ goto err;
+ }
+
+ tok = find_by_keyword(tokens, K_DIR_KEY_CROSSCERT);
+ if (check_signature_token(cert->cache_info.identity_digest,
+ DIGEST_LEN,
+ tok,
+ cert->signing_key,
+ CST_NO_CHECK_OBJTYPE,
+ "key cross-certification")) {
+ goto err;
+ }
+ }
+
+ cert->cache_info.signed_descriptor_len = len;
+ cert->cache_info.signed_descriptor_body = tor_malloc(len+1);
+ memcpy(cert->cache_info.signed_descriptor_body, s, len);
+ cert->cache_info.signed_descriptor_body[len] = 0;
+ cert->cache_info.saved_location = SAVED_NOWHERE;
+
+ if (end_of_string) {
+ *end_of_string = eat_whitespace(eos);
+ }
+ SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
+ smartlist_free(tokens);
+ if (area) {
+ DUMP_AREA(area, "authority cert");
+ memarea_drop_all(area);
+ }
+ return cert;
+ err:
+ dump_desc(s_dup, "authority cert");
+ authority_cert_free(cert);
+ SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
+ smartlist_free(tokens);
+ if (area) {
+ DUMP_AREA(area, "authority cert");
+ memarea_drop_all(area);
+ }
+ return NULL;
+}
diff --git a/src/feature/dirparse/authcert_parse.h b/src/feature/dirparse/authcert_parse.h
new file mode 100644
index 000000000..f63525e04
--- /dev/null
+++ b/src/feature/dirparse/authcert_parse.h
@@ -0,0 +1,18 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file authcert_parse.h
+ * \brief Header file for authcert_parse.c.
+ **/
+
+#ifndef TOR_AUTHCERT_PARSE_H
+#define TOR_AUTHCERT_PARSE_H
+
+authority_cert_t *authority_cert_parse_from_string(const char *s,
+ const char **end_of_string);
+
+#endif /* !defined(TOR_AUTHCERT_PARSE_H) */
diff --git a/src/feature/dirparse/routerparse.c b/src/feature/dirparse/routerparse.c
index 5ff5fdf23..be1f75e56 100644
--- a/src/feature/dirparse/routerparse.c
+++ b/src/feature/dirparse/routerparse.c
@@ -48,9 +48,6 @@
* <li>authority key certificates (managed from routerlist.c)
* <li>hidden service descriptors (managed from rendcommon.c and rendcache.c)
* </ul>
- *
- * For no terribly good reason, the functions to <i>generate</i> signatures on
- * the above directory objects are also in this module.
**/
#define ROUTERPARSE_PRIVATE
@@ -82,6 +79,8 @@
#include "lib/crypt_ops/crypto_util.h"
#include "lib/memarea/memarea.h"
#include "lib/sandbox/sandbox.h"
+#include "feature/dirparse/authcert_parse.h"
+#include "feature/dirparse/sigcommon.h"
#include "feature/dirparse/unparseable.h"
#include "feature/dirauth/dirvote.h"
@@ -210,26 +209,6 @@ static token_rule_t rtrstatus_token_table[] = {
END_OF_TABLE
};
-/** List of tokens common to V3 authority certificates and V3 consensuses. */
-#define CERTIFICATE_MEMBERS \
- T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION, \
- GE(1), NO_OBJ ), \
- T1("dir-identity-key", K_DIR_IDENTITY_KEY, NO_ARGS, NEED_KEY ),\
- T1("dir-key-published",K_DIR_KEY_PUBLISHED, CONCAT_ARGS, NO_OBJ), \
- T1("dir-key-expires", K_DIR_KEY_EXPIRES, CONCAT_ARGS, NO_OBJ), \
- T1("dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY ),\
- T1("dir-key-crosscert", K_DIR_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ),\
- T1("dir-key-certification", K_DIR_KEY_CERTIFICATION, \
- NO_ARGS, NEED_OBJ), \
- T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ),
-
-/** List of tokens recognized in V3 authority certificates. */
-static token_rule_t dir_key_certificate_table[] = {
- CERTIFICATE_MEMBERS
- T1("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
- END_OF_TABLE
-};
-
/** List of tokens recognized in rendezvous service descriptors */
static token_rule_t desc_token_table[] = {
T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR,
@@ -292,7 +271,7 @@ static token_rule_t networkstatus_token_table[] = {
T01("required-relay-protocols", K_REQUIRED_RELAY_PROTOCOLS,
CONCAT_ARGS, NO_OBJ ),
- CERTIFICATE_MEMBERS
+#include "feature/dirparse/authcert_members.i"
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
T1( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
@@ -385,41 +364,8 @@ static addr_policy_t *router_parse_addr_policy(directory_token_t *tok,
unsigned fmt_flags);
static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok);
-static int router_get_hash_impl_helper(const char *s, size_t s_len,
- const char *start_str,
- const char *end_str, char end_c,
- int log_severity,
- const char **start_out, const char **end_out);
-static int router_get_hash_impl(const char *s, size_t s_len, char *digest,
- const char *start_str, const char *end_str,
- char end_char,
- digest_algorithm_t alg);
-static int router_get_hashes_impl(const char *s, size_t s_len,
- common_digests_t *digests,
- const char *start_str, const char *end_str,
- char end_char);
static smartlist_t *find_all_exitpolicy(smartlist_t *s);
-#define CST_NO_CHECK_OBJTYPE (1<<0)
-static int check_signature_token(const char *digest,
- ssize_t digest_len,
- directory_token_t *tok,
- crypto_pk_t *pkey,
- int flags,
- const char *doctype);
-
-#undef DEBUG_AREA_ALLOC
-
-#ifdef DEBUG_AREA_ALLOC
-#define DUMP_AREA(a,name) STMT_BEGIN \
- size_t alloc=0, used=0; \
- memarea_get_stats((a),&alloc,&used); \
- log_debug(LD_MM, "Area for %s has %lu allocated; using %lu.", \
- name, (unsigned long)alloc, (unsigned long)used); \
- STMT_END
-#else /* !(defined(DEBUG_AREA_ALLOC)) */
-#define DUMP_AREA(a,name) STMT_NIL
-#endif /* defined(DEBUG_AREA_ALLOC) */
/** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
* <b>s</b>. Return 0 on success, -1 on failure.
@@ -498,149 +444,6 @@ router_get_extrainfo_hash(const char *s, size_t s_len, char *digest)
"\nrouter-signature",'\n', DIGEST_SHA1);
}
-/** Helper: used to generate signatures for routers, directories and
- * 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.
- */
-char *
-router_get_dirobj_signature(const char *digest,
- size_t digest_len,
- const 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);
- siglen = crypto_pk_private_sign(private_key, signature, keysize,
- digest, digest_len);
- if (siglen < 0) {
- log_warn(LD_BUG,"Couldn't sign digest.");
- goto err;
- }
-
- /* 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);
- if (base64_encode(buf+i, buf_len-i, signature, siglen,
- BASE64_ENCODE_MULTILINE) < 0) {
- log_warn(LD_BUG,"couldn't base64-encode signature");
- goto err;
- }
-
- if (strlcat(buf, "-----END SIGNATURE-----\n", buf_len) >= buf_len)
- goto truncated;
-
- tor_free(signature);
- return buf;
-
- truncated:
- log_warn(LD_BUG,"tried to exceed string length.");
- err:
- tor_free(signature);
- 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 a 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);
- tor_free(sig);
- return 0;
-}
-
-MOCK_IMPL(STATIC int,
-signed_digest_equals, (const uint8_t *d1, const uint8_t *d2, size_t len))
-{
- return tor_memeq(d1, d2, len);
-}
-
-/** Check whether the object body of the token in <b>tok</b> has a good
- * signature for <b>digest</b> using key <b>pkey</b>.
- * If <b>CST_NO_CHECK_OBJTYPE</b> is set, do not check
- * the object type of the signature object. Use <b>doctype</b> as the type of
- * the document when generating log messages. Return 0 on success, negative
- * on failure.
- */
-static int
-check_signature_token(const char *digest,
- ssize_t digest_len,
- directory_token_t *tok,
- crypto_pk_t *pkey,
- int flags,
- const char *doctype)
-{
- char *signed_digest;
- size_t keysize;
- const int check_objtype = ! (flags & CST_NO_CHECK_OBJTYPE);
-
- tor_assert(pkey);
- tor_assert(tok);
- tor_assert(digest);
- tor_assert(doctype);
-
- if (check_objtype) {
- if (strcmp(tok->object_type, "SIGNATURE")) {
- log_warn(LD_DIR, "Bad object type on %s signature", doctype);
- return -1;
- }
- }
-
- keysize = crypto_pk_keysize(pkey);
- signed_digest = tor_malloc(keysize);
- if (crypto_pk_public_checksig(pkey, signed_digest, keysize,
- tok->object_body, tok->object_size)
- < digest_len) {
- log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype);
- tor_free(signed_digest);
- return -1;
- }
- // log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
- // hex_str(signed_digest,4));
- if (! signed_digest_equals((const uint8_t *)digest,
- (const uint8_t *)signed_digest, digest_len)) {
- log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
- tor_free(signed_digest);
- return -1;
- }
- tor_free(signed_digest);
- return 0;
-}
-
/** Helper: move *<b>s_ptr</b> ahead to the next router, the next extra-info,
* or to the first of the annotations proceeding the next router or
* extra-info---whichever comes first. Set <b>is_extrainfo_out</b> to true if
@@ -1649,191 +1452,6 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
return extrainfo;
}
-/** Parse a key certificate from <b>s</b>; point <b>end-of-string</b> to
- * the first character after the certificate. */
-authority_cert_t *
-authority_cert_parse_from_string(const char *s, const char **end_of_string)
-{
- /** Reject any certificate at least this big; it is probably an overflow, an
- * attack, a bug, or some other nonsense. */
-#define MAX_CERT_SIZE (128*1024)
-
- authority_cert_t *cert = NULL, *old_cert;
- smartlist_t *tokens = NULL;
- char digest[DIGEST_LEN];
- directory_token_t *tok;
- char fp_declared[DIGEST_LEN];
- char *eos;
- size_t len;
- int found;
- memarea_t *area = NULL;
- const char *s_dup = s;
-
- s = eat_whitespace(s);
- eos = strstr(s, "\ndir-key-certification");
- if (! eos) {
- log_warn(LD_DIR, "No signature found on key certificate");
- return NULL;
- }
- eos = strstr(eos, "\n-----END SIGNATURE-----\n");
- if (! eos) {
- log_warn(LD_DIR, "No end-of-signature found on key certificate");
- return NULL;
- }
- eos = strchr(eos+2, '\n');
- tor_assert(eos);
- ++eos;
- len = eos - s;
-
- if (len > MAX_CERT_SIZE) {
- log_warn(LD_DIR, "Certificate is far too big (at %lu bytes long); "
- "rejecting", (unsigned long)len);
- return NULL;
- }
-
- tokens = smartlist_new();
- area = memarea_new();
- if (tokenize_string(area,s, eos, tokens, dir_key_certificate_table, 0) < 0) {
- log_warn(LD_DIR, "Error tokenizing key certificate");
- goto err;
- }
- if (router_get_hash_impl(s, strlen(s), digest, "dir-key-certificate-version",
- "\ndir-key-certification", '\n', DIGEST_SHA1) < 0)
- goto err;
- tok = smartlist_get(tokens, 0);
- if (tok->tp != K_DIR_KEY_CERTIFICATE_VERSION || strcmp(tok->args[0], "3")) {
- log_warn(LD_DIR,
- "Key certificate does not begin with a recognized version (3).");
- goto err;
- }
-
- cert = tor_malloc_zero(sizeof(authority_cert_t));
- memcpy(cert->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
-
- tok = find_by_keyword(tokens, K_DIR_SIGNING_KEY);
- tor_assert(tok->key);
- cert->signing_key = tok->key;
- tok->key = NULL;
- if (crypto_pk_get_digest(cert->signing_key, cert->signing_key_digest))
- goto err;
-
- tok = find_by_keyword(tokens, K_DIR_IDENTITY_KEY);
- tor_assert(tok->key);
- cert->identity_key = tok->key;
- tok->key = NULL;
-
- tok = find_by_keyword(tokens, K_FINGERPRINT);
- tor_assert(tok->n_args);
- if (base16_decode(fp_declared, DIGEST_LEN, tok->args[0],
- strlen(tok->args[0])) != DIGEST_LEN) {
- log_warn(LD_DIR, "Couldn't decode key certificate fingerprint %s",
- escaped(tok->args[0]));
- goto err;
- }
-
- if (crypto_pk_get_digest(cert->identity_key,
- cert->cache_info.identity_digest))
- goto err;
-
- if (tor_memneq(cert->cache_info.identity_digest, fp_declared, DIGEST_LEN)) {
- log_warn(LD_DIR, "Digest of certificate key didn't match declared "
- "fingerprint");
- goto err;
- }
-
- tok = find_opt_by_keyword(tokens, K_DIR_ADDRESS);
- if (tok) {
- struct in_addr in;
- char *address = NULL;
- tor_assert(tok->n_args);
- /* XXX++ use some tor_addr parse function below instead. -RD */
- if (tor_addr_port_split(LOG_WARN, tok->args[0], &address,
- &cert->dir_port) < 0 ||
- tor_inet_aton(address, &in) == 0) {
- log_warn(LD_DIR, "Couldn't parse dir-address in certificate");
- tor_free(address);
- goto err;
- }
- cert->addr = ntohl(in.s_addr);
- tor_free(address);
- }
-
- tok = find_by_keyword(tokens, K_DIR_KEY_PUBLISHED);
- if (parse_iso_time(tok->args[0], &cert->cache_info.published_on) < 0) {
- goto err;
- }
- tok = find_by_keyword(tokens, K_DIR_KEY_EXPIRES);
- if (parse_iso_time(tok->args[0], &cert->expires) < 0) {
- goto err;
- }
-
- tok = smartlist_get(tokens, smartlist_len(tokens)-1);
- if (tok->tp != K_DIR_KEY_CERTIFICATION) {
- log_warn(LD_DIR, "Certificate didn't end with dir-key-certification.");
- goto err;
- }
-
- /* If we already have this cert, don't bother checking the signature. */
- old_cert = authority_cert_get_by_digests(
- cert->cache_info.identity_digest,
- cert->signing_key_digest);
- found = 0;
- if (old_cert) {
- /* XXXX We could just compare signed_descriptor_digest, but that wouldn't
- * buy us much. */
- if (old_cert->cache_info.signed_descriptor_len == len &&
- old_cert->cache_info.signed_descriptor_body &&
- tor_memeq(s, old_cert->cache_info.signed_descriptor_body, len)) {
- log_debug(LD_DIR, "We already checked the signature on this "
- "certificate; no need to do so again.");
- found = 1;
- }
- }
- if (!found) {
- if (check_signature_token(digest, DIGEST_LEN, tok, cert->identity_key, 0,
- "key certificate")) {
- goto err;
- }
-
- tok = find_by_keyword(tokens, K_DIR_KEY_CROSSCERT);
- if (check_signature_token(cert->cache_info.identity_digest,
- DIGEST_LEN,
- tok,
- cert->signing_key,
- CST_NO_CHECK_OBJTYPE,
- "key cross-certification")) {
- goto err;
- }
- }
-
- cert->cache_info.signed_descriptor_len = len;
- cert->cache_info.signed_descriptor_body = tor_malloc(len+1);
- memcpy(cert->cache_info.signed_descriptor_body, s, len);
- cert->cache_info.signed_descriptor_body[len] = 0;
- cert->cache_info.saved_location = SAVED_NOWHERE;
-
- if (end_of_string) {
- *end_of_string = eat_whitespace(eos);
- }
- SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
- smartlist_free(tokens);
- if (area) {
- DUMP_AREA(area, "authority cert");
- memarea_drop_all(area);
- }
- return cert;
- err:
- dump_desc(s_dup, "authority cert");
- authority_cert_free(cert);
- SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
- smartlist_free(tokens);
- if (area) {
- DUMP_AREA(area, "authority cert");
- memarea_drop_all(area);
- }
- return NULL;
-}
-
/** Helper: given a string <b>s</b>, return the start of the next router-status
* object (starting with "r " at the start of a line). If none is found,
* return the start of the directory footer, or the next directory signature.
@@ -3857,116 +3475,6 @@ find_all_exitpolicy(smartlist_t *s)
return out;
}
-/** Helper function for <b>router_get_hash_impl</b>: given <b>s</b>,
- * <b>s_len</b>, <b>start_str</b>, <b>end_str</b>, and <b>end_c</b> with the
- * same semantics as in that function, set *<b>start_out</b> (inclusive) and
- * *<b>end_out</b> (exclusive) to the boundaries of the string to be hashed.
- *
- * Return 0 on success and -1 on failure.
- */
-static int
-router_get_hash_impl_helper(const char *s, size_t s_len,
- const char *start_str,
- const char *end_str, char end_c,
- int log_severity,
- const char **start_out, const char **end_out)
-{
- const char *start, *end;
- start = tor_memstr(s, s_len, start_str);
- if (!start) {
- log_fn(log_severity,LD_DIR,
- "couldn't find start of hashed material \"%s\"",start_str);
- return -1;
- }
- if (start != s && *(start-1) != '\n') {
- log_fn(log_severity,LD_DIR,
- "first occurrence of \"%s\" is not at the start of a line",
- start_str);
- return -1;
- }
- end = tor_memstr(start+strlen(start_str),
- s_len - (start-s) - strlen(start_str), end_str);
- if (!end) {
- log_fn(log_severity,LD_DIR,
- "couldn't find end of hashed material \"%s\"",end_str);
- return -1;
- }
- end = memchr(end+strlen(end_str), end_c, s_len - (end-s) - strlen(end_str));
- if (!end) {
- log_fn(log_severity,LD_DIR,
- "couldn't find EOL");
- return -1;
- }
- ++end;
-
- *start_out = start;
- *end_out = end;
- return 0;
-}
-
-/** Compute the digest of the substring of <b>s</b> taken from the first
- * occurrence of <b>start_str</b> through the first instance of c after the
- * first subsequent occurrence of <b>end_str</b>; store the 20-byte or 32-byte
- * result in <b>digest</b>; return 0 on success.
- *
- * If no such substring exists, return -1.
- */
-static int
-router_get_hash_impl(const char *s, size_t s_len, char *digest,
- const char *start_str,
- const char *end_str, char end_c,
- digest_algorithm_t alg)
-{
- const char *start=NULL, *end=NULL;
- if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,LOG_WARN,
- &start,&end)<0)
- return -1;
-
- return router_compute_hash_final(digest, start, end-start, alg);
-}
-
-/** Compute the digest of the <b>len</b>-byte directory object at
- * <b>start</b>, using <b>alg</b>. Store the result in <b>digest</b>, which
- * must be long enough to hold it. */
-MOCK_IMPL(STATIC int,
-router_compute_hash_final,(char *digest,
- const char *start, size_t len,
- digest_algorithm_t alg))
-{
- if (alg == DIGEST_SHA1) {
- if (crypto_digest(digest, start, len) < 0) {
- log_warn(LD_BUG,"couldn't compute digest");
- return -1;
- }
- } else {
- if (crypto_digest256(digest, start, len, alg) < 0) {
- log_warn(LD_BUG,"couldn't compute digest");
- return -1;
- }
- }
-
- return 0;
-}
-
-/** As router_get_hash_impl, but compute all hashes. */
-static int
-router_get_hashes_impl(const char *s, size_t s_len, common_digests_t *digests,
- const char *start_str,
- const char *end_str, char end_c)
-{
- const char *start=NULL, *end=NULL;
- if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,LOG_WARN,
- &start,&end)<0)
- return -1;
-
- if (crypto_common_digests(digests, start, end-start)) {
- log_warn(LD_BUG,"couldn't compute digests");
- return -1;
- }
-
- return 0;
-}
-
/** Assuming that s starts with a microdesc, return the start of the
* *NEXT* one. Return NULL on "not found." */
static const char *
diff --git a/src/feature/dirparse/routerparse.h b/src/feature/dirparse/routerparse.h
index 6f1af4016..4aba62653 100644
--- a/src/feature/dirparse/routerparse.h
+++ b/src/feature/dirparse/routerparse.h
@@ -26,14 +26,7 @@ int router_get_networkstatus_v3_signed_boundaries(const char *s,
int router_get_networkstatus_v3_sha3_as_signed(uint8_t *digest_out,
const char *s);
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,
- const crypto_pk_t *private_key);
-int router_append_dirobj_signature(char *buf, size_t buf_len,
- const char *digest,
- size_t digest_len,
- crypto_pk_t *private_key);
+
int router_parse_list_from_string(const char **s, const char *eos,
smartlist_t *dest,
saved_location_t saved_location,
@@ -70,8 +63,6 @@ smartlist_t *microdescs_parse_from_string(const char *s, const char *eos,
saved_location_t where,
smartlist_t *invalid_digests_out);
-authority_cert_t *authority_cert_parse_from_string(const char *s,
- const char **end_of_string);
int rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
char *desc_id_out,
char **intro_points_encrypted_out,
@@ -105,12 +96,6 @@ STATIC routerstatus_t *routerstatus_parse_entry_from_string(
vote_routerstatus_t *vote_rs,
int consensus_method,
consensus_flavor_t flav);
-MOCK_DECL(STATIC int, router_compute_hash_final,(char *digest,
- const char *start, size_t len,
- digest_algorithm_t alg));
-MOCK_DECL(STATIC int, signed_digest_equals,
- (const uint8_t *d1, const uint8_t *d2, size_t len));
-
STATIC void summarize_protover_flags(protover_summary_flags_t *out,
const char *protocols,
const char *version);
diff --git a/src/feature/dirparse/sigcommon.c b/src/feature/dirparse/sigcommon.c
new file mode 100644
index 000000000..28e6ff56e
--- /dev/null
+++ b/src/feature/dirparse/sigcommon.c
@@ -0,0 +1,185 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file sigcommon.c
+ * \brief Shared hashing, signing, and signature-checking code for directory
+ * objects.
+ **/
+
+#define SIGCOMMON_PRIVATE
+
+#include "core/or/or.h"
+#include "feature/dirparse/parsecommon.h"
+#include "feature/dirparse/sigcommon.h"
+
+/** Helper function for <b>router_get_hash_impl</b>: given <b>s</b>,
+ * <b>s_len</b>, <b>start_str</b>, <b>end_str</b>, and <b>end_c</b> with the
+ * same semantics as in that function, set *<b>start_out</b> (inclusive) and
+ * *<b>end_out</b> (exclusive) to the boundaries of the string to be hashed.
+ *
+ * Return 0 on success and -1 on failure.
+ */
+int
+router_get_hash_impl_helper(const char *s, size_t s_len,
+ const char *start_str,
+ const char *end_str, char end_c,
+ int log_severity,
+ const char **start_out, const char **end_out)
+{
+ const char *start, *end;
+ start = tor_memstr(s, s_len, start_str);
+ if (!start) {
+ log_fn(log_severity,LD_DIR,
+ "couldn't find start of hashed material \"%s\"",start_str);
+ return -1;
+ }
+ if (start != s && *(start-1) != '\n') {
+ log_fn(log_severity,LD_DIR,
+ "first occurrence of \"%s\" is not at the start of a line",
+ start_str);
+ return -1;
+ }
+ end = tor_memstr(start+strlen(start_str),
+ s_len - (start-s) - strlen(start_str), end_str);
+ if (!end) {
+ log_fn(log_severity,LD_DIR,
+ "couldn't find end of hashed material \"%s\"",end_str);
+ return -1;
+ }
+ end = memchr(end+strlen(end_str), end_c, s_len - (end-s) - strlen(end_str));
+ if (!end) {
+ log_fn(log_severity,LD_DIR,
+ "couldn't find EOL");
+ return -1;
+ }
+ ++end;
+
+ *start_out = start;
+ *end_out = end;
+ return 0;
+}
+
+/** Compute the digest of the substring of <b>s</b> taken from the first
+ * occurrence of <b>start_str</b> through the first instance of c after the
+ * first subsequent occurrence of <b>end_str</b>; store the 20-byte or 32-byte
+ * result in <b>digest</b>; return 0 on success.
+ *
+ * If no such substring exists, return -1.
+ */
+int
+router_get_hash_impl(const char *s, size_t s_len, char *digest,
+ const char *start_str,
+ const char *end_str, char end_c,
+ digest_algorithm_t alg)
+{
+ const char *start=NULL, *end=NULL;
+ if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,LOG_WARN,
+ &start,&end)<0)
+ return -1;
+
+ return router_compute_hash_final(digest, start, end-start, alg);
+}
+
+/** Compute the digest of the <b>len</b>-byte directory object at
+ * <b>start</b>, using <b>alg</b>. Store the result in <b>digest</b>, which
+ * must be long enough to hold it. */
+MOCK_IMPL(STATIC int,
+router_compute_hash_final,(char *digest,
+ const char *start, size_t len,
+ digest_algorithm_t alg))
+{
+ if (alg == DIGEST_SHA1) {
+ if (crypto_digest(digest, start, len) < 0) {
+ log_warn(LD_BUG,"couldn't compute digest");
+ return -1;
+ }
+ } else {
+ if (crypto_digest256(digest, start, len, alg) < 0) {
+ log_warn(LD_BUG,"couldn't compute digest");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/** As router_get_hash_impl, but compute all hashes. */
+int
+router_get_hashes_impl(const char *s, size_t s_len, common_digests_t *digests,
+ const char *start_str,
+ const char *end_str, char end_c)
+{
+ const char *start=NULL, *end=NULL;
+ if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,LOG_WARN,
+ &start,&end)<0)
+ return -1;
+
+ if (crypto_common_digests(digests, start, end-start)) {
+ log_warn(LD_BUG,"couldn't compute digests");
+ return -1;
+ }
+
+ return 0;
+}
+
+MOCK_IMPL(STATIC int,
+signed_digest_equals, (const uint8_t *d1, const uint8_t *d2, size_t len))
+{
+ return tor_memeq(d1, d2, len);
+}
+
+/** Check whether the object body of the token in <b>tok</b> has a good
+ * signature for <b>digest</b> using key <b>pkey</b>.
+ * If <b>CST_NO_CHECK_OBJTYPE</b> is set, do not check
+ * the object type of the signature object. Use <b>doctype</b> as the type of
+ * the document when generating log messages. Return 0 on success, negative
+ * on failure.
+ */
+int
+check_signature_token(const char *digest,
+ ssize_t digest_len,
+ directory_token_t *tok,
+ crypto_pk_t *pkey,
+ int flags,
+ const char *doctype)
+{
+ char *signed_digest;
+ size_t keysize;
+ const int check_objtype = ! (flags & CST_NO_CHECK_OBJTYPE);
+
+ tor_assert(pkey);
+ tor_assert(tok);
+ tor_assert(digest);
+ tor_assert(doctype);
+
+ if (check_objtype) {
+ if (strcmp(tok->object_type, "SIGNATURE")) {
+ log_warn(LD_DIR, "Bad object type on %s signature", doctype);
+ return -1;
+ }
+ }
+
+ keysize = crypto_pk_keysize(pkey);
+ signed_digest = tor_malloc(keysize);
+ if (crypto_pk_public_checksig(pkey, signed_digest, keysize,
+ tok->object_body, tok->object_size)
+ < digest_len) {
+ log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype);
+ tor_free(signed_digest);
+ return -1;
+ }
+ // log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
+ // hex_str(signed_digest,4));
+ if (! signed_digest_equals((const uint8_t *)digest,
+ (const uint8_t *)signed_digest, digest_len)) {
+ log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
+ tor_free(signed_digest);
+ return -1;
+ }
+ tor_free(signed_digest);
+ return 0;
+}
diff --git a/src/feature/dirparse/sigcommon.h b/src/feature/dirparse/sigcommon.h
new file mode 100644
index 000000000..5f25817cd
--- /dev/null
+++ b/src/feature/dirparse/sigcommon.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file sigcommon.h
+ * \brief Header file for sigcommon.c.
+ **/
+
+#ifndef TOR_SIGCOMMON_H
+#define TOR_SIGCOMMON_H
+
+/* TODO: Rename all of these functions */
+int router_get_hash_impl(const char *s, size_t s_len, char *digest,
+ const char *start_str, const char *end_str,
+ char end_char,
+ digest_algorithm_t alg);
+
+#define CST_NO_CHECK_OBJTYPE (1<<0)
+struct directory_token_t;
+int check_signature_token(const char *digest,
+ ssize_t digest_len,
+ struct directory_token_t *tok,
+ crypto_pk_t *pkey,
+ int flags,
+ const char *doctype);
+
+int router_get_hash_impl_helper(const char *s, size_t s_len,
+ const char *start_str,
+ const char *end_str, char end_c,
+ int log_severity,
+ const char **start_out, const char **end_out);
+int router_get_hashes_impl(const char *s, size_t s_len,
+ common_digests_t *digests,
+ const char *start_str, const char *end_str,
+ char end_char);
+
+#ifdef SIGCOMMON_PRIVATE
+MOCK_DECL(STATIC int, signed_digest_equals,
+ (const uint8_t *d1, const uint8_t *d2, size_t len));
+MOCK_DECL(STATIC int, router_compute_hash_final,(char *digest,
+ const char *start, size_t len,
+ digest_algorithm_t alg));
+#endif
+
+#endif /* !defined(TOR_SIGCOMMON_H) */
diff --git a/src/feature/dirparse/signing.c b/src/feature/dirparse/signing.c
new file mode 100644
index 000000000..8d6a40605
--- /dev/null
+++ b/src/feature/dirparse/signing.c
@@ -0,0 +1,98 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file signing.c
+ * \brief Code to sign directory objects.
+ **/
+
+#include "core/or/or.h"
+#include "feature/dirparse/signing.h"
+
+/** Helper: used to generate signatures for routers, directories and
+ * 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.
+ */
+char *
+router_get_dirobj_signature(const char *digest,
+ size_t digest_len,
+ const 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);
+ siglen = crypto_pk_private_sign(private_key, signature, keysize,
+ digest, digest_len);
+ if (siglen < 0) {
+ log_warn(LD_BUG,"Couldn't sign digest.");
+ goto err;
+ }
+
+ /* 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);
+ if (base64_encode(buf+i, buf_len-i, signature, siglen,
+ BASE64_ENCODE_MULTILINE) < 0) {
+ log_warn(LD_BUG,"couldn't base64-encode signature");
+ goto err;
+ }
+
+ if (strlcat(buf, "-----END SIGNATURE-----\n", buf_len) >= buf_len)
+ goto truncated;
+
+ tor_free(signature);
+ return buf;
+
+ truncated:
+ log_warn(LD_BUG,"tried to exceed string length.");
+ err:
+ tor_free(signature);
+ 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 a 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);
+ tor_free(sig);
+ return 0;
+}
diff --git a/src/feature/dirparse/signing.h b/src/feature/dirparse/signing.h
new file mode 100644
index 000000000..2b547a185
--- /dev/null
+++ b/src/feature/dirparse/signing.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file signing.h
+ * \brief Header file for signing.c.
+ **/
+
+#ifndef TOR_SIGNING_H
+#define TOR_SIGNING_H
+
+#define DIROBJ_MAX_SIG_LEN 256
+char *router_get_dirobj_signature(const char *digest,
+ size_t digest_len,
+ const crypto_pk_t *private_key);
+int router_append_dirobj_signature(char *buf, size_t buf_len,
+ const char *digest,
+ size_t digest_len,
+ crypto_pk_t *private_key);
+#endif
diff --git a/src/feature/dirparse/unparseable.h b/src/feature/dirparse/unparseable.h
index 831ab6777..2e48c6a9a 100644
--- a/src/feature/dirparse/unparseable.h
+++ b/src/feature/dirparse/unparseable.h
@@ -18,6 +18,18 @@ MOCK_DECL(void,dump_desc,(const char *desc, const char *type));
void dump_desc_fifo_cleanup(void);
void dump_desc_init(void);
+#undef DEBUG_AREA_ALLOC
+#ifdef DEBUG_AREA_ALLOC
+#define DUMP_AREA(a,name) STMT_BEGIN \
+ size_t alloc=0, used=0; \
+ memarea_get_stats((a),&alloc,&used); \
+ log_debug(LD_MM, "Area for %s has %lu allocated; using %lu.", \
+ name, (unsigned long)alloc, (unsigned long)used); \
+ STMT_END
+#else /* !(defined(DEBUG_AREA_ALLOC)) */
+#define DUMP_AREA(a,name) STMT_NIL
+#endif /* defined(DEBUG_AREA_ALLOC) */
+
#ifdef UNPARSEABLE_PRIVATE
/*
diff --git a/src/feature/nodelist/authcert.c b/src/feature/nodelist/authcert.c
index 1d2377016..b111422d0 100644
--- a/src/feature/nodelist/authcert.c
+++ b/src/feature/nodelist/authcert.c
@@ -28,7 +28,7 @@
#include "feature/dirclient/dlstatus.h"
#include "feature/dircommon/directory.h"
#include "feature/dircommon/fp_pair.h"
-#include "feature/dirparse/routerparse.h"
+#include "feature/dirparse/authcert_parse.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/dirlist.h"
#include "feature/nodelist/networkstatus.h"
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index 318cb41ec..4afcddc67 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -21,7 +21,9 @@
#include "feature/dircache/dirserv.h"
#include "feature/dirclient/dirclient.h"
#include "feature/dircommon/directory.h"
+#include "feature/dirparse/authcert_parse.h"
#include "feature/dirparse/routerparse.h"
+#include "feature/dirparse/signing.h"
#include "feature/hibernate/hibernate.h"
#include "feature/keymgt/loadkey.h"
#include "feature/nodelist/authcert.h"
diff --git a/src/feature/rend/rendcommon.c b/src/feature/rend/rendcommon.c
index 57d753fe4..2c28437b2 100644
--- a/src/feature/rend/rendcommon.c
+++ b/src/feature/rend/rendcommon.c
@@ -31,6 +31,7 @@
#include "feature/relay/router.h"
#include "feature/nodelist/routerlist.h"
#include "feature/dirparse/routerparse.h"
+#include "feature/dirparse/signing.h"
#include "core/or/cpath_build_state_st.h"
#include "core/or/crypt_path_st.h"
diff --git a/src/test/fuzz/fuzz_consensus.c b/src/test/fuzz/fuzz_consensus.c
index 1b3f01986..64507c67e 100644
--- a/src/test/fuzz/fuzz_consensus.c
+++ b/src/test/fuzz/fuzz_consensus.c
@@ -1,8 +1,9 @@
/* Copyright (c) 2016-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define ROUTERPARSE_PRIVATE
+#define SIGCOMMON_PRIVATE
#include "core/or/or.h"
#include "feature/dirparse/routerparse.h"
+#include "feature/dirparse/sigcommon.h"
#include "feature/dirparse/unparseable.h"
#include "feature/nodelist/networkstatus.h"
#include "lib/crypt_ops/crypto_ed25519.h"
diff --git a/src/test/fuzz/fuzz_descriptor.c b/src/test/fuzz/fuzz_descriptor.c
index 8087e1639..342011371 100644
--- a/src/test/fuzz/fuzz_descriptor.c
+++ b/src/test/fuzz/fuzz_descriptor.c
@@ -1,8 +1,9 @@
/* Copyright (c) 2016-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define ROUTERPARSE_PRIVATE
+#define SIGCOMMON_PRIVATE
#include "core/or/or.h"
#include "feature/dirparse/routerparse.h"
+#include "feature/dirparse/sigcommon.h"
#include "feature/dirparse/unparseable.h"
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/torcert.h"
diff --git a/src/test/fuzz/fuzz_extrainfo.c b/src/test/fuzz/fuzz_extrainfo.c
index 3ec2baf1e..da0fe8083 100644
--- a/src/test/fuzz/fuzz_extrainfo.c
+++ b/src/test/fuzz/fuzz_extrainfo.c
@@ -1,8 +1,9 @@
/* Copyright (c) 2016-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define ROUTERPARSE_PRIVATE
+#define SIGCOMMON_PRIVATE
#include "core/or/or.h"
#include "feature/dirparse/routerparse.h"
+#include "feature/dirparse/sigcommon.h"
#include "feature/dirparse/unparseable.h"
#include "feature/nodelist/routerlist.h"
#include "feature/relay/routerkeys.h"
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 9c189ba6b..23a1d1ba4 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -52,6 +52,7 @@
#include "feature/nodelist/nickname.h"
#include "feature/nodelist/node_select.h"
#include "feature/nodelist/routerlist.h"
+#include "feature/dirparse/authcert_parse.h"
#include "feature/dirparse/routerparse.h"
#include "feature/dirparse/unparseable.h"
#include "feature/nodelist/routerset.h"
diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c
index e65e2b011..5a9659ad4 100644
--- a/src/test/test_dir_common.c
+++ b/src/test/test_dir_common.c
@@ -10,6 +10,7 @@
#include "feature/dirauth/dirvote.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerlist.h"
+#include "feature/dirparse/authcert_parse.h"
#include "test/test_dir_common.h"
#include "feature/dircommon/voting_schedule.h"
diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c
index 7deed61e7..7cae45f13 100644
--- a/src/test/test_dir_handle_get.c
+++ b/src/test/test_dir_handle_get.c
@@ -29,6 +29,7 @@
#include "test/test_helpers.h"
#include "feature/nodelist/nodelist.h"
#include "feature/client/entrynodes.h"
+#include "feature/dirparse/authcert_parse.h"
#include "feature/dirparse/routerparse.h"
#include "feature/nodelist/networkstatus.h"
#include "core/proto/proto_http.h"
diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c
index a76f5c37d..d4606c227 100644
--- a/src/test/test_routerlist.c
+++ b/src/test/test_routerlist.c
@@ -33,6 +33,7 @@
#include "feature/nodelist/node_select.h"
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/routerset.h"
+#include "feature/dirparse/authcert_parse.h"
#include "feature/dirparse/routerparse.h"
#include "feature/dirauth/shared_random.h"
#include "app/config/statefile.h"
diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c
index 4dc017f33..397a4ceb5 100644
--- a/src/test/test_shared_random.c
+++ b/src/test/test_shared_random.c
@@ -19,6 +19,7 @@
#include "feature/relay/routerkeys.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/dirlist.h"
+#include "feature/dirparse/authcert_parse.h"
#include "feature/dirparse/routerparse.h"
#include "feature/hs_common/shared_random_client.h"
#include "feature/dircommon/voting_schedule.h"
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits