[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