mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 06:13:31 +01:00
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:
parent
818e6f939d
commit
fe5d2477aa
@ -1724,7 +1724,24 @@ crypto_digest_assign(crypto_digest_t *into,
|
||||
* <b>out_len</b> must be \<= DIGEST256_LEN. */
|
||||
void
|
||||
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)
|
||||
{
|
||||
crypto_digest_t *d;
|
||||
@ -1732,6 +1749,8 @@ crypto_digest_smartlist(char *digest_out, size_t len_out,
|
||||
d = crypto_digest_new();
|
||||
else
|
||||
d = crypto_digest256_new(alg);
|
||||
if (prepend)
|
||||
crypto_digest_add_bytes(d, prepend, strlen(prepend));
|
||||
SMARTLIST_FOREACH(lst, const char *, cp,
|
||||
crypto_digest_add_bytes(d, cp, strlen(cp)));
|
||||
if (append)
|
||||
@ -2692,6 +2711,8 @@ base64_encode(char *dest, size_t destlen, const char *src, size_t srclen)
|
||||
return -1;
|
||||
if (destlen > SIZE_T_CEILING)
|
||||
return -1;
|
||||
if (destlen)
|
||||
*dest = 0; /* Ensure we always initialize the buffer */
|
||||
|
||||
EVP_EncodeInit(&ctx);
|
||||
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;
|
||||
}
|
||||
|
||||
/** 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 */
|
||||
#define X 255
|
||||
|
@ -207,6 +207,11 @@ int crypto_digest256(char *digest, const char *m, size_t len,
|
||||
digest_algorithm_t algorithm);
|
||||
int crypto_digest_all(digests_t *ds_out, const char *m, size_t len);
|
||||
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,
|
||||
const struct smartlist_t *lst, const char *append,
|
||||
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_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. */
|
||||
#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567"
|
||||
void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen);
|
||||
|
@ -351,6 +351,7 @@ ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Release all storage held for <b>kp</b>. */
|
||||
void
|
||||
ed25519_keypair_free(ed25519_keypair_t *kp)
|
||||
{
|
||||
@ -361,3 +362,13 @@ ed25519_keypair_free(ed25519_keypair_t *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);
|
||||
}
|
||||
|
||||
|
@ -95,6 +95,13 @@ int ed25519_public_from_base64(ed25519_public_key_t *pkey,
|
||||
int ed25519_public_to_base64(char *output,
|
||||
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. */
|
||||
|
||||
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);
|
||||
|
||||
int ed25519_pubkey_eq(const ed25519_public_key_t *key1,
|
||||
const ed25519_public_key_t *key2);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -65,3 +65,42 @@ ed25519_public_to_base64(char *output,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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? */
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -620,9 +620,18 @@ test_crypto_formats(void *arg)
|
||||
for (idx = 0; idx < 10; ++idx) {
|
||||
i = base64_encode(data2, 1024, data1, idx);
|
||||
tt_int_op(i, OP_GE, 0);
|
||||
tt_int_op(i, OP_EQ, strlen(data2));
|
||||
j = base64_decode(data3, 1024, data2, i);
|
||||
tt_int_op(j,OP_EQ, 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);
|
||||
@ -1172,6 +1181,8 @@ test_crypto_ed25519_simple(void *arg)
|
||||
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_assert(ed25519_pubkey_eq(&pub1, &pub2));
|
||||
tt_assert(ed25519_pubkey_eq(&pub1, &pub1));
|
||||
|
||||
memcpy(&kp1.pubkey, &pub1, sizeof(pub1));
|
||||
memcpy(&kp1.seckey, &sec1, sizeof(sec1));
|
||||
@ -1191,6 +1202,7 @@ test_crypto_ed25519_simple(void *arg)
|
||||
/* Wrong public key doesn't work. */
|
||||
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_assert(! ed25519_pubkey_eq(&pub1, &pub2));
|
||||
|
||||
/* Wrong message doesn't work. */
|
||||
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
|
||||
test_crypto_ed25519_encode(void *arg)
|
||||
{
|
||||
char buf[ED25519_BASE64_LEN+1];
|
||||
char buf[ED25519_SIG_BASE64_LEN+1];
|
||||
ed25519_keypair_t kp;
|
||||
ed25519_public_key_t pk;
|
||||
ed25519_signature_t sig1, sig2;
|
||||
char *mem_op_hex_tmp = NULL;
|
||||
(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_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. */
|
||||
tt_int_op(0, OP_EQ, ed25519_public_from_base64(&pk,
|
||||
"lVIuIctLjbGZGU5wKMNXxXlSE3cW4kaqkqm04u6pxvM"));
|
||||
|
@ -14,6 +14,7 @@
|
||||
#define NETWORKSTATUS_PRIVATE
|
||||
#include "or.h"
|
||||
#include "config.h"
|
||||
#include "crypto_ed25519.h"
|
||||
#include "directory.h"
|
||||
#include "dirserv.h"
|
||||
#include "dirvote.h"
|
||||
@ -23,6 +24,7 @@
|
||||
#include "routerlist.h"
|
||||
#include "routerparse.h"
|
||||
#include "test.h"
|
||||
#include "torcert.h"
|
||||
|
||||
static void
|
||||
test_dir_nicknames(void *arg)
|
||||
@ -89,6 +91,7 @@ test_dir_formats(void *arg)
|
||||
routerlist_t *dir1 = NULL, *dir2 = NULL;
|
||||
or_options_t *options = get_options_mutable();
|
||||
const addr_policy_t *p;
|
||||
time_t now = time(NULL);
|
||||
|
||||
(void)arg;
|
||||
pk1 = pk_generate(0);
|
||||
@ -127,6 +130,22 @@ test_dir_formats(void *arg)
|
||||
ex2->prt_min = ex2->prt_max = 24;
|
||||
r2 = tor_malloc_zero(sizeof(routerinfo_t));
|
||||
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->cache_info.published_on = 5;
|
||||
r2->or_port = 9005;
|
||||
@ -150,7 +169,7 @@ test_dir_formats(void *arg)
|
||||
/* XXXX025 router_dump_to_string should really take this from ri.*/
|
||||
options->ContactInfo = tor_strdup("Magri White "
|
||||
"<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);
|
||||
tt_assert(buf);
|
||||
|
||||
@ -183,7 +202,7 @@ test_dir_formats(void *arg)
|
||||
tt_str_op(buf,OP_EQ, buf2);
|
||||
tor_free(buf);
|
||||
|
||||
buf = router_dump_router_to_string(r1, pk2);
|
||||
buf = router_dump_router_to_string(r1, pk2, NULL);
|
||||
tt_assert(buf);
|
||||
cp = buf;
|
||||
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,
|
||||
"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));
|
||||
strlcat(buf2, get_uname(), sizeof(buf2));
|
||||
strlcat(buf2, "\n"
|
||||
@ -219,15 +242,16 @@ test_dir_formats(void *arg)
|
||||
strlcat(buf2, "ntor-onion-key "
|
||||
"skyinAnvardNostarsNomoonNowindormistsorsnow=\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
|
||||
* twice */
|
||||
tt_str_op(buf,OP_EQ, buf2);
|
||||
tor_free(buf);
|
||||
|
||||
buf = router_dump_router_to_string(r2, pk1);
|
||||
buf = router_dump_router_to_string(r2, pk1, NULL);
|
||||
cp = buf;
|
||||
rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
|
||||
tt_assert(rp2);
|
||||
|
@ -90,6 +90,7 @@ test_routerkeys_ed_certs(void *args)
|
||||
tor_cert_t *parsed_cert[2] = {NULL, NULL};
|
||||
time_t now = 1412094534;
|
||||
uint8_t *junk = NULL;
|
||||
char *base64 = NULL;
|
||||
|
||||
tt_int_op(0,==,ed25519_keypair_generate(&kp1, 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[1]);
|
||||
tor_free(junk);
|
||||
tor_free(base64);
|
||||
}
|
||||
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user