mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 20:33:31 +01:00
Merge branch 'bug10884_squashed'
This commit is contained in:
commit
273f536d72
5
changes/bug10884
Normal file
5
changes/bug10884
Normal file
@ -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.
|
||||||
|
|
@ -2305,6 +2305,10 @@ __DataDirectory__**/keys/***::
|
|||||||
__DataDirectory__**/fingerprint**::
|
__DataDirectory__**/fingerprint**::
|
||||||
Only used by servers. Holds the fingerprint of the server's identity key.
|
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**::
|
__DataDirectory__**/approved-routers**::
|
||||||
Only for naming authoritative directory servers (see
|
Only for naming authoritative directory servers (see
|
||||||
**NamingAuthoritativeDirectory**). This file lists nickname to identity
|
**NamingAuthoritativeDirectory**). This file lists nickname to identity
|
||||||
|
@ -1374,6 +1374,28 @@ crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space)
|
|||||||
return 0;
|
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 */
|
/* symmetric crypto */
|
||||||
|
|
||||||
/** Return a pointer to the key set for the cipher in <b>env</b>.
|
/** Return a pointer to the key set for the cipher in <b>env</b>.
|
||||||
|
@ -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_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_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_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 */
|
/* symmetric crypto */
|
||||||
const char *crypto_cipher_get_key(crypto_cipher_t *env);
|
const char *crypto_cipher_get_key(crypto_cipher_t *env);
|
||||||
|
@ -2764,6 +2764,8 @@ sandbox_init_filter(void)
|
|||||||
get_datadir_fname2("keys", "secret_id_key.tmp"), 1,
|
get_datadir_fname2("keys", "secret_id_key.tmp"), 1,
|
||||||
get_datadir_fname("fingerprint"), 1,
|
get_datadir_fname("fingerprint"), 1,
|
||||||
get_datadir_fname("fingerprint.tmp"), 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"), 1,
|
||||||
get_datadir_fname("cached-consensus.tmp"), 1,
|
get_datadir_fname("cached-consensus.tmp"), 1,
|
||||||
"/etc/resolv.conf", 0,
|
"/etc/resolv.conf", 0,
|
||||||
|
@ -684,6 +684,63 @@ router_initialize_tls_context(void)
|
|||||||
(unsigned int)lifetime);
|
(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.
|
/** Initialize all OR private keys, and the TLS context, as necessary.
|
||||||
* On OPs, this only initializes the tls context. Return 0 on success,
|
* On OPs, this only initializes the tls context. Return 0 on success,
|
||||||
* or -1 if Tor should die.
|
* or -1 if Tor should die.
|
||||||
@ -692,14 +749,10 @@ int
|
|||||||
init_keys(void)
|
init_keys(void)
|
||||||
{
|
{
|
||||||
char *keydir;
|
char *keydir;
|
||||||
char fingerprint[FINGERPRINT_LEN+1];
|
|
||||||
/*nickname<space>fp\n\0 */
|
|
||||||
char fingerprint_line[MAX_NICKNAME_LEN+FINGERPRINT_LEN+3];
|
|
||||||
const char *mydesc;
|
const char *mydesc;
|
||||||
crypto_pk_t *prkey;
|
crypto_pk_t *prkey;
|
||||||
char digest[DIGEST_LEN];
|
char digest[DIGEST_LEN];
|
||||||
char v3_digest[DIGEST_LEN];
|
char v3_digest[DIGEST_LEN];
|
||||||
char *cp;
|
|
||||||
const or_options_t *options = get_options();
|
const or_options_t *options = get_options();
|
||||||
dirinfo_type_t type;
|
dirinfo_type_t type;
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
@ -889,40 +942,16 @@ init_keys(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 5. Dump fingerprint to 'fingerprint' */
|
/* 5. Dump fingerprint and possibly hashed fingerprint to files. */
|
||||||
keydir = get_datadir_fname("fingerprint");
|
if (router_write_fingerprint(0)) {
|
||||||
log_info(LD_GENERAL,"Dumping fingerprint to \"%s\"...",keydir);
|
log_err(LD_FS, "Error writing fingerprint to file");
|
||||||
if (crypto_pk_get_fingerprint(get_server_identity_key(),
|
|
||||||
fingerprint, 0) < 0) {
|
|
||||||
log_err(LD_GENERAL,"Error computing fingerprint");
|
|
||||||
tor_free(keydir);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
tor_assert(strlen(options->Nickname) <= MAX_NICKNAME_LEN);
|
if (!public_server_mode(options) && router_write_fingerprint(1)) {
|
||||||
if (tor_snprintf(fingerprint_line, sizeof(fingerprint_line),
|
log_err(LD_FS, "Error writing hashed fingerprint to file");
|
||||||
"%s %s\n",options->Nickname, fingerprint) < 0) {
|
|
||||||
log_err(LD_GENERAL,"Error writing fingerprint line");
|
|
||||||
tor_free(keydir);
|
|
||||||
return -1;
|
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))
|
if (!authdir_mode(options))
|
||||||
return 0;
|
return 0;
|
||||||
/* 6. [authdirserver only] load approved-routers file */
|
/* 6. [authdirserver only] load approved-routers file */
|
||||||
|
@ -147,6 +147,7 @@ smartlist_t *router_get_all_orports(const routerinfo_t *ri);
|
|||||||
#ifdef ROUTER_PRIVATE
|
#ifdef ROUTER_PRIVATE
|
||||||
/* Used only by router.c and test.c */
|
/* Used only by router.c and test.c */
|
||||||
STATIC void get_platform_str(char *platform, size_t len);
|
STATIC void get_platform_str(char *platform, size_t len);
|
||||||
|
STATIC int router_write_fingerprint(int hashed);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -35,6 +35,7 @@ src_test_test_SOURCES = \
|
|||||||
src/test/test_options.c \
|
src/test/test_options.c \
|
||||||
src/test/test_pt.c \
|
src/test/test_pt.c \
|
||||||
src/test/test_replay.c \
|
src/test/test_replay.c \
|
||||||
|
src/test/test_routerkeys.c \
|
||||||
src/test/test_socks.c \
|
src/test/test_socks.c \
|
||||||
src/test/test_util.c \
|
src/test/test_util.c \
|
||||||
src/test/test_config.c \
|
src/test/test_config.c \
|
||||||
|
@ -1629,6 +1629,7 @@ extern struct testcase_t logging_tests[];
|
|||||||
extern struct testcase_t backtrace_tests[];
|
extern struct testcase_t backtrace_tests[];
|
||||||
extern struct testcase_t hs_tests[];
|
extern struct testcase_t hs_tests[];
|
||||||
extern struct testcase_t nodelist_tests[];
|
extern struct testcase_t nodelist_tests[];
|
||||||
|
extern struct testcase_t routerkeys_tests[];
|
||||||
|
|
||||||
static struct testgroup_t testgroups[] = {
|
static struct testgroup_t testgroups[] = {
|
||||||
{ "", test_array },
|
{ "", test_array },
|
||||||
@ -1654,6 +1655,7 @@ static struct testgroup_t testgroups[] = {
|
|||||||
{ "control/", controller_event_tests },
|
{ "control/", controller_event_tests },
|
||||||
{ "hs/", hs_tests },
|
{ "hs/", hs_tests },
|
||||||
{ "nodelist/", nodelist_tests },
|
{ "nodelist/", nodelist_tests },
|
||||||
|
{ "routerkeys/", routerkeys_tests },
|
||||||
END_OF_GROUPS
|
END_OF_GROUPS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -509,6 +509,56 @@ test_crypto_pk(void)
|
|||||||
tor_free(encoded);
|
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 */
|
/** Sanity check for crypto pk digests */
|
||||||
static void
|
static void
|
||||||
test_crypto_digests(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" },
|
{ "aes_EVP", test_crypto_aes, TT_FORK, &pass_data, (void*)"evp" },
|
||||||
CRYPTO_LEGACY(sha),
|
CRYPTO_LEGACY(sha),
|
||||||
CRYPTO_LEGACY(pk),
|
CRYPTO_LEGACY(pk),
|
||||||
|
{ "pk_fingerprints", test_crypto_pk_fingerprints, TT_FORK, NULL, NULL },
|
||||||
CRYPTO_LEGACY(digests),
|
CRYPTO_LEGACY(digests),
|
||||||
CRYPTO_LEGACY(dh),
|
CRYPTO_LEGACY(dh),
|
||||||
CRYPTO_LEGACY(s2k),
|
CRYPTO_LEGACY(s2k),
|
||||||
|
84
src/test/test_routerkeys.c
Normal file
84
src/test/test_routerkeys.c
Normal file
@ -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
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user