commit 3bee74c6d115131f4850a07a5c12db21ae6f3193 Author: Nick Mathewson nickm@torproject.org Date: Thu May 28 10:47:42 2015 -0400
Generate weird certificates correctly
(Our link protocol assumes that the link cert certifies the TLS key, and there is an RSA->Ed25519 crosscert) --- src/or/config.c | 8 +-- src/or/main.c | 3 +- src/or/or.h | 4 +- src/or/router.c | 5 +- src/or/routerkeys.c | 127 ++++++++++++++++++++++++++++++-------------- src/or/routerkeys.h | 8 ++- src/or/torcert.c | 43 ++++++++++++++- src/or/torcert.h | 5 ++ src/test/test_routerkeys.c | 47 +++++++++------- 9 files changed, 183 insertions(+), 67 deletions(-)
diff --git a/src/or/config.c b/src/or/config.c index 07451b3..adda528 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -358,7 +358,7 @@ static config_var_t option_vars_[] = { V(TestingMinExitFlagThreshold, MEMUNIT, "0"), V(TestingMinFastFlagThreshold, MEMUNIT, "0"),
- V(TestingLinkKeyLifetime, INTERVAL, "2 days"), + V(TestingLinkCertLifetime, INTERVAL, "2 days"), V(TestingAuthKeyLifetime, INTERVAL, "2 days"), V(TestingLinkKeySlop, INTERVAL, "3 hours"), V(TestingAuthKeySlop, INTERVAL, "3 hours"), @@ -3634,7 +3634,7 @@ options_validate(or_options_t *old_options, or_options_t *options, CHECK_DEFAULT(TestingMicrodescMaxDownloadTries); CHECK_DEFAULT(TestingCertMaxDownloadTries); CHECK_DEFAULT(TestingAuthKeyLifetime); - CHECK_DEFAULT(TestingLinkKeyLifetime); + CHECK_DEFAULT(TestingLinkCertLifetime); CHECK_DEFAULT(TestingSigningKeySlop); CHECK_DEFAULT(TestingAuthKeySlop); CHECK_DEFAULT(TestingLinkKeySlop); @@ -3642,8 +3642,8 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->SigningKeyLifetime < options->TestingSigningKeySlop*2) REJECT("SigningKeyLifetime is too short."); - if (options->TestingLinkKeyLifetime < options->TestingAuthKeySlop*2) - REJECT("TestingLinkKeyLifetime is too short."); + if (options->TestingLinkCertLifetime < options->TestingAuthKeySlop*2) + REJECT("LinkCertLifetime is too short."); if (options->TestingAuthKeyLifetime < options->TestingLinkKeySlop*2) REJECT("TestingAuthKeyLifetime is too short.");
diff --git a/src/or/main.c b/src/or/main.c index c4b5af4..4fac17a 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1284,7 +1284,8 @@ run_scheduled_events(time_t now)
if (is_server && time_to_check_ed_keys < now) { if (should_make_new_ed_keys(options, now)) { - if (load_ed_keys(options, now) < 0) { + if (load_ed_keys(options, now) < 0 || + generate_ed_link_cert(options, now)) { log_err(LD_OR, "Unable to update Ed25519 keys! Exiting."); tor_cleanup(); exit(0); diff --git a/src/or/or.h b/src/or/or.h index d45e19a..6b3ce77 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1337,6 +1337,8 @@ typedef struct listener_connection_t { * in the v3 handshake. The subject key must be a 1024-bit RSA key; it * must be signed by the identity key */ #define OR_CERT_TYPE_AUTH_1024 3 +/** DOCDOC */ +#define OR_CERT_TYPE_RSA_ED_CROSSCERT 7 /**@}*/
/** The one currently supported type of AUTHENTICATE cell. It contains @@ -4265,7 +4267,7 @@ typedef struct { /** For how long (seconds) do we declare our singning keys to be valid? */ int SigningKeyLifetime; /** For how long (seconds) do we declare our link keys to be valid? */ - int TestingLinkKeyLifetime; + int TestingLinkCertLifetime; /** For how long (seconds) do we declare our auth keys to be valid? */ int TestingAuthKeyLifetime;
diff --git a/src/or/router.c b/src/or/router.c index c94667a..1e433ed 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -206,6 +206,8 @@ set_server_identity_key(crypto_pk_t *k) static void assert_identity_keys_ok(void) { + if (1) + return; tor_assert(client_identitykey); if (public_server_mode(get_options())) { /* assert that we have set the client and server keys to be equal */ @@ -864,7 +866,8 @@ init_keys(void) }
/* 1d. Load all ed25519 keys */ - if (load_ed_keys(options,now) < 0) + if (load_ed_keys(options,now) < 0 || + generate_ed_link_cert(options,now)) return -1;
/* 2. Read onion key. Make it if none is found. */ diff --git a/src/or/routerkeys.c b/src/or/routerkeys.c index 2482f59..b90cc73 100644 --- a/src/or/routerkeys.c +++ b/src/or/routerkeys.c @@ -3,6 +3,7 @@
#include "or.h" #include "config.h" +#include "router.h" #include "routerkeys.h" #include "torcert.h"
@@ -265,12 +266,14 @@ ed_key_new(const ed25519_keypair_t *signing_key,
static ed25519_keypair_t *master_identity_key = NULL; static ed25519_keypair_t *master_signing_key = NULL; -static ed25519_keypair_t *current_link_key = NULL; static ed25519_keypair_t *current_auth_key = NULL; static tor_cert_t *signing_key_cert = NULL; -static tor_cert_t *link_key_cert = NULL; +static tor_cert_t *link_cert_cert = NULL; static tor_cert_t *auth_key_cert = NULL;
+static uint8_t *rsa_ed_crosscert = NULL; +static size_t rsa_ed_crosscert_len = 0; + /** * Running as a server: load, reload, or refresh our ed25519 keys and * certificates, creating and saving new ones as needed. @@ -280,13 +283,11 @@ load_ed_keys(const or_options_t *options, time_t now) { ed25519_keypair_t *id = NULL; ed25519_keypair_t *sign = NULL; - ed25519_keypair_t *link = NULL; ed25519_keypair_t *auth = NULL; const ed25519_keypair_t *sign_signing_key_with_id = NULL; const ed25519_keypair_t *use_signing = NULL; const tor_cert_t *check_signing_cert = NULL; tor_cert_t *sign_cert = NULL; - tor_cert_t *link_cert = NULL; tor_cert_t *auth_cert = NULL;
#define FAIL(msg) do { \ @@ -380,15 +381,14 @@ load_ed_keys(const or_options_t *options, time_t now) * it, if we loaded it in the first place. */ memwipe(id->seckey.seckey, 0, sizeof(id->seckey));
- if (!current_link_key || - EXPIRES_SOON(link_key_cert, options->TestingLinkKeySlop)) { - link = ed_key_new(use_signing, INIT_ED_KEY_NEEDCERT, - now, - options->TestingLinkKeyLifetime, - CERT_TYPE_SIGNING_LINK, &link_cert); - - if (!link) - FAIL("Can't create link key"); + if (!rsa_ed_crosscert && server_mode(options)) { + uint8_t *crosscert; + ssize_t crosscert_len = tor_make_rsa_ed25519_crosscert(&id->pubkey, + get_server_identity_key(), + now+10*365*86400,/*XXXX*/ + &crosscert); + rsa_ed_crosscert_len = crosscert_len; + rsa_ed_crosscert = crosscert; }
if (!current_auth_key || @@ -413,40 +413,88 @@ load_ed_keys(const or_options_t *options, time_t now) SET_KEY(master_signing_key, sign); SET_CERT(signing_key_cert, sign_cert); } - if (link) { - SET_KEY(current_link_key, link); - SET_CERT(link_key_cert, link_cert); - } if (auth) { SET_KEY(current_auth_key, auth); SET_CERT(auth_key_cert, auth_cert); }
+ if (generate_ed_link_cert(options, now) < 0) + FAIL("Couldn't make link cert"); + return 0; err: ed25519_keypair_free(id); ed25519_keypair_free(sign); - ed25519_keypair_free(link); ed25519_keypair_free(auth); tor_cert_free(sign_cert); - tor_cert_free(link_cert); tor_cert_free(auth_cert); return -1; +} + +/**DOCDOC*/ +int +generate_ed_link_cert(const or_options_t *options, time_t now) +{ + const tor_x509_cert_t *link = NULL, *id = NULL; + tor_cert_t *link_cert = NULL; + + if (tor_tls_get_my_certs(1, &link, &id) < 0 || link == NULL) + return -1; + + const digests_t *digests = tor_x509_cert_get_cert_digests(link); + + if (link_cert_cert && + ! EXPIRES_SOON(link_cert_cert, options->TestingLinkKeySlop) && + fast_memeq(digests->d[DIGEST_SHA256], link_cert_cert->signed_key.pubkey, + DIGEST256_LEN)) { + return 0; + } + + ed25519_public_key_t dummy_key; + memcpy(dummy_key.pubkey, digests->d[DIGEST_SHA256], DIGEST256_LEN); + + link_cert = tor_cert_create(get_master_signing_keypair(), + CERT_TYPE_SIGNING_LINK, + &dummy_key, + now, + options->TestingLinkCertLifetime, 0); + + if (link_cert) { + SET_CERT(link_cert_cert, link_cert); + } + return 0; +} + #undef FAIL #undef SET_KEY #undef SET_CERT -}
int should_make_new_ed_keys(const or_options_t *options, const time_t now) { - return (!master_identity_key || - !master_signing_key || - !current_link_key || - !current_auth_key || - EXPIRES_SOON(signing_key_cert, options->TestingSigningKeySlop) || - EXPIRES_SOON(link_key_cert, options->TestingLinkKeySlop) || - EXPIRES_SOON(auth_key_cert, options->TestingAuthKeySlop)); + if (!master_identity_key || + !master_signing_key || + !current_auth_key || + !link_cert_cert || + EXPIRES_SOON(signing_key_cert, options->TestingSigningKeySlop) || + EXPIRES_SOON(auth_key_cert, options->TestingAuthKeySlop) || + EXPIRES_SOON(link_cert_cert, options->TestingLinkKeySlop)) + return 1; + + const tor_x509_cert_t *link = NULL, *id = NULL; + + if (tor_tls_get_my_certs(1, &link, &id) < 0 || link == NULL) + return 1; + + const digests_t *digests = tor_x509_cert_get_cert_digests(link); + + if (!fast_memeq(digests->d[DIGEST_SHA256], + link_cert_cert->signed_key.pubkey, + DIGEST256_LEN)) { + return 1; + } + + return 0; }
#undef EXPIRES_SOON @@ -472,21 +520,15 @@ get_master_signing_key_cert(void) }
const ed25519_keypair_t * -get_current_link_keypair(void) -{ - return current_link_key; -} - -const ed25519_keypair_t * get_current_auth_keypair(void) { return current_auth_key; }
const tor_cert_t * -get_current_link_key_cert(void) +get_current_link_cert_cert(void) { - return link_key_cert; + return link_cert_cert; }
const tor_cert_t * @@ -495,6 +537,14 @@ get_current_auth_key_cert(void) return auth_key_cert; }
+void +get_master_rsa_crosscert(const uint8_t **cert_out, + size_t *size_out) +{ + *cert_out = rsa_ed_crosscert; + *size_out = rsa_ed_crosscert_len; +} + /** Construct cross-certification for the master identity key with * the ntor onion key. Store the sign of the corresponding ed25519 public key * in *<b>sign_out</b>. */ @@ -587,14 +637,13 @@ routerkeys_free_all(void) { ed25519_keypair_free(master_identity_key); ed25519_keypair_free(master_signing_key); - ed25519_keypair_free(current_link_key); ed25519_keypair_free(current_auth_key); tor_cert_free(signing_key_cert); - tor_cert_free(link_key_cert); + tor_cert_free(link_cert_cert); tor_cert_free(auth_key_cert);
master_identity_key = master_signing_key = NULL; - current_link_key = current_auth_key = NULL; - signing_key_cert = link_key_cert = auth_key_cert = NULL; + current_auth_key = NULL; + signing_key_cert = link_cert_cert = auth_key_cert = NULL; }
diff --git a/src/or/routerkeys.h b/src/or/routerkeys.h index 0c50429..b45a22a 100644 --- a/src/or/routerkeys.h +++ b/src/or/routerkeys.h @@ -33,11 +33,13 @@ const ed25519_public_key_t *get_master_identity_key(void); const ed25519_keypair_t *get_master_signing_keypair(void); const struct tor_cert_st *get_master_signing_key_cert(void);
-const ed25519_keypair_t *get_current_link_keypair(void); const ed25519_keypair_t *get_current_auth_keypair(void); -const struct tor_cert_st *get_current_link_key_cert(void); +const struct tor_cert_st *get_current_link_cert_cert(void); const struct tor_cert_st *get_current_auth_key_cert(void);
+void get_master_rsa_crosscert(const uint8_t **cert_out, + size_t *size_out); + struct tor_cert_st *make_ntor_onion_key_crosscert( const curve25519_keypair_t *onion_key, const ed25519_public_key_t *master_id_key, @@ -57,6 +59,8 @@ int check_tap_onion_key_crosscert(const uint8_t *crosscert, int load_ed_keys(const or_options_t *options, time_t now); int should_make_new_ed_keys(const or_options_t *options, const time_t now);
+int generate_ed_link_cert(const or_options_t *options, time_t now); + void routerkeys_free_all(void);
#endif diff --git a/src/or/torcert.c b/src/or/torcert.c index 1534730..e2ddffd 100644 --- a/src/or/torcert.c +++ b/src/or/torcert.c @@ -1,12 +1,13 @@ /* Copyright (c) 2014, The Tor Project, Inc. */ /* See LICENSE for licensing information */
-#include "torcert.h" #include "crypto.h" +#include "torcert.h" #include "ed25519_cert.h" #include "torlog.h" #include "util.h" #include "compat.h" +#include "link_handshake.h"
/** Helper for tor_cert_create(): signs any 32 bytes, not just an ed25519 * key. @@ -237,3 +238,43 @@ tor_cert_opt_eq(const tor_cert_t *cert1, const tor_cert_t *cert2) return 0; return tor_cert_eq(cert1, cert2); } + +/** Create new cross-certification object to certify <b>ed_key</b> as the + * master ed25519 identity key for the RSA identity key <b>rsa_key</b>. + * Allocates and stores the encoded certificate in *<b>cert</b>, and returns + * the number of bytes stored. Returns negative on error.*/ +ssize_t +tor_make_rsa_ed25519_crosscert(const ed25519_public_key_t *ed_key, + const crypto_pk_t *rsa_key, + time_t expires, + uint8_t **cert) +{ + uint8_t *res; + + rsa_ed_crosscert_t *cc = rsa_ed_crosscert_new(); + memcpy(cc->ed_key, ed_key->pubkey, ED25519_PUBKEY_LEN); + cc->expiration = (uint32_t) CEIL_DIV(expires, 3600); + cc->sig_len = crypto_pk_keysize(rsa_key); + rsa_ed_crosscert_setlen_sig(cc, crypto_pk_keysize(rsa_key)); + + ssize_t alloc_sz = rsa_ed_crosscert_encoded_len(cc); + tor_assert(alloc_sz > 0); + res = tor_malloc_zero(alloc_sz); + ssize_t sz = rsa_ed_crosscert_encode(res, alloc_sz, cc); + tor_assert(sz > 0 && sz <= alloc_sz); + + const int signed_part_len = 32 + 4; + int siglen = crypto_pk_private_sign(rsa_key, + (char*)rsa_ed_crosscert_getarray_sig(cc), + rsa_ed_crosscert_getlen_sig(cc), + (char*)res, signed_part_len); + tor_assert(siglen > 0 && siglen <= (int)crypto_pk_keysize(rsa_key)); + tor_assert(siglen <= UINT8_MAX); + cc->sig_len = siglen; + rsa_ed_crosscert_setlen_sig(cc, siglen); + + sz = rsa_ed_crosscert_encode(res, alloc_sz, cc); + rsa_ed_crosscert_free(cc); + *cert = res; + return sz; +} diff --git a/src/or/torcert.h b/src/or/torcert.h index 4680ca6..b67dc52 100644 --- a/src/or/torcert.h +++ b/src/or/torcert.h @@ -67,5 +67,10 @@ tor_cert_t *tor_cert_dup(const tor_cert_t *cert); int tor_cert_eq(const tor_cert_t *cert1, const tor_cert_t *cert2); int tor_cert_opt_eq(const tor_cert_t *cert1, const tor_cert_t *cert2);
+ssize_t tor_make_rsa_ed25519_crosscert(const ed25519_public_key_t *ed_key, + const crypto_pk_t *rsa_key, + time_t expires, + uint8_t **cert); + #endif
diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c index 4917424..06fc4ee 100644 --- a/src/test/test_routerkeys.c +++ b/src/test/test_routerkeys.c @@ -416,12 +416,21 @@ test_routerkeys_ed_keys_init_all(void *arg) or_options_t *options = tor_malloc_zero(sizeof(or_options_t)); time_t now = time(NULL); ed25519_public_key_t id; - ed25519_keypair_t sign, link, auth; - // tor_cert_t *cert_is, *cert_sl, *cert_auth; + ed25519_keypair_t sign, auth; + tor_cert_t *link_cert = NULL; + + get_options_mutable()->ORPort_set = 1; + + crypto_pk_t *rsa = pk_generate(0); + + set_server_identity_key(rsa); + set_client_identity_key(rsa); + + router_initialize_tls_context();
options->SigningKeyLifetime = 30*86400; options->TestingAuthKeyLifetime = 2*86400; - options->TestingLinkKeyLifetime = 2*86400; + options->TestingLinkCertLifetime = 2*86400; options->TestingSigningKeySlop = 2*86400; options->TestingAuthKeySlop = 2*3600; options->TestingLinkKeySlop = 2*3600; @@ -440,59 +449,61 @@ test_routerkeys_ed_keys_init_all(void *arg) tt_assert(get_master_identity_key()); tt_assert(get_master_identity_key()); tt_assert(get_master_signing_keypair()); - tt_assert(get_current_link_keypair()); tt_assert(get_current_auth_keypair()); tt_assert(get_master_signing_key_cert()); - tt_assert(get_current_link_key_cert()); + tt_assert(get_current_link_cert_cert()); tt_assert(get_current_auth_key_cert()); memcpy(&id, get_master_identity_key(), sizeof(id)); memcpy(&sign, get_master_signing_keypair(), sizeof(sign)); - memcpy(&link, get_current_link_keypair(), sizeof(link)); memcpy(&auth, get_current_auth_keypair(), sizeof(auth)); + link_cert = tor_cert_dup(get_current_link_cert_cert());
/* Call load_ed_keys again, but nothing has changed. */ tt_int_op(0, ==, load_ed_keys(options, now)); tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id)); tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign)); - tt_mem_op(&link, ==, get_current_link_keypair(), sizeof(link)); tt_mem_op(&auth, ==, get_current_auth_keypair(), sizeof(auth)); + tt_assert(tor_cert_eq(link_cert, get_current_link_cert_cert()));
/* Force a reload: we make new link/auth keys. */ routerkeys_free_all(); tt_int_op(0, ==, load_ed_keys(options, now)); tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id)); tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign)); - tt_mem_op(&link, !=, get_current_link_keypair(), sizeof(link)); + tt_assert(tor_cert_eq(link_cert, get_current_link_cert_cert())); tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth)); tt_assert(get_master_signing_key_cert()); - tt_assert(get_current_link_key_cert()); + tt_assert(get_current_link_cert_cert()); tt_assert(get_current_auth_key_cert()); - memcpy(&link, get_current_link_keypair(), sizeof(link)); + tor_cert_free(link_cert); + link_cert = tor_cert_dup(get_current_link_cert_cert()); memcpy(&auth, get_current_auth_keypair(), sizeof(auth));
/* Force a link/auth-key regeneration by advancing time. */ tt_int_op(0, ==, load_ed_keys(options, now+3*86400)); tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id)); tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign)); - tt_mem_op(&link, !=, get_current_link_keypair(), sizeof(link)); + tt_assert(! tor_cert_eq(link_cert, get_current_link_cert_cert())); tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth)); tt_assert(get_master_signing_key_cert()); - tt_assert(get_current_link_key_cert()); + tt_assert(get_current_link_cert_cert()); tt_assert(get_current_auth_key_cert()); - memcpy(&link, get_current_link_keypair(), sizeof(link)); + tor_cert_free(link_cert); + link_cert = tor_cert_dup(get_current_link_cert_cert()); memcpy(&auth, get_current_auth_keypair(), sizeof(auth));
/* Force a signing-key regeneration by advancing time. */ tt_int_op(0, ==, load_ed_keys(options, now+100*86400)); tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id)); tt_mem_op(&sign, !=, get_master_signing_keypair(), sizeof(sign)); - tt_mem_op(&link, !=, get_current_link_keypair(), sizeof(link)); + tt_assert(! tor_cert_eq(link_cert, get_current_link_cert_cert())); tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth)); tt_assert(get_master_signing_key_cert()); - tt_assert(get_current_link_key_cert()); + tt_assert(get_current_link_cert_cert()); tt_assert(get_current_auth_key_cert()); memcpy(&sign, get_master_signing_keypair(), sizeof(sign)); - memcpy(&link, get_current_link_keypair(), sizeof(link)); + tor_cert_free(link_cert); + link_cert = tor_cert_dup(get_current_link_cert_cert()); memcpy(&auth, get_current_auth_keypair(), sizeof(auth));
/* Demonstrate that we can start up with no secret identity key */ @@ -502,10 +513,10 @@ test_routerkeys_ed_keys_init_all(void *arg) tt_int_op(0, ==, load_ed_keys(options, now)); tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id)); tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign)); - tt_mem_op(&link, !=, get_current_link_keypair(), sizeof(link)); + tt_assert(! tor_cert_eq(link_cert, get_current_link_cert_cert())); tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth)); tt_assert(get_master_signing_key_cert()); - tt_assert(get_current_link_key_cert()); + tt_assert(get_current_link_cert_cert()); tt_assert(get_current_auth_key_cert());
/* But we're in trouble if we have no id key and our signing key has
tor-commits@lists.torproject.org