diff --git a/src/common/crypto.c b/src/common/crypto.c index 218c7bea1e..06631e1604 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -1724,7 +1724,24 @@ crypto_digest_assign(crypto_digest_t *into, * out_len 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 lst, set the len_out-byte digest + * at digest_out to the hash of the concatenation of: the + * optional string prepend, those strings, + * and the optional string append, computed with the algorithm + * alg. + * out_len 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 diff --git a/src/common/crypto.h b/src/common/crypto.h index d305bc17a0..526619766d 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -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); diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c index 7e8b00abef..6b93751dda 100644 --- a/src/common/crypto_ed25519.c +++ b/src/common/crypto_ed25519.c @@ -351,6 +351,7 @@ ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out, return 0; } +/** Release all storage held for kp. */ 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 key1 and key2 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); +} + diff --git a/src/common/crypto_ed25519.h b/src/common/crypto_ed25519.h index 8e06191fc5..79b3db8f9a 100644 --- a/src/common/crypto_ed25519.h +++ b/src/common/crypto_ed25519.h @@ -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 diff --git a/src/common/crypto_format.c b/src/common/crypto_format.c index 00e0e9ea85..503d1de932 100644 --- a/src/common/crypto_format.c +++ b/src/common/crypto_format.c @@ -65,3 +65,42 @@ ed25519_public_to_base64(char *output, return digest256_to_base64(output, (const char *)pkey->pubkey); } +/** Encode the signature sig into the buffer at output, + * 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 input into an ed25519 signature. On + * success, store the value in sig 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; +} + 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 @@ -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 cert */ +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 diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index e9fb8bf084..15ba14b3bf 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -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")); diff --git a/src/test/test_dir.c b/src/test/test_dir.c index a949f5de73..85ca40f3de 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -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 " ""); - 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); diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c index 63284b798b..8780213a29 100644 --- a/src/test/test_routerkeys.c +++ b/src/test/test_routerkeys.c @@ -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