aboutsummaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2014-09-30 23:36:47 -0400
committerNick Mathewson <nickm@torproject.org>2015-05-28 10:40:56 -0400
commitfe5d2477aabbf06c940c33a266d6ebb3a7b19fe1 (patch)
tree6b1ac0df25a95b8c29b44a3ccdd9b9a32a8198d7 /src/or
parent818e6f939d4bd241e762970da4c6360858993cd5 (diff)
downloadtor-fe5d2477aabbf06c940c33a266d6ebb3a7b19fe1.tar.gz
tor-fe5d2477aabbf06c940c33a266d6ebb3a7b19fe1.zip
Implement ed25519-signed descriptors
Now that we have ed25519 keys, we can sign descriptors with them and check those signatures as documented in proposal 220.
Diffstat (limited to 'src/or')
-rw-r--r--src/or/or.h2
-rw-r--r--src/or/router.c61
-rw-r--r--src/or/router.h3
-rw-r--r--src/or/routerkeys.c2
-rw-r--r--src/or/routerlist.c3
-rw-r--r--src/or/routerparse.c91
-rw-r--r--src/or/routerparse.h2
-rw-r--r--src/or/torcert.c10
-rw-r--r--src/or/torcert.h2
9 files changed, 169 insertions, 7 deletions
diff --git a/src/or/or.h b/src/or/or.h
index 2044e844c3..437183e727 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2021,6 +2021,8 @@ typedef struct {
crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */
/** Public curve25519 key for onions */
curve25519_public_key_t *onion_curve25519_pkey;
+ /** Certificate for ed25519 signing key */
+ struct tor_cert_st *signing_key_cert;
char *platform; /**< What software/operating system is this OR using? */
diff --git a/src/or/router.c b/src/or/router.c
index 135561381f..6b2a238140 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -30,6 +30,7 @@
#include "routerlist.h"
#include "routerparse.h"
#include "statefile.h"
+#include "torcert.h"
#include "transports.h"
#include "routerset.h"
@@ -1881,6 +1882,8 @@ router_rebuild_descriptor(int force)
routerinfo_free(ri);
return -1;
}
+ ri->signing_key_cert = tor_cert_dup(get_master_signing_key_cert());
+
get_platform_str(platform, sizeof(platform));
ri->platform = tor_strdup(platform);
@@ -1995,8 +1998,9 @@ router_rebuild_descriptor(int force)
/* ri was allocated with tor_malloc_zero, so there is no need to
* zero ri->cache_info.extra_info_digest here. */
}
- if (! (ri->cache_info.signed_descriptor_body = router_dump_router_to_string(
- ri, get_server_identity_key()))) {
+ if (! (ri->cache_info.signed_descriptor_body =
+ router_dump_router_to_string(ri, get_server_identity_key(),
+ get_master_signing_keypair())) ) {
log_warn(LD_BUG, "Couldn't generate router descriptor.");
routerinfo_free(ri);
extrainfo_free(ei);
@@ -2302,12 +2306,13 @@ get_platform_str(char *platform, size_t len)
*/
char *
router_dump_router_to_string(routerinfo_t *router,
- crypto_pk_t *ident_key)
+ crypto_pk_t *ident_key,
+ const ed25519_keypair_t *signing_keypair)
{
char *address = NULL;
char *onion_pkey = NULL; /* Onion key, PEM-encoded. */
char *identity_pkey = NULL; /* Identity key, PEM-encoded. */
- char digest[DIGEST_LEN];
+ char digest[DIGEST256_LEN];
char published[ISO_TIME_LEN+1];
char fingerprint[FINGERPRINT_LEN+1];
int has_extra_info_digest;
@@ -2318,6 +2323,8 @@ router_dump_router_to_string(routerinfo_t *router,
const or_options_t *options = get_options();
smartlist_t *chunks = NULL;
char *output = NULL;
+ const int emit_ed_sigs = signing_keypair && router->signing_key_cert;
+ char *ed_cert_line = NULL;
/* Make sure the identity key matches the one in the routerinfo. */
if (!crypto_pk_eq_keys(ident_key, router->identity_pkey)) {
@@ -2325,6 +2332,15 @@ router_dump_router_to_string(routerinfo_t *router,
"match router's public key!");
goto err;
}
+ if (emit_ed_sigs) {
+ if (!router->signing_key_cert->signing_key_included ||
+ !ed25519_pubkey_eq(&router->signing_key_cert->signed_key,
+ &signing_keypair->pubkey)) {
+ log_warn(LD_BUG, "Tried to sign a router descriptor with a mismatched "
+ "ed25519 key chain");
+ goto err;
+ }
+ }
/* record our fingerprint, so we can include it in the descriptor */
if (crypto_pk_get_fingerprint(router->identity_pkey, fingerprint, 1)<0) {
@@ -2332,6 +2348,21 @@ router_dump_router_to_string(routerinfo_t *router,
goto err;
}
+ if (emit_ed_sigs) {
+ /* Encode ed25519 signing cert */
+ char ed_cert_base64[256];
+ if (base64_encode(ed_cert_base64, sizeof(ed_cert_base64),
+ (const char*)router->signing_key_cert->encoded,
+ router->signing_key_cert->encoded_len) < 0) {
+ log_err(LD_BUG,"Couldn't base64-encode signing key certificate!");
+ goto err;
+ }
+ tor_asprintf(&ed_cert_line, "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "%s"
+ "-----END ED25519 CERT-----\n", ed_cert_base64);
+ }
+
/* PEM-encode the onion key */
if (crypto_pk_write_public_key_to_string(router->onion_pkey,
&onion_pkey,&onion_pkeylen)<0) {
@@ -2385,6 +2416,7 @@ router_dump_router_to_string(routerinfo_t *router,
smartlist_add_asprintf(chunks,
"router %s %s %d 0 %d\n"
"%s"
+ "%s"
"platform %s\n"
"protocols Link 1 2 Circuit 1\n"
"published %s\n"
@@ -2399,6 +2431,7 @@ router_dump_router_to_string(routerinfo_t *router,
address,
router->or_port,
decide_to_advertise_dirport(options, router->dir_port),
+ ed_cert_line ? ed_cert_line : "",
extra_or_address ? extra_or_address : "",
router->platform,
published,
@@ -2455,7 +2488,24 @@ router_dump_router_to_string(routerinfo_t *router,
tor_free(p6);
}
- /* Sign the descriptor */
+ /* Sign the descriptor with Ed25519 */
+ if (emit_ed_sigs) {
+ smartlist_add(chunks, tor_strdup("router-sig-ed25519 "));
+ crypto_digest_smartlist_prefix(digest, DIGEST256_LEN,
+ ED_DESC_SIGNATURE_PREFIX,
+ chunks, "", DIGEST_SHA256);
+ ed25519_signature_t sig;
+ char buf[ED25519_SIG_BASE64_LEN+1];
+ if (ed25519_sign(&sig, (const uint8_t*)digest, DIGEST256_LEN,
+ signing_keypair) < 0)
+ goto err;
+ if (ed25519_signature_to_base64(buf, &sig) < 0)
+ goto err;
+
+ smartlist_add_asprintf(chunks, "%s\n", buf);
+ }
+
+ /* Sign the descriptor with RSA */
smartlist_add(chunks, tor_strdup("router-signature\n"));
crypto_digest_smartlist(digest, DIGEST_LEN, chunks, "", DIGEST_SHA1);
@@ -2507,6 +2557,7 @@ router_dump_router_to_string(routerinfo_t *router,
tor_free(onion_pkey);
tor_free(identity_pkey);
tor_free(extra_or_address);
+ tor_free(ed_cert_line);
return output;
}
diff --git a/src/or/router.h b/src/or/router.h
index 8108ffb22f..c53a104ebc 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -91,7 +91,8 @@ int router_is_me(const routerinfo_t *router);
int router_pick_published_address(const or_options_t *options, uint32_t *addr);
int router_rebuild_descriptor(int force);
char *router_dump_router_to_string(routerinfo_t *router,
- crypto_pk_t *ident_key);
+ crypto_pk_t *ident_key,
+ const ed25519_keypair_t *signing_keypair);
char *router_dump_exit_policy_to_string(const routerinfo_t *router,
int include_ipv4,
int include_ipv6);
diff --git a/src/or/routerkeys.c b/src/or/routerkeys.c
index fb61c310bd..6609d89311 100644
--- a/src/or/routerkeys.c
+++ b/src/or/routerkeys.c
@@ -300,7 +300,7 @@ load_ed_keys(const or_options_t *options, time_t now)
(void) options;
id = ed_key_init_from_file(
- options_get_datadir_fname2(options, "keys", "ed25519_master_id"),
+ options_get_datadir_fname2(options, "keys", "ed25519_master_id"),
(INIT_ED_KEY_CREATE|INIT_ED_KEY_SPLIT|
INIT_ED_KEY_MISSING_SECRET_OK|
INIT_ED_KEY_EXTRA_STRONG),
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index f4f6200bbc..069f70d662 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -13,6 +13,7 @@
#define ROUTERLIST_PRIVATE
#include "or.h"
+#include "crypto_ed25519.h"
#include "circuitstats.h"
#include "config.h"
#include "connection.h"
@@ -38,6 +39,7 @@
#include "routerparse.h"
#include "routerset.h"
#include "../common/sandbox.h"
+#include "torcert.h"
// #define DEBUG_ROUTERLIST
/****************************************************************************/
@@ -2663,6 +2665,7 @@ routerinfo_free(routerinfo_t *router)
tor_free(router->onion_curve25519_pkey);
if (router->identity_pkey)
crypto_pk_free(router->identity_pkey);
+ tor_cert_free(router->signing_key_cert);
if (router->declared_family) {
SMARTLIST_FOREACH(router->declared_family, char *, s, tor_free(s));
smartlist_free(router->declared_family);
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 5a9626f0a2..dbd6fdd472 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -26,6 +26,8 @@
#include "rephist.h"
#include "routerparse.h"
#include "entrynodes.h"
+#include "torcert.h"
+
#undef log
#include <math.h>
@@ -83,6 +85,8 @@ typedef enum {
K_HIDDEN_SERVICE_DIR,
K_ALLOW_SINGLE_HOP_EXITS,
K_IPV6_POLICY,
+ K_ROUTER_SIG_ED25519,
+ K_IDENTITY_ED25519,
K_DIRREQ_END,
K_DIRREQ_V2_IPS,
@@ -293,6 +297,9 @@ static token_rule_t routerdesc_token_table[] = {
T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ),
T01("extra-info-digest", K_EXTRA_INFO_DIGEST, GE(1), NO_OBJ ),
T01("hidden-service-dir", K_HIDDEN_SERVICE_DIR, NO_ARGS, NO_OBJ ),
+ T01("identity-ed25519", K_IDENTITY_ED25519, NO_ARGS, NEED_OBJ ),
+ T01("router-sig-ed25519", K_ROUTER_SIG_ED25519, GE(1), NO_OBJ ),
+
T01("allow-single-hop-exits",K_ALLOW_SINGLE_HOP_EXITS, NO_ARGS, NO_OBJ ),
T01("family", K_FAMILY, ARGS, NO_OBJ ),
@@ -506,6 +513,10 @@ 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,
+ 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,
@@ -1302,6 +1313,86 @@ router_parse_entry_from_string(const char *s, const char *end,
tor_memdup(&k, sizeof(curve25519_public_key_t));
}
+ {
+ directory_token_t *ed_sig_tok, *ed_cert_tok;
+ ed_sig_tok = find_opt_by_keyword(tokens, K_ROUTER_SIG_ED25519);
+ ed_cert_tok = find_opt_by_keyword(tokens, K_IDENTITY_ED25519);
+ if (!ed_sig_tok != !ed_cert_tok) {
+ log_warn(LD_DIR, "Router descriptor with only partial ed25519 support");
+ goto err;
+ }
+ if (ed_sig_tok) {
+ tor_assert(ed_cert_tok);
+ if (ed_cert_tok != smartlist_get(tokens, 0) &&
+ ed_cert_tok != smartlist_get(tokens, 1)) {
+ log_warn(LD_DIR, "Ed25519 certificate in wrong position");
+ goto err;
+ }
+ if (ed_sig_tok != smartlist_get(tokens, smartlist_len(tokens)-2)) {
+ log_warn(LD_DIR, "Ed25519 signature in wrong position");
+ goto err;
+ }
+ if (strcmp(ed_cert_tok->object_type, "ED25519 CERT")) {
+ log_warn(LD_DIR, "Wrong object type on identity-ed25519 in decriptor");
+ goto err;
+ }
+
+ uint8_t d256[DIGEST256_LEN];
+ const char *signed_start, *signed_end;
+
+ tor_cert_t *cert = tor_cert_parse(
+ (const uint8_t*)ed_cert_tok->object_body,
+ ed_cert_tok->object_size);
+ if (! cert) {
+ log_warn(LD_DIR, "Couldn't parse ed25519 cert");
+ goto err;
+ }
+ router->signing_key_cert = cert;
+ if (cert->cert_type != CERT_TYPE_ID_SIGNING ||
+ ! cert->signing_key_included) {
+ log_warn(LD_DIR, "Invalid form for ed25519 cert");
+ goto err;
+ }
+
+ if (router_get_hash_impl_helper(s, end-s, "router ",
+ "\nrouter-sig-ed25519",
+ ' ', &signed_start, &signed_end) < 0) {
+ log_warn(LD_DIR, "Can't find ed25519-signed portion of descriptor");
+ goto err;
+ }
+ crypto_digest_t *d = crypto_digest256_new(DIGEST_SHA256);
+ crypto_digest_add_bytes(d, ED_DESC_SIGNATURE_PREFIX,
+ strlen(ED_DESC_SIGNATURE_PREFIX));
+ crypto_digest_add_bytes(d, signed_start, signed_end-signed_start);
+ crypto_digest_get_digest(d, (char*)d256, sizeof(d256));
+ crypto_digest_free(d);
+
+ ed25519_checkable_t check[2];
+ int check_ok[2];
+ if (tor_cert_get_checkable_sig(&check[0], cert, NULL) < 0) {
+ log_err(LD_BUG, "Couldn't create 'checkable' for cert.");
+ goto err;
+ }
+ if (ed25519_signature_from_base64(&check[1].signature,
+ ed_sig_tok->args[0])<0) {
+ log_warn(LD_DIR, "Couldn't decode ed25519 signature");
+ goto err;
+ }
+ check[1].pubkey = &cert->signed_key;
+ check[1].msg = d256;
+ check[1].len = DIGEST256_LEN;
+
+ if (ed25519_checksig_batch(check_ok, check, 2) < 0) {
+ log_warn(LD_DIR, "Incorrect ed25519 signatures");
+ goto err;
+ }
+ if (cert->valid_until < time(NULL)) {
+ log_warn(LD_DIR, "Expired ed25519 certificate in router descriptor");
+ goto err;
+ }
+ }
+ }
+
tok = find_by_keyword(tokens, K_SIGNING_KEY);
router->identity_pkey = tok->key;
tok->key = NULL; /* Prevent free */
diff --git a/src/or/routerparse.h b/src/or/routerparse.h
index fc21cb1041..52e53a833c 100644
--- a/src/or/routerparse.h
+++ b/src/or/routerparse.h
@@ -92,5 +92,7 @@ STATIC int routerstatus_parse_guardfraction(const char *guardfraction_str,
routerstatus_t *rs);
#endif
+#define ED_DESC_SIGNATURE_PREFIX "Tor router descriptor signature v1"
+
#endif
diff --git a/src/or/torcert.c b/src/or/torcert.c
index 478ec4d5ac..8fe9c12000 100644
--- a/src/or/torcert.c
+++ b/src/or/torcert.c
@@ -206,3 +206,13 @@ tor_cert_checksig(tor_cert_t *cert,
}
}
+/** Return a new copy of <b>cert</b> */
+tor_cert_t *
+tor_cert_dup(const tor_cert_t *cert)
+{
+ tor_cert_t *newcert = tor_memdup(cert, sizeof(tor_cert_t));
+ if (cert->encoded)
+ newcert->encoded = tor_memdup(cert->encoded, cert->encoded_len);
+ return newcert;
+}
+
diff --git a/src/or/torcert.h b/src/or/torcert.h
index 7e9c3f5b2d..644cbf812d 100644
--- a/src/or/torcert.h
+++ b/src/or/torcert.h
@@ -62,5 +62,7 @@ int tor_cert_get_checkable_sig(ed25519_checkable_t *checkable_out,
int tor_cert_checksig(tor_cert_t *cert,
const ed25519_public_key_t *pubkey, time_t now);
+tor_cert_t *tor_cert_dup(const tor_cert_t *cert);
+
#endif