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.
This commit is contained in:
Nick Mathewson 2014-09-30 23:36:47 -04:00
parent 818e6f939d
commit fe5d2477aa
17 changed files with 370 additions and 14 deletions

View File

@ -1724,7 +1724,24 @@ crypto_digest_assign(crypto_digest_t *into,
* <b>out_len</b> must be \<= DIGEST256_LEN. */ * <b>out_len</b> must be \<= DIGEST256_LEN. */
void void
crypto_digest_smartlist(char *digest_out, size_t len_out, crypto_digest_smartlist(char *digest_out, size_t len_out,
const smartlist_t *lst, const char *append, const smartlist_t *lst,
const char *append,
digest_algorithm_t alg)
{
crypto_digest_smartlist_prefix(digest_out, len_out, NULL, lst, append, alg);
}
/** Given a list of strings in <b>lst</b>, set the <b>len_out</b>-byte digest
* at <b>digest_out</b> to the hash of the concatenation of: the
* optional string <b>prepend</b>, those strings,
* and the optional string <b>append</b>, computed with the algorithm
* <b>alg</b>.
* <b>out_len</b> must be \<= DIGEST256_LEN. */
void
crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
const char *prepend,
const smartlist_t *lst,
const char *append,
digest_algorithm_t alg) digest_algorithm_t alg)
{ {
crypto_digest_t *d; crypto_digest_t *d;
@ -1732,6 +1749,8 @@ crypto_digest_smartlist(char *digest_out, size_t len_out,
d = crypto_digest_new(); d = crypto_digest_new();
else else
d = crypto_digest256_new(alg); d = crypto_digest256_new(alg);
if (prepend)
crypto_digest_add_bytes(d, prepend, strlen(prepend));
SMARTLIST_FOREACH(lst, const char *, cp, SMARTLIST_FOREACH(lst, const char *, cp,
crypto_digest_add_bytes(d, cp, strlen(cp))); crypto_digest_add_bytes(d, cp, strlen(cp)));
if (append) if (append)
@ -2692,6 +2711,8 @@ base64_encode(char *dest, size_t destlen, const char *src, size_t srclen)
return -1; return -1;
if (destlen > SIZE_T_CEILING) if (destlen > SIZE_T_CEILING)
return -1; return -1;
if (destlen)
*dest = 0; /* Ensure we always initialize the buffer */
EVP_EncodeInit(&ctx); EVP_EncodeInit(&ctx);
EVP_EncodeUpdate(&ctx, (unsigned char*)dest, &len, EVP_EncodeUpdate(&ctx, (unsigned char*)dest, &len,
@ -2701,6 +2722,65 @@ base64_encode(char *dest, size_t destlen, const char *src, size_t srclen)
return ret; return ret;
} }
/** As base64_encode, but do not add any internal spaces or external padding
* to the output stream. */
int
base64_encode_nopad(char *dest, size_t destlen,
const uint8_t *src, size_t srclen)
{
int n = base64_encode(dest, destlen, (const char*) src, srclen);
if (n <= 0)
return n;
tor_assert((size_t)n < destlen && dest[n] == 0);
char *in, *out;
in = out = dest;
while (*in) {
if (*in == '=' || *in == '\n') {
++in;
} else {
*out++ = *in++;
}
}
*out = 0;
tor_assert(out - dest <= INT_MAX);
return (int)(out - dest);
}
/** As base64_decode, but do not require any padding on the input */
int
base64_decode_nopad(uint8_t *dest, size_t destlen,
const char *src, size_t srclen)
{
if (srclen > SIZE_T_CEILING - 4)
return -1;
char *buf = tor_malloc(srclen + 4);
memcpy(buf, src, srclen+1);
size_t buflen;
switch (srclen % 4)
{
case 0:
default:
buflen = srclen;
break;
case 1:
tor_free(buf);
return -1;
case 2:
memcpy(buf+srclen, "==", 3);
buflen = srclen + 2;
break;
case 3:
memcpy(buf+srclen, "=", 2);
buflen = srclen + 1;
break;
}
int n = base64_decode((char*)dest, destlen, buf, buflen);
tor_free(buf);
return n;
}
/** @{ */ /** @{ */
/** Special values used for the base64_decode_table */ /** Special values used for the base64_decode_table */
#define X 255 #define X 255

View File

@ -207,6 +207,11 @@ int crypto_digest256(char *digest, const char *m, size_t len,
digest_algorithm_t algorithm); digest_algorithm_t algorithm);
int crypto_digest_all(digests_t *ds_out, const char *m, size_t len); int crypto_digest_all(digests_t *ds_out, const char *m, size_t len);
struct smartlist_t; struct smartlist_t;
void crypto_digest_smartlist_prefix(char *digest_out, size_t len_out,
const char *prepend,
const struct smartlist_t *lst,
const char *append,
digest_algorithm_t alg);
void crypto_digest_smartlist(char *digest_out, size_t len_out, void crypto_digest_smartlist(char *digest_out, size_t len_out,
const struct smartlist_t *lst, const char *append, const struct smartlist_t *lst, const char *append,
digest_algorithm_t alg); digest_algorithm_t alg);
@ -270,6 +275,11 @@ void smartlist_shuffle(struct smartlist_t *sl);
int base64_encode(char *dest, size_t destlen, const char *src, size_t srclen); int base64_encode(char *dest, size_t destlen, const char *src, size_t srclen);
int base64_decode(char *dest, size_t destlen, const char *src, size_t srclen); int base64_decode(char *dest, size_t destlen, const char *src, size_t srclen);
int base64_encode_nopad(char *dest, size_t destlen,
const uint8_t *src, size_t srclen);
int base64_decode_nopad(uint8_t *dest, size_t destlen,
const char *src, size_t srclen);
/** Characters that can appear (case-insensitively) in a base32 encoding. */ /** Characters that can appear (case-insensitively) in a base32 encoding. */
#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567" #define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567"
void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen); void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen);

View File

@ -351,6 +351,7 @@ ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out,
return 0; return 0;
} }
/** Release all storage held for <b>kp</b>. */
void void
ed25519_keypair_free(ed25519_keypair_t *kp) ed25519_keypair_free(ed25519_keypair_t *kp)
{ {
@ -361,3 +362,13 @@ ed25519_keypair_free(ed25519_keypair_t *kp)
tor_free(kp); tor_free(kp);
} }
/** Return true iff <b>key1</b> and <b>key2</b> are the same public key. */
int
ed25519_pubkey_eq(const ed25519_public_key_t *key1,
const ed25519_public_key_t *key2)
{
tor_assert(key1);
tor_assert(key2);
return tor_memeq(key1->pubkey, key2->pubkey, ED25519_PUBKEY_LEN);
}

View File

@ -95,6 +95,13 @@ int ed25519_public_from_base64(ed25519_public_key_t *pkey,
int ed25519_public_to_base64(char *output, int ed25519_public_to_base64(char *output,
const ed25519_public_key_t *pkey); const ed25519_public_key_t *pkey);
#define ED25519_SIG_BASE64_LEN 86
int ed25519_signature_from_base64(ed25519_signature_t *sig,
const char *input);
int ed25519_signature_to_base64(char *output,
const ed25519_signature_t *sig);
/* XXXX read encrypted, write encrypted. */ /* XXXX read encrypted, write encrypted. */
int ed25519_seckey_write_to_file(const ed25519_secret_key_t *seckey, int ed25519_seckey_write_to_file(const ed25519_secret_key_t *seckey,
@ -112,5 +119,8 @@ int ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out,
void ed25519_keypair_free(ed25519_keypair_t *kp); void ed25519_keypair_free(ed25519_keypair_t *kp);
int ed25519_pubkey_eq(const ed25519_public_key_t *key1,
const ed25519_public_key_t *key2);
#endif #endif

View File

@ -65,3 +65,42 @@ ed25519_public_to_base64(char *output,
return digest256_to_base64(output, (const char *)pkey->pubkey); return digest256_to_base64(output, (const char *)pkey->pubkey);
} }
/** Encode the signature <b>sig</b> into the buffer at <b>output</b>,
* which must have space for ED25519_SIG_BASE64_LEN bytes of encoded signature,
* plus one byte for a terminating NUL. Return 0 on success, -1 on failure.
*/
int
ed25519_signature_to_base64(char *output,
const ed25519_signature_t *sig)
{
char buf[256];
int n = base64_encode_nopad(buf, sizeof(buf), sig->sig, ED25519_SIG_LEN);
tor_assert(n == ED25519_SIG_BASE64_LEN);
memcpy(output, buf, ED25519_SIG_BASE64_LEN+1);
return 0;
}
/** Try to decode the string <b>input</b> into an ed25519 signature. On
* success, store the value in <b>sig</b> and return 0. Otherwise return
* -1. */
int
ed25519_signature_from_base64(ed25519_signature_t *sig,
const char *input)
{
if (strlen(input) != ED25519_SIG_BASE64_LEN)
return -1;
char buf[ED25519_SIG_BASE64_LEN+3];
memcpy(buf, input, ED25519_SIG_BASE64_LEN);
buf[ED25519_SIG_BASE64_LEN+0] = '=';
buf[ED25519_SIG_BASE64_LEN+1] = '=';
buf[ED25519_SIG_BASE64_LEN+2] = 0;
char decoded[128];
int n = base64_decode(decoded, sizeof(decoded), buf, strlen(buf));
if (n < 0 || n != ED25519_SIG_LEN)
return -1;
memcpy(sig->sig, decoded, ED25519_SIG_LEN);
return 0;
}

View File

@ -2021,6 +2021,8 @@ typedef struct {
crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */ crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */
/** Public curve25519 key for onions */ /** Public curve25519 key for onions */
curve25519_public_key_t *onion_curve25519_pkey; 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? */ char *platform; /**< What software/operating system is this OR using? */

View File

@ -30,6 +30,7 @@
#include "routerlist.h" #include "routerlist.h"
#include "routerparse.h" #include "routerparse.h"
#include "statefile.h" #include "statefile.h"
#include "torcert.h"
#include "transports.h" #include "transports.h"
#include "routerset.h" #include "routerset.h"
@ -1881,6 +1882,8 @@ router_rebuild_descriptor(int force)
routerinfo_free(ri); routerinfo_free(ri);
return -1; return -1;
} }
ri->signing_key_cert = tor_cert_dup(get_master_signing_key_cert());
get_platform_str(platform, sizeof(platform)); get_platform_str(platform, sizeof(platform));
ri->platform = tor_strdup(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 /* ri was allocated with tor_malloc_zero, so there is no need to
* zero ri->cache_info.extra_info_digest here. */ * zero ri->cache_info.extra_info_digest here. */
} }
if (! (ri->cache_info.signed_descriptor_body = router_dump_router_to_string( if (! (ri->cache_info.signed_descriptor_body =
ri, get_server_identity_key()))) { router_dump_router_to_string(ri, get_server_identity_key(),
get_master_signing_keypair())) ) {
log_warn(LD_BUG, "Couldn't generate router descriptor."); log_warn(LD_BUG, "Couldn't generate router descriptor.");
routerinfo_free(ri); routerinfo_free(ri);
extrainfo_free(ei); extrainfo_free(ei);
@ -2302,12 +2306,13 @@ get_platform_str(char *platform, size_t len)
*/ */
char * char *
router_dump_router_to_string(routerinfo_t *router, 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 *address = NULL;
char *onion_pkey = NULL; /* Onion key, PEM-encoded. */ char *onion_pkey = NULL; /* Onion key, PEM-encoded. */
char *identity_pkey = NULL; /* Identity 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 published[ISO_TIME_LEN+1];
char fingerprint[FINGERPRINT_LEN+1]; char fingerprint[FINGERPRINT_LEN+1];
int has_extra_info_digest; int has_extra_info_digest;
@ -2318,6 +2323,8 @@ router_dump_router_to_string(routerinfo_t *router,
const or_options_t *options = get_options(); const or_options_t *options = get_options();
smartlist_t *chunks = NULL; smartlist_t *chunks = NULL;
char *output = 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. */ /* Make sure the identity key matches the one in the routerinfo. */
if (!crypto_pk_eq_keys(ident_key, router->identity_pkey)) { 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!"); "match router's public key!");
goto err; 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 */ /* record our fingerprint, so we can include it in the descriptor */
if (crypto_pk_get_fingerprint(router->identity_pkey, fingerprint, 1)<0) { 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; 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 */ /* PEM-encode the onion key */
if (crypto_pk_write_public_key_to_string(router->onion_pkey, if (crypto_pk_write_public_key_to_string(router->onion_pkey,
&onion_pkey,&onion_pkeylen)<0) { &onion_pkey,&onion_pkeylen)<0) {
@ -2385,6 +2416,7 @@ router_dump_router_to_string(routerinfo_t *router,
smartlist_add_asprintf(chunks, smartlist_add_asprintf(chunks,
"router %s %s %d 0 %d\n" "router %s %s %d 0 %d\n"
"%s" "%s"
"%s"
"platform %s\n" "platform %s\n"
"protocols Link 1 2 Circuit 1\n" "protocols Link 1 2 Circuit 1\n"
"published %s\n" "published %s\n"
@ -2399,6 +2431,7 @@ router_dump_router_to_string(routerinfo_t *router,
address, address,
router->or_port, router->or_port,
decide_to_advertise_dirport(options, router->dir_port), decide_to_advertise_dirport(options, router->dir_port),
ed_cert_line ? ed_cert_line : "",
extra_or_address ? extra_or_address : "", extra_or_address ? extra_or_address : "",
router->platform, router->platform,
published, published,
@ -2455,7 +2488,24 @@ router_dump_router_to_string(routerinfo_t *router,
tor_free(p6); 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")); smartlist_add(chunks, tor_strdup("router-signature\n"));
crypto_digest_smartlist(digest, DIGEST_LEN, chunks, "", DIGEST_SHA1); 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(onion_pkey);
tor_free(identity_pkey); tor_free(identity_pkey);
tor_free(extra_or_address); tor_free(extra_or_address);
tor_free(ed_cert_line);
return output; return output;
} }

View File

@ -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_pick_published_address(const or_options_t *options, uint32_t *addr);
int router_rebuild_descriptor(int force); int router_rebuild_descriptor(int force);
char *router_dump_router_to_string(routerinfo_t *router, 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, char *router_dump_exit_policy_to_string(const routerinfo_t *router,
int include_ipv4, int include_ipv4,
int include_ipv6); int include_ipv6);

View File

@ -13,6 +13,7 @@
#define ROUTERLIST_PRIVATE #define ROUTERLIST_PRIVATE
#include "or.h" #include "or.h"
#include "crypto_ed25519.h"
#include "circuitstats.h" #include "circuitstats.h"
#include "config.h" #include "config.h"
#include "connection.h" #include "connection.h"
@ -38,6 +39,7 @@
#include "routerparse.h" #include "routerparse.h"
#include "routerset.h" #include "routerset.h"
#include "../common/sandbox.h" #include "../common/sandbox.h"
#include "torcert.h"
// #define DEBUG_ROUTERLIST // #define DEBUG_ROUTERLIST
/****************************************************************************/ /****************************************************************************/
@ -2663,6 +2665,7 @@ routerinfo_free(routerinfo_t *router)
tor_free(router->onion_curve25519_pkey); tor_free(router->onion_curve25519_pkey);
if (router->identity_pkey) if (router->identity_pkey)
crypto_pk_free(router->identity_pkey); crypto_pk_free(router->identity_pkey);
tor_cert_free(router->signing_key_cert);
if (router->declared_family) { if (router->declared_family) {
SMARTLIST_FOREACH(router->declared_family, char *, s, tor_free(s)); SMARTLIST_FOREACH(router->declared_family, char *, s, tor_free(s));
smartlist_free(router->declared_family); smartlist_free(router->declared_family);

View File

@ -26,6 +26,8 @@
#include "rephist.h" #include "rephist.h"
#include "routerparse.h" #include "routerparse.h"
#include "entrynodes.h" #include "entrynodes.h"
#include "torcert.h"
#undef log #undef log
#include <math.h> #include <math.h>
@ -83,6 +85,8 @@ typedef enum {
K_HIDDEN_SERVICE_DIR, K_HIDDEN_SERVICE_DIR,
K_ALLOW_SINGLE_HOP_EXITS, K_ALLOW_SINGLE_HOP_EXITS,
K_IPV6_POLICY, K_IPV6_POLICY,
K_ROUTER_SIG_ED25519,
K_IDENTITY_ED25519,
K_DIRREQ_END, K_DIRREQ_END,
K_DIRREQ_V2_IPS, 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("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ),
T01("extra-info-digest", K_EXTRA_INFO_DIGEST, GE(1), 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("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("allow-single-hop-exits",K_ALLOW_SINGLE_HOP_EXITS, NO_ARGS, NO_OBJ ),
T01("family", K_FAMILY, 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); unsigned fmt_flags);
static addr_policy_t *router_parse_addr_policy_private(directory_token_t *tok); 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, static int router_get_hash_impl(const char *s, size_t s_len, char *digest,
const char *start_str, const char *end_str, const char *start_str, const char *end_str,
char end_char, 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)); 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); tok = find_by_keyword(tokens, K_SIGNING_KEY);
router->identity_pkey = tok->key; router->identity_pkey = tok->key;
tok->key = NULL; /* Prevent free */ tok->key = NULL; /* Prevent free */

View File

@ -92,5 +92,7 @@ STATIC int routerstatus_parse_guardfraction(const char *guardfraction_str,
routerstatus_t *rs); routerstatus_t *rs);
#endif #endif
#define ED_DESC_SIGNATURE_PREFIX "Tor router descriptor signature v1"
#endif #endif

View File

@ -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;
}

View File

@ -62,5 +62,7 @@ int tor_cert_get_checkable_sig(ed25519_checkable_t *checkable_out,
int tor_cert_checksig(tor_cert_t *cert, int tor_cert_checksig(tor_cert_t *cert,
const ed25519_public_key_t *pubkey, time_t now); const ed25519_public_key_t *pubkey, time_t now);
tor_cert_t *tor_cert_dup(const tor_cert_t *cert);
#endif #endif

View File

@ -620,9 +620,18 @@ test_crypto_formats(void *arg)
for (idx = 0; idx < 10; ++idx) { for (idx = 0; idx < 10; ++idx) {
i = base64_encode(data2, 1024, data1, idx); i = base64_encode(data2, 1024, data1, idx);
tt_int_op(i, OP_GE, 0); tt_int_op(i, OP_GE, 0);
tt_int_op(i, OP_EQ, strlen(data2));
j = base64_decode(data3, 1024, data2, i); j = base64_decode(data3, 1024, data2, i);
tt_int_op(j,OP_EQ, idx); tt_int_op(j,OP_EQ, idx);
tt_mem_op(data3,OP_EQ, data1, idx); tt_mem_op(data3,OP_EQ, data1, idx);
i = base64_encode_nopad(data2, 1024, (uint8_t*)data1, idx);
tt_int_op(i, OP_GE, 0);
tt_int_op(i, OP_EQ, strlen(data2));
tt_assert(! strchr(data2, '='));
j = base64_decode_nopad((uint8_t*)data3, 1024, data2, i);
tt_int_op(j, OP_EQ, idx);
tt_mem_op(data3,OP_EQ, data1, idx);
} }
strlcpy(data1, "Test string that contains 35 chars.", 1024); strlcpy(data1, "Test string that contains 35 chars.", 1024);
@ -1172,6 +1181,8 @@ test_crypto_ed25519_simple(void *arg)
tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pub2, &sec1)); tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pub2, &sec1));
tt_mem_op(pub1.pubkey, OP_EQ, pub2.pubkey, sizeof(pub1.pubkey)); tt_mem_op(pub1.pubkey, OP_EQ, pub2.pubkey, sizeof(pub1.pubkey));
tt_assert(ed25519_pubkey_eq(&pub1, &pub2));
tt_assert(ed25519_pubkey_eq(&pub1, &pub1));
memcpy(&kp1.pubkey, &pub1, sizeof(pub1)); memcpy(&kp1.pubkey, &pub1, sizeof(pub1));
memcpy(&kp1.seckey, &sec1, sizeof(sec1)); memcpy(&kp1.seckey, &sec1, sizeof(sec1));
@ -1191,6 +1202,7 @@ test_crypto_ed25519_simple(void *arg)
/* Wrong public key doesn't work. */ /* Wrong public key doesn't work. */
tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pub2, &sec2)); tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pub2, &sec2));
tt_int_op(-1, OP_EQ, ed25519_checksig(&sig2, msg, msg_len, &pub2)); tt_int_op(-1, OP_EQ, ed25519_checksig(&sig2, msg, msg_len, &pub2));
tt_assert(! ed25519_pubkey_eq(&pub1, &pub2));
/* Wrong message doesn't work. */ /* Wrong message doesn't work. */
tt_int_op(0, OP_EQ, ed25519_checksig(&sig2, msg, msg_len, &pub1)); tt_int_op(0, OP_EQ, ed25519_checksig(&sig2, msg, msg_len, &pub1));
@ -1329,9 +1341,10 @@ test_crypto_ed25519_test_vectors(void *arg)
static void static void
test_crypto_ed25519_encode(void *arg) test_crypto_ed25519_encode(void *arg)
{ {
char buf[ED25519_BASE64_LEN+1]; char buf[ED25519_SIG_BASE64_LEN+1];
ed25519_keypair_t kp; ed25519_keypair_t kp;
ed25519_public_key_t pk; ed25519_public_key_t pk;
ed25519_signature_t sig1, sig2;
char *mem_op_hex_tmp = NULL; char *mem_op_hex_tmp = NULL;
(void) arg; (void) arg;
@ -1342,6 +1355,11 @@ test_crypto_ed25519_encode(void *arg)
tt_int_op(0, OP_EQ, ed25519_public_from_base64(&pk, buf)); tt_int_op(0, OP_EQ, ed25519_public_from_base64(&pk, buf));
tt_mem_op(kp.pubkey.pubkey, OP_EQ, pk.pubkey, ED25519_PUBKEY_LEN); tt_mem_op(kp.pubkey.pubkey, OP_EQ, pk.pubkey, ED25519_PUBKEY_LEN);
tt_int_op(0, OP_EQ, ed25519_sign(&sig1, (const uint8_t*)"ABC", 3, &kp));
tt_int_op(0, OP_EQ, ed25519_signature_to_base64(buf, &sig1));
tt_int_op(0, OP_EQ, ed25519_signature_from_base64(&sig2, buf));
tt_mem_op(sig1.sig, OP_EQ, sig2.sig, ED25519_SIG_LEN);
/* Test known value. */ /* Test known value. */
tt_int_op(0, OP_EQ, ed25519_public_from_base64(&pk, tt_int_op(0, OP_EQ, ed25519_public_from_base64(&pk,
"lVIuIctLjbGZGU5wKMNXxXlSE3cW4kaqkqm04u6pxvM")); "lVIuIctLjbGZGU5wKMNXxXlSE3cW4kaqkqm04u6pxvM"));

View File

@ -14,6 +14,7 @@
#define NETWORKSTATUS_PRIVATE #define NETWORKSTATUS_PRIVATE
#include "or.h" #include "or.h"
#include "config.h" #include "config.h"
#include "crypto_ed25519.h"
#include "directory.h" #include "directory.h"
#include "dirserv.h" #include "dirserv.h"
#include "dirvote.h" #include "dirvote.h"
@ -23,6 +24,7 @@
#include "routerlist.h" #include "routerlist.h"
#include "routerparse.h" #include "routerparse.h"
#include "test.h" #include "test.h"
#include "torcert.h"
static void static void
test_dir_nicknames(void *arg) test_dir_nicknames(void *arg)
@ -89,6 +91,7 @@ test_dir_formats(void *arg)
routerlist_t *dir1 = NULL, *dir2 = NULL; routerlist_t *dir1 = NULL, *dir2 = NULL;
or_options_t *options = get_options_mutable(); or_options_t *options = get_options_mutable();
const addr_policy_t *p; const addr_policy_t *p;
time_t now = time(NULL);
(void)arg; (void)arg;
pk1 = pk_generate(0); pk1 = pk_generate(0);
@ -127,6 +130,22 @@ test_dir_formats(void *arg)
ex2->prt_min = ex2->prt_max = 24; ex2->prt_min = ex2->prt_max = 24;
r2 = tor_malloc_zero(sizeof(routerinfo_t)); r2 = tor_malloc_zero(sizeof(routerinfo_t));
r2->addr = 0x0a030201u; /* 10.3.2.1 */ r2->addr = 0x0a030201u; /* 10.3.2.1 */
ed25519_keypair_t kp1, kp2;
ed25519_secret_key_from_seed(&kp1.seckey,
(const uint8_t*)"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY");
ed25519_public_key_generate(&kp1.pubkey, &kp1.seckey);
ed25519_secret_key_from_seed(&kp2.seckey,
(const uint8_t*)"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
ed25519_public_key_generate(&kp2.pubkey, &kp2.seckey);
r2->signing_key_cert = tor_cert_create(&kp1,
CERT_TYPE_ID_SIGNING,
&kp2.pubkey,
now, 86400,
CERT_FLAG_INCLUDE_SIGNING_KEY);
char cert_buf[256];
base64_encode(cert_buf, sizeof(cert_buf),
(const char*)r2->signing_key_cert->encoded,
r2->signing_key_cert->encoded_len);
r2->platform = tor_strdup(platform); r2->platform = tor_strdup(platform);
r2->cache_info.published_on = 5; r2->cache_info.published_on = 5;
r2->or_port = 9005; r2->or_port = 9005;
@ -150,7 +169,7 @@ test_dir_formats(void *arg)
/* XXXX025 router_dump_to_string should really take this from ri.*/ /* XXXX025 router_dump_to_string should really take this from ri.*/
options->ContactInfo = tor_strdup("Magri White " options->ContactInfo = tor_strdup("Magri White "
"<magri@elsewhere.example.com>"); "<magri@elsewhere.example.com>");
buf = router_dump_router_to_string(r1, pk2); buf = router_dump_router_to_string(r1, pk2, NULL);
tor_free(options->ContactInfo); tor_free(options->ContactInfo);
tt_assert(buf); tt_assert(buf);
@ -183,7 +202,7 @@ test_dir_formats(void *arg)
tt_str_op(buf,OP_EQ, buf2); tt_str_op(buf,OP_EQ, buf2);
tor_free(buf); tor_free(buf);
buf = router_dump_router_to_string(r1, pk2); buf = router_dump_router_to_string(r1, pk2, NULL);
tt_assert(buf); tt_assert(buf);
cp = buf; cp = buf;
rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL); rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
@ -201,6 +220,10 @@ test_dir_formats(void *arg)
strlcpy(buf2, strlcpy(buf2,
"router Fred 10.3.2.1 9005 0 0\n" "router Fred 10.3.2.1 9005 0 0\n"
"identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n", sizeof(buf2));
strlcat(buf2, cert_buf, sizeof(buf2));
strlcat(buf2, "-----END ED25519 CERT-----\n"
"platform Tor "VERSION" on ", sizeof(buf2)); "platform Tor "VERSION" on ", sizeof(buf2));
strlcat(buf2, get_uname(), sizeof(buf2)); strlcat(buf2, get_uname(), sizeof(buf2));
strlcat(buf2, "\n" strlcat(buf2, "\n"
@ -219,15 +242,16 @@ test_dir_formats(void *arg)
strlcat(buf2, "ntor-onion-key " strlcat(buf2, "ntor-onion-key "
"skyinAnvardNostarsNomoonNowindormistsorsnow=\n", sizeof(buf2)); "skyinAnvardNostarsNomoonNowindormistsorsnow=\n", sizeof(buf2));
strlcat(buf2, "accept *:80\nreject 18.0.0.0/8:24\n", sizeof(buf2)); strlcat(buf2, "accept *:80\nreject 18.0.0.0/8:24\n", sizeof(buf2));
strlcat(buf2, "router-signature\n", sizeof(buf2)); strlcat(buf2, "router-sig-ed25519 ", sizeof(buf2));
buf = router_dump_router_to_string(r2, pk1); buf = router_dump_router_to_string(r2, pk1, &kp2);
tt_assert(buf);
buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
* twice */ * twice */
tt_str_op(buf,OP_EQ, buf2); tt_str_op(buf,OP_EQ, buf2);
tor_free(buf); tor_free(buf);
buf = router_dump_router_to_string(r2, pk1); buf = router_dump_router_to_string(r2, pk1, NULL);
cp = buf; cp = buf;
rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL); rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
tt_assert(rp2); tt_assert(rp2);

View File

@ -90,6 +90,7 @@ test_routerkeys_ed_certs(void *args)
tor_cert_t *parsed_cert[2] = {NULL, NULL}; tor_cert_t *parsed_cert[2] = {NULL, NULL};
time_t now = 1412094534; time_t now = 1412094534;
uint8_t *junk = NULL; uint8_t *junk = NULL;
char *base64 = NULL;
tt_int_op(0,==,ed25519_keypair_generate(&kp1, 0)); tt_int_op(0,==,ed25519_keypair_generate(&kp1, 0));
tt_int_op(0,==,ed25519_keypair_generate(&kp2, 0)); tt_int_op(0,==,ed25519_keypair_generate(&kp2, 0));
@ -186,6 +187,7 @@ test_routerkeys_ed_certs(void *args)
tor_cert_free(parsed_cert[0]); tor_cert_free(parsed_cert[0]);
tor_cert_free(parsed_cert[1]); tor_cert_free(parsed_cert[1]);
tor_free(junk); tor_free(junk);
tor_free(base64);
} }
static void static void