Generate weird certificates correctly

(Our link protocol assumes that the link cert certifies the TLS key,
and there is an RSA->Ed25519 crosscert)
This commit is contained in:
Nick Mathewson 2015-05-28 10:47:42 -04:00
parent 32f59d7337
commit 3bee74c6d1
9 changed files with 183 additions and 67 deletions

View File

@ -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.");

View File

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

View File

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

View File

@ -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. */

View File

@ -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
@ -471,12 +519,6 @@ get_master_signing_key_cert(void)
return signing_key_cert;
}
const ed25519_keypair_t *
get_current_link_keypair(void)
{
return current_link_key;
}
const ed25519_keypair_t *
get_current_auth_keypair(void)
{
@ -484,9 +526,9 @@ get_current_auth_keypair(void)
}
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;
}

View File

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

View File

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

View File

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

View File

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