Просмотр исходного кода

Merge branch 'bug10884_squashed'

Nick Mathewson 11 лет назад
Родитель
Сommit
273f536d72
11 измененных файлов с 235 добавлено и 33 удалено
  1. 5 0
      changes/bug10884
  2. 4 0
      doc/tor.1.txt
  3. 22 0
      src/common/crypto.c
  4. 1 0
      src/common/crypto.h
  5. 2 0
      src/or/main.c
  6. 62 33
      src/or/router.c
  7. 1 0
      src/or/router.h
  8. 1 0
      src/test/include.am
  9. 2 0
      src/test/test.c
  10. 51 0
      src/test/test_crypto.c
  11. 84 0
      src/test/test_routerkeys.c

+ 5 - 0
changes/bug10884

@@ -0,0 +1,5 @@
+  o Minor features:
+    - Bridges write the SHA1 digest of their identity key fingerprint to
+      notice-level logs and to hashed-fingerprint, so that bridge
+      operators can look up their bridge in Globe and similar tools.
+

+ 4 - 0
doc/tor.1.txt

@@ -2305,6 +2305,10 @@ __DataDirectory__**/keys/***::
 __DataDirectory__**/fingerprint**::
     Only used by servers. Holds the fingerprint of the server's identity key.
 
+__DataDirectory__**/hashed-fingerprint**::
+    Only used by bridges. Holds the hashed fingerprint of the bridge's
+    identity key. (That is, the hash of the hash of the identity key.)
+
 __DataDirectory__**/approved-routers**::
     Only for naming authoritative directory servers (see
     **NamingAuthoritativeDirectory**). This file lists nickname to identity

+ 22 - 0
src/common/crypto.c

@@ -1374,6 +1374,28 @@ crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space)
   return 0;
 }
 
+/** Given a private or public key <b>pk</b>, put a hashed fingerprint of
+ * the public key into <b>fp_out</b> (must have at least FINGERPRINT_LEN+1
+ * bytes of space).  Return 0 on success, -1 on failure.
+ *
+ * Hashed fingerprints are computed as the SHA1 digest of the SHA1 digest
+ * of the ASN.1 encoding of the public key, converted to hexadecimal, in
+ * upper case.
+ */
+int
+crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out)
+{
+  char digest[DIGEST_LEN], hashed_digest[DIGEST_LEN];
+  if (crypto_pk_get_digest(pk, digest)) {
+    return -1;
+  }
+  if (crypto_digest(hashed_digest, digest, DIGEST_LEN)) {
+    return -1;
+  }
+  base16_encode(fp_out, FINGERPRINT_LEN + 1, hashed_digest, DIGEST_LEN);
+  return 0;
+}
+
 /* symmetric crypto */
 
 /** Return a pointer to the key set for the cipher in <b>env</b>.

+ 1 - 0
src/common/crypto.h

@@ -182,6 +182,7 @@ crypto_pk_t *crypto_pk_asn1_decode(const char *str, size_t len);
 int crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out);
 int crypto_pk_get_all_digests(crypto_pk_t *pk, digests_t *digests_out);
 int crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out,int add_space);
+int crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out);
 
 /* symmetric crypto */
 const char *crypto_cipher_get_key(crypto_cipher_t *env);

+ 2 - 0
src/or/main.c

@@ -2764,6 +2764,8 @@ sandbox_init_filter(void)
         get_datadir_fname2("keys", "secret_id_key.tmp"), 1,
         get_datadir_fname("fingerprint"), 1,
         get_datadir_fname("fingerprint.tmp"), 1,
+        get_datadir_fname("hashed-fingerprint"), 1,
+        get_datadir_fname("hashed-fingerprint.tmp"), 1,
         get_datadir_fname("cached-consensus"), 1,
         get_datadir_fname("cached-consensus.tmp"), 1,
         "/etc/resolv.conf", 0,

+ 62 - 33
src/or/router.c

@@ -684,6 +684,63 @@ router_initialize_tls_context(void)
                               (unsigned int)lifetime);
 }
 
+/** Compute fingerprint (or hashed fingerprint if hashed is 1) and write
+ * it to 'fingerprint' (or 'hashed-fingerprint'). Return 0 on success, or
+ * -1 if Tor should die,
+ */
+STATIC int
+router_write_fingerprint(int hashed)
+{
+  char *keydir = NULL, *cp = NULL;
+  const char *fname = hashed ? "hashed-fingerprint" :
+                               "fingerprint";
+  char fingerprint[FINGERPRINT_LEN+1];
+  const or_options_t *options = get_options();
+  char *fingerprint_line = NULL;
+  int result = -1;
+
+  keydir = get_datadir_fname(fname);
+  log_info(LD_GENERAL,"Dumping %sfingerprint to \"%s\"...",
+           hashed ? "hashed " : "", keydir);
+  if (!hashed) {
+    if (crypto_pk_get_fingerprint(get_server_identity_key(),
+                                  fingerprint, 0) < 0) {
+      log_err(LD_GENERAL,"Error computing fingerprint");
+      goto done;
+    }
+  } else {
+    if (crypto_pk_get_hashed_fingerprint(get_server_identity_key(),
+                                         fingerprint) < 0) {
+      log_err(LD_GENERAL,"Error computing hashed fingerprint");
+      goto done;
+    }
+  }
+
+  tor_asprintf(&fingerprint_line, "%s %s\n", options->Nickname, fingerprint);
+
+  /* Check whether we need to write the (hashed-)fingerprint file. */
+
+  cp = read_file_to_str(keydir, RFTS_IGNORE_MISSING, NULL);
+  if (!cp || strcmp(cp, fingerprint_line)) {
+    if (write_str_to_file(keydir, fingerprint_line, 0)) {
+      log_err(LD_FS, "Error writing %sfingerprint line to file",
+              hashed ? "hashed " : "");
+      goto done;
+    }
+  }
+
+  log_notice(LD_GENERAL, "Your Tor %s identity key fingerprint is '%s %s'",
+             hashed ? "bridge's hashed" : "server's", options->Nickname,
+             fingerprint);
+
+  result = 0;
+ done:
+  tor_free(cp);
+  tor_free(keydir);
+  tor_free(fingerprint_line);
+  return result;
+}
+
 /** Initialize all OR private keys, and the TLS context, as necessary.
  * On OPs, this only initializes the tls context. Return 0 on success,
  * or -1 if Tor should die.
@@ -692,14 +749,10 @@ int
 init_keys(void)
 {
   char *keydir;
-  char fingerprint[FINGERPRINT_LEN+1];
-  /*nickname<space>fp\n\0 */
-  char fingerprint_line[MAX_NICKNAME_LEN+FINGERPRINT_LEN+3];
   const char *mydesc;
   crypto_pk_t *prkey;
   char digest[DIGEST_LEN];
   char v3_digest[DIGEST_LEN];
-  char *cp;
   const or_options_t *options = get_options();
   dirinfo_type_t type;
   time_t now = time(NULL);
@@ -889,40 +942,16 @@ init_keys(void)
     }
   }
 
-  /* 5. Dump fingerprint to 'fingerprint' */
-  keydir = get_datadir_fname("fingerprint");
-  log_info(LD_GENERAL,"Dumping fingerprint to \"%s\"...",keydir);
-  if (crypto_pk_get_fingerprint(get_server_identity_key(),
-                                fingerprint, 0) < 0) {
-    log_err(LD_GENERAL,"Error computing fingerprint");
-    tor_free(keydir);
+  /* 5. Dump fingerprint and possibly hashed fingerprint to files. */
+  if (router_write_fingerprint(0)) {
+    log_err(LD_FS, "Error writing fingerprint to file");
     return -1;
   }
-  tor_assert(strlen(options->Nickname) <= MAX_NICKNAME_LEN);
-  if (tor_snprintf(fingerprint_line, sizeof(fingerprint_line),
-                   "%s %s\n",options->Nickname, fingerprint) < 0) {
-    log_err(LD_GENERAL,"Error writing fingerprint line");
-    tor_free(keydir);
+  if (!public_server_mode(options) && router_write_fingerprint(1)) {
+    log_err(LD_FS, "Error writing hashed fingerprint to file");
     return -1;
   }
-  /* Check whether we need to write the fingerprint file. */
-  cp = NULL;
-  if (file_status(keydir) == FN_FILE)
-    cp = read_file_to_str(keydir, 0, NULL);
-  if (!cp || strcmp(cp, fingerprint_line)) {
-    if (write_str_to_file(keydir, fingerprint_line, 0)) {
-      log_err(LD_FS, "Error writing fingerprint line to file");
-      tor_free(keydir);
-      tor_free(cp);
-      return -1;
-    }
-  }
-  tor_free(cp);
-  tor_free(keydir);
 
-  log_notice(LD_GENERAL,
-      "Your Tor server's identity key fingerprint is '%s %s'",
-      options->Nickname, fingerprint);
   if (!authdir_mode(options))
     return 0;
   /* 6. [authdirserver only] load approved-routers file */

+ 1 - 0
src/or/router.h

@@ -147,6 +147,7 @@ smartlist_t *router_get_all_orports(const routerinfo_t *ri);
 #ifdef ROUTER_PRIVATE
 /* Used only by router.c and test.c */
 STATIC void get_platform_str(char *platform, size_t len);
+STATIC int router_write_fingerprint(int hashed);
 #endif
 
 #endif

+ 1 - 0
src/test/include.am

@@ -35,6 +35,7 @@ src_test_test_SOURCES = \
 	src/test/test_options.c \
 	src/test/test_pt.c \
 	src/test/test_replay.c \
+	src/test/test_routerkeys.c \
 	src/test/test_socks.c \
 	src/test/test_util.c \
 	src/test/test_config.c \

+ 2 - 0
src/test/test.c

@@ -1629,6 +1629,7 @@ extern struct testcase_t logging_tests[];
 extern struct testcase_t backtrace_tests[];
 extern struct testcase_t hs_tests[];
 extern struct testcase_t nodelist_tests[];
+extern struct testcase_t routerkeys_tests[];
 
 static struct testgroup_t testgroups[] = {
   { "", test_array },
@@ -1654,6 +1655,7 @@ static struct testgroup_t testgroups[] = {
   { "control/", controller_event_tests },
   { "hs/", hs_tests },
   { "nodelist/", nodelist_tests },
+  { "routerkeys/", routerkeys_tests },
   END_OF_GROUPS
 };
 

+ 51 - 0
src/test/test_crypto.c

@@ -509,6 +509,56 @@ test_crypto_pk(void)
   tor_free(encoded);
 }
 
+static void
+test_crypto_pk_fingerprints(void *arg)
+{
+  crypto_pk_t *pk = NULL;
+  char encoded[512];
+  char d[DIGEST_LEN], d2[DIGEST_LEN];
+  char fingerprint[FINGERPRINT_LEN+1];
+  int n;
+  unsigned i;
+  char *mem_op_hex_tmp=NULL;
+
+  (void)arg;
+
+  pk = pk_generate(1);
+  tt_assert(pk);
+  n = crypto_pk_asn1_encode(pk, encoded, sizeof(encoded));
+  tt_int_op(n, >, 0);
+  tt_int_op(n, >, 128);
+  tt_int_op(n, <, 256);
+
+  /* Is digest as expected? */
+  crypto_digest(d, encoded, n);
+  tt_int_op(0, ==, crypto_pk_get_digest(pk, d2));
+  test_memeq(d, d2, DIGEST_LEN);
+
+  /* Is fingerprint right? */
+  tt_int_op(0, ==, crypto_pk_get_fingerprint(pk, fingerprint, 0));
+  tt_int_op(strlen(fingerprint), ==, DIGEST_LEN * 2);
+  test_memeq_hex(d, fingerprint);
+
+  /* Are spaces right? */
+  tt_int_op(0, ==, crypto_pk_get_fingerprint(pk, fingerprint, 1));
+  for (i = 4; i < strlen(fingerprint); i += 5) {
+    tt_int_op(fingerprint[i], ==, ' ');
+  }
+  tor_strstrip(fingerprint, " ");
+  tt_int_op(strlen(fingerprint), ==, DIGEST_LEN * 2);
+  test_memeq_hex(d, fingerprint);
+
+  /* Now hash again and check crypto_pk_get_hashed_fingerprint. */
+  crypto_digest(d2, d, sizeof(d));
+  tt_int_op(0, ==, crypto_pk_get_hashed_fingerprint(pk, fingerprint));
+  tt_int_op(strlen(fingerprint), ==, DIGEST_LEN * 2);
+  test_memeq_hex(d2, fingerprint);
+
+ done:
+  crypto_pk_free(pk);
+  tor_free(mem_op_hex_tmp);
+}
+
 /** Sanity check for crypto pk digests  */
 static void
 test_crypto_digests(void)
@@ -1234,6 +1284,7 @@ struct testcase_t crypto_tests[] = {
   { "aes_EVP", test_crypto_aes, TT_FORK, &pass_data, (void*)"evp" },
   CRYPTO_LEGACY(sha),
   CRYPTO_LEGACY(pk),
+  { "pk_fingerprints", test_crypto_pk_fingerprints, TT_FORK, NULL, NULL },
   CRYPTO_LEGACY(digests),
   CRYPTO_LEGACY(dh),
   CRYPTO_LEGACY(s2k),

+ 84 - 0
src/test/test_routerkeys.c

@@ -0,0 +1,84 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#define ROUTER_PRIVATE
+#include "or.h"
+#include "config.h"
+#include "router.h"
+#include "util.h"
+#include "crypto.h"
+
+#include "test.h"
+
+static void
+test_routerkeys_write_fingerprint(void *arg)
+{
+  crypto_pk_t *key = pk_generate(2);
+  or_options_t *options = get_options_mutable();
+  const char *ddir = get_fname("write_fingerprint");
+  char *cp = NULL, *cp2 = NULL;
+  char fp[FINGERPRINT_LEN+1];
+
+  (void)arg;
+
+  tt_assert(key);
+
+  options->ORPort_set = 1; /* So that we can get the server ID key */
+  options->DataDirectory = tor_strdup(ddir);
+  options->Nickname = tor_strdup("haflinger");
+  set_server_identity_key(key);
+  set_client_identity_key(crypto_pk_dup_key(key));
+
+  check_private_dir(ddir, CPD_CREATE, NULL);
+  tt_int_op(crypto_pk_cmp_keys(get_server_identity_key(),key),==,0);
+
+  /* Write fingerprint file */
+  tt_int_op(0, ==, router_write_fingerprint(0));
+  cp = read_file_to_str(get_fname("write_fingerprint/fingerprint"),
+                        0, NULL);
+  crypto_pk_get_fingerprint(key, fp, 0);
+  tor_asprintf(&cp2, "haflinger %s\n", fp);
+  tt_str_op(cp, ==, cp2);
+  tor_free(cp);
+  tor_free(cp2);
+
+  /* Write hashed-fingerprint file */
+  tt_int_op(0, ==, router_write_fingerprint(1));
+  cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"),
+                        0, NULL);
+  crypto_pk_get_hashed_fingerprint(key, fp);
+  tor_asprintf(&cp2, "haflinger %s\n", fp);
+  tt_str_op(cp, ==, cp2);
+  tor_free(cp);
+  tor_free(cp2);
+
+  /* Replace outdated file */
+  write_str_to_file(get_fname("write_fingerprint/hashed-fingerprint"),
+                    "junk goes here", 0);
+  tt_int_op(0, ==, router_write_fingerprint(1));
+  cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"),
+                        0, NULL);
+  crypto_pk_get_hashed_fingerprint(key, fp);
+  tor_asprintf(&cp2, "haflinger %s\n", fp);
+  tt_str_op(cp, ==, cp2);
+  tor_free(cp);
+  tor_free(cp2);
+
+ done:
+  crypto_pk_free(key);
+  set_client_identity_key(NULL);
+  tor_free(cp);
+  tor_free(cp2);
+}
+
+#define TEST(name, flags)                                       \
+  { #name , test_routerkeys_ ## name, (flags), NULL, NULL }
+
+struct testcase_t routerkeys_tests[] = {
+  TEST(write_fingerprint, TT_FORK),
+  END_OF_TESTCASES
+};
+