From 85dccce35db907221df38da7bd789f28f7d1e2f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20F=C3=A6r=C3=B8y?= Date: Wed, 8 Mar 2017 15:15:12 +0100 Subject: [PATCH 1/5] Make MAX_DIR_PERIOD independent of MIN_ONION_KEY_LIFETIME. As part of the work for proposal #274 we are going to remove the need for MIN_ONION_KEY_LIFETIME and turn it into a dynamic value defined by a consensus parameter. See: https://bugs.torproject.org/21641 --- src/or/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/or/config.c b/src/or/config.c index a527571cb0..79e12f4e22 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -2815,7 +2815,7 @@ compute_publishserverdescriptor(or_options_t *options) #define MAX_PREDICTED_CIRCS_RELEVANCE (60*60) /** Highest allowable value for RendPostPeriod. */ -#define MAX_DIR_PERIOD (MIN_ONION_KEY_LIFETIME/2) +#define MAX_DIR_PERIOD ((7*24*60*60)/2) /** Lowest allowable value for MaxCircuitDirtiness; if this is too low, Tor * will generate too many circuits and potentially overload the network. */ From 23ae5b655b9d94d62c6c9296cb8cc2b33ae345d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20F=C3=A6r=C3=B8y?= Date: Fri, 10 Mar 2017 12:18:52 +0100 Subject: [PATCH 2/5] Make MIN_ONION_KEY_LIFETIME a consensus parameter defined value. This patch turns `MIN_ONION_KEY_LIFETIME` into a new function `get_onion_key_lifetime()` which gets its value from a network consensus parameter named "onion-key-rotation-days". This allows us to tune the value at a later point in time with no code modifications. We also bump the default onion key lifetime from 7 to 28 days as per proposal #274. See: https://bugs.torproject.org/21641 --- src/or/main.c | 11 ++++++----- src/or/or.h | 11 +++++++++-- src/or/router.c | 29 +++++++++++++++++++++++++++-- src/or/router.h | 1 + src/test/test_dir.c | 2 +- 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/or/main.c b/src/or/main.c index 475587eacd..107a4842a9 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1472,15 +1472,16 @@ run_scheduled_events(time_t now) pt_configure_remaining_proxies(); } -/* Periodic callback: Every MIN_ONION_KEY_LIFETIME seconds, rotate the onion - * keys, shut down and restart all cpuworkers, and update our descriptor if - * necessary. +/* Periodic callback: rotate the onion keys after the period defined by the + * "onion-key-rotation-days" consensus parameter, shut down and restart all + * cpuworkers, and update our descriptor if necessary. */ static int rotate_onion_key_callback(time_t now, const or_options_t *options) { if (server_mode(options)) { - time_t rotation_time = get_onion_key_set_at()+MIN_ONION_KEY_LIFETIME; + int onion_key_lifetime = get_onion_key_lifetime(); + time_t rotation_time = get_onion_key_set_at()+onion_key_lifetime; if (rotation_time > now) { return safe_timer_diff(now, rotation_time); } @@ -1493,7 +1494,7 @@ rotate_onion_key_callback(time_t now, const or_options_t *options) } if (advertised_server_mode() && !options->DisableNetwork) router_upload_dir_desc_to_dirservers(0); - return MIN_ONION_KEY_LIFETIME; + return onion_key_lifetime; } return PERIODIC_EVENT_NO_UPDATE; } diff --git a/src/or/or.h b/src/or/or.h index 0e2dc2401b..2903f5e283 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -147,8 +147,15 @@ /** Maximum size of a single extrainfo document, as above. */ #define MAX_EXTRAINFO_UPLOAD_SIZE 50000 -/** How often do we rotate onion keys? */ -#define MIN_ONION_KEY_LIFETIME (7*24*60*60) +/** Minimum lifetime for an onion key in days. */ +#define MIN_ONION_KEY_LIFETIME_DAYS (1) + +/** Maximum lifetime for an onion key in days. */ +#define MAX_ONION_KEY_LIFETIME_DAYS (90) + +/** Default lifetime for an onion key in days. */ +#define DEFAULT_ONION_KEY_LIFETIME_DAYS (28) + /** How often do we rotate TLS contexts? */ #define MAX_SSL_KEY_LIFETIME_INTERNAL (2*60*60) diff --git a/src/or/router.c b/src/or/router.c index e4fa72a283..1fa0f10b7e 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -683,6 +683,31 @@ v3_authority_check_key_expiry(void) last_warned = now; } +/** Get the lifetime of an onion key in days. This value is defined by the + * network consesus parameter "onion-key-rotation-days". Always returns a value + * between MIN_ONION_KEY_LIFETIME_DAYS and + * MAX_ONION_KEY_LIFETIME_DAYS. + */ +static int +get_onion_key_rotation_days_(void) +{ + return networkstatus_get_param(NULL, + "onion-key-rotation-days", + DEFAULT_ONION_KEY_LIFETIME_DAYS, + MIN_ONION_KEY_LIFETIME_DAYS, + MAX_ONION_KEY_LIFETIME_DAYS); +} + +/** Get the current lifetime of an onion key in seconds. This value is defined + * by the network consesus parameter "onion-key-rotation-days", but the value + * is converted to seconds. + */ +int +get_onion_key_lifetime(void) +{ + return get_onion_key_rotation_days_()*24*60*60; +} + /** Set up Tor's TLS contexts, based on our configuration and keys. Return 0 * on success, and -1 on failure. */ int @@ -928,7 +953,7 @@ init_keys(void) /* We have no LastRotatedOnionKey set; either we just created the key * or it's a holdover from 0.1.2.4-alpha-dev or earlier. In either case, * start the clock ticking now so that we will eventually rotate it even - * if we don't stay up for a full MIN_ONION_KEY_LIFETIME. */ + * if we don't stay up for the full lifetime of an onion key. */ state->LastRotatedOnionKey = onionkey_set_at = now; or_state_mark_dirty(state, options->AvoidDiskWrites ? time(NULL)+3600 : 0); @@ -2760,7 +2785,7 @@ router_dump_router_to_string(routerinfo_t *router, make_ntor_onion_key_crosscert(ntor_keypair, &router->cache_info.signing_key_cert->signing_key, router->cache_info.published_on, - MIN_ONION_KEY_LIFETIME, &sign); + get_onion_key_lifetime(), &sign); if (!cert) { log_warn(LD_BUG,"make_ntor_onion_key_crosscert failed!"); goto err; diff --git a/src/or/router.h b/src/or/router.h index c30a0301b7..9060bc22c9 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -31,6 +31,7 @@ void rotate_onion_key(void); crypto_pk_t *init_key_from_file(const char *fname, int generate, int severity, int log_greeting); void v3_authority_check_key_expiry(void); +int get_onion_key_lifetime(void); di_digest256_map_t *construct_ntor_key_map(void); void ntor_key_map_free(di_digest256_map_t *map); diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 3906206696..91d6af9ce2 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -329,7 +329,7 @@ test_dir_formats(void *arg) ntor_cc = make_ntor_onion_key_crosscert(&r2_onion_keypair, &kp1.pubkey, r2->cache_info.published_on, - MIN_ONION_KEY_LIFETIME, + get_onion_key_lifetime(), &ntor_cc_sign); tt_assert(ntor_cc); base64_encode(cert_buf, sizeof(cert_buf), From d88f10cdf2cc0682e607de5f63ebae9370c5fe55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20F=C3=A6r=C3=B8y?= Date: Fri, 10 Mar 2017 12:56:36 +0100 Subject: [PATCH 3/5] Add API to query the current onion key grace period. This patch adds an API to get the current grace period, in days, defined as the consensus parameter "onion-key-grace-period-days". As per proposal #274 the values for "onion-key-grace-period-days" is a default value of 7 days, a minimum value of 1 day, and a maximum value defined by other consensus parameter "onion-key-rotation-days" also defined in days. See: https://bugs.torproject.org/21641 --- src/or/or.h | 8 ++++++++ src/or/router.c | 16 ++++++++++++++++ src/or/router.h | 1 + 3 files changed, 25 insertions(+) diff --git a/src/or/or.h b/src/or/or.h index 2903f5e283..1c4e24ea4a 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -156,6 +156,14 @@ /** Default lifetime for an onion key in days. */ #define DEFAULT_ONION_KEY_LIFETIME_DAYS (28) +/** Minimum grace period for acceptance of an onion key in days. + * The maximum value is defined in proposal #274 as being the current network + * consensus parameter for "onion-key-rotation-days". */ +#define MIN_ONION_KEY_GRACE_PERIOD_DAYS (1) + +/** Default grace period for acceptance of an onion key in days. */ +#define DEFAULT_ONION_KEY_GRACE_PERIOD_DAYS (7) + /** How often do we rotate TLS contexts? */ #define MAX_SSL_KEY_LIFETIME_INTERNAL (2*60*60) diff --git a/src/or/router.c b/src/or/router.c index 1fa0f10b7e..2985753226 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -708,6 +708,22 @@ get_onion_key_lifetime(void) return get_onion_key_rotation_days_()*24*60*60; } +/** Get the grace period of an onion key in seconds. This value is defined by + * the network consesus parameter "onion-key-grace-period-days", but the value + * is converted to seconds. + */ +int +get_onion_key_grace_period(void) +{ + int grace_period; + grace_period = networkstatus_get_param(NULL, + "onion-key-grace-period-days", + DEFAULT_ONION_KEY_GRACE_PERIOD_DAYS, + MIN_ONION_KEY_GRACE_PERIOD_DAYS, + get_onion_key_rotation_days_()); + return grace_period*24*60*60; +} + /** Set up Tor's TLS contexts, based on our configuration and keys. Return 0 * on success, and -1 on failure. */ int diff --git a/src/or/router.h b/src/or/router.h index 9060bc22c9..55a3927998 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -32,6 +32,7 @@ crypto_pk_t *init_key_from_file(const char *fname, int generate, int severity, int log_greeting); void v3_authority_check_key_expiry(void); int get_onion_key_lifetime(void); +int get_onion_key_grace_period(void); di_digest256_map_t *construct_ntor_key_map(void); void ntor_key_map_free(di_digest256_map_t *map); From 853b54dea4c56ea2913caf58ad6d337502b18b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20F=C3=A6r=C3=B8y?= Date: Fri, 10 Mar 2017 13:00:20 +0100 Subject: [PATCH 4/5] Add periodic timer for expiring old onion keys. This patch adds a new timer that is executed when it is time to expire our current set of old onion keys. Because of proposal #274 this can no longer be assumed to be at the same time we rotate our onion keys since they will be updated less frequently. See: https://bugs.torproject.org/21641 --- changes/bug21641 | 5 +++++ src/or/main.c | 29 +++++++++++++++++++++++++++++ src/or/router.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/or/router.h | 1 + 4 files changed, 80 insertions(+) create mode 100644 changes/bug21641 diff --git a/changes/bug21641 b/changes/bug21641 new file mode 100644 index 0000000000..96fdf5fe22 --- /dev/null +++ b/changes/bug21641 @@ -0,0 +1,5 @@ + o Minor feature (defaults, directory): + - Onion key rotation and expiry intervals are now defined as a network + consensus parameter as per proposal #274. The default lifetime of an + onion key is bumped from 7 to 28 days. Old onion keys will expire after 7 + days by default. Fixes bug #21641. diff --git a/src/or/main.c b/src/or/main.c index 107a4842a9..d24c674ba3 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1161,6 +1161,7 @@ static int periodic_events_initialized = 0; #define CALLBACK(name) \ static int name ## _callback(time_t, const or_options_t *) CALLBACK(rotate_onion_key); +CALLBACK(check_onion_keys_expiry_time); CALLBACK(check_ed_keys); CALLBACK(launch_descriptor_fetches); CALLBACK(rotate_x509_certificate); @@ -1192,6 +1193,7 @@ CALLBACK(heartbeat); static periodic_event_item_t periodic_events[] = { CALLBACK(rotate_onion_key), + CALLBACK(check_onion_keys_expiry_time), CALLBACK(check_ed_keys), CALLBACK(launch_descriptor_fetches), CALLBACK(rotate_x509_certificate), @@ -1499,6 +1501,33 @@ rotate_onion_key_callback(time_t now, const or_options_t *options) return PERIODIC_EVENT_NO_UPDATE; } +/* Period callback: Check if our old onion keys are still valid after the + * period of time defined by the consensus parameter + * "onion-key-grace-period-days", otherwise expire them by setting them to + * NULL. + */ +static int +check_onion_keys_expiry_time_callback(time_t now, const or_options_t *options) +{ + if (server_mode(options)) { + int onion_key_grace_period = get_onion_key_grace_period(); + time_t expiry_time = get_onion_key_set_at()+onion_key_grace_period; + + if (expiry_time > now) { + return safe_timer_diff(now, expiry_time); + } + + log_info(LD_GENERAL, "Expiring old onion keys."); + + expire_old_onion_keys(); + cpuworkers_rotate_keyinfo(); + + return onion_key_grace_period; + } + + return PERIODIC_EVENT_NO_UPDATE; +} + /* Periodic callback: Every 30 seconds, check whether it's time to make new * Ed25519 subkeys. */ diff --git a/src/or/router.c b/src/or/router.c index 2985753226..dd869d2361 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -148,6 +148,51 @@ dup_onion_keys(crypto_pk_t **key, crypto_pk_t **last) tor_mutex_release(key_lock); } +/** Expire our old set of onion keys. This is done by setting + * last_curve25519_onion_key and lastonionkey to all zero's and NULL + * respectively. + * + * This function does not perform any grace period checks for the old onion + * keys. + */ +void +expire_old_onion_keys(void) +{ + char *fname = NULL; + + tor_mutex_acquire(key_lock); + + /* Free lastonionkey and set it to NULL. */ + if (lastonionkey) { + crypto_pk_free(lastonionkey); + lastonionkey = NULL; + } + + /* We zero out the keypair. See the tor_mem_is_zero() check made in + * construct_ntor_key_map() below. */ + memset(&last_curve25519_onion_key, 0, sizeof(last_curve25519_onion_key)); + + tor_mutex_release(key_lock); + + fname = get_datadir_fname2("keys", "secret_onion_key.old"); + if (file_status(fname) == FN_FILE) { + if (tor_unlink(fname) != 0) { + log_warn(LD_FS, "Couldn't unlink old onion key file %s: %s", + fname, strerror(errno)); + } + } + tor_free(fname); + + fname = get_datadir_fname2("keys", "secret_onion_key_ntor.old"); + if (file_status(fname) == FN_FILE) { + if (tor_unlink(fname) != 0) { + log_warn(LD_FS, "Couldn't unlink old ntor onion key file %s: %s", + fname, strerror(errno)); + } + } + tor_free(fname); +} + /** Return the current secret onion key for the ntor handshake. Must only * be called from the main thread. */ static const curve25519_keypair_t * diff --git a/src/or/router.h b/src/or/router.h index 55a3927998..a02488f37a 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -27,6 +27,7 @@ crypto_pk_t *get_my_v3_authority_signing_key(void); authority_cert_t *get_my_v3_legacy_cert(void); crypto_pk_t *get_my_v3_legacy_signing_key(void); void dup_onion_keys(crypto_pk_t **key, crypto_pk_t **last); +void expire_old_onion_keys(void); void rotate_onion_key(void); crypto_pk_t *init_key_from_file(const char *fname, int generate, int severity, int log_greeting); From 946ccf3e4de883b98aa62666b8a5bdc3eb535447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20F=C3=A6r=C3=B8y?= Date: Fri, 17 Mar 2017 05:27:31 +0100 Subject: [PATCH 5/5] Check onion key consensus parameters every hour. This patch changes the way we decide when to check for whether it's time to rotate and/or expiry our onion keys. Due to proposal #274 we can now have the keys rotate at different frequencies than before and we thus do the check once an hour when our Tor daemon is running in server mode. This should allow us to quickly notice if the network consensus parameter have changed while we are running instead of having to wait until the current parameters timeout value have passed. See: See: https://bugs.torproject.org/21641 --- src/or/main.c | 11 ++++------- src/or/or.h | 4 ++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/or/main.c b/src/or/main.c index d24c674ba3..f8df5d3b9f 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1485,7 +1485,7 @@ rotate_onion_key_callback(time_t now, const or_options_t *options) int onion_key_lifetime = get_onion_key_lifetime(); time_t rotation_time = get_onion_key_set_at()+onion_key_lifetime; if (rotation_time > now) { - return safe_timer_diff(now, rotation_time); + return ONION_KEY_CONSENSUS_CHECK_INTERVAL; } log_info(LD_GENERAL,"Rotating onion key."); @@ -1496,7 +1496,7 @@ rotate_onion_key_callback(time_t now, const or_options_t *options) } if (advertised_server_mode() && !options->DisableNetwork) router_upload_dir_desc_to_dirservers(0); - return onion_key_lifetime; + return ONION_KEY_CONSENSUS_CHECK_INTERVAL; } return PERIODIC_EVENT_NO_UPDATE; } @@ -1512,17 +1512,14 @@ check_onion_keys_expiry_time_callback(time_t now, const or_options_t *options) if (server_mode(options)) { int onion_key_grace_period = get_onion_key_grace_period(); time_t expiry_time = get_onion_key_set_at()+onion_key_grace_period; - if (expiry_time > now) { - return safe_timer_diff(now, expiry_time); + return ONION_KEY_CONSENSUS_CHECK_INTERVAL; } log_info(LD_GENERAL, "Expiring old onion keys."); - expire_old_onion_keys(); cpuworkers_rotate_keyinfo(); - - return onion_key_grace_period; + return ONION_KEY_CONSENSUS_CHECK_INTERVAL; } return PERIODIC_EVENT_NO_UPDATE; diff --git a/src/or/or.h b/src/or/or.h index 1c4e24ea4a..855b234584 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -164,6 +164,10 @@ /** Default grace period for acceptance of an onion key in days. */ #define DEFAULT_ONION_KEY_GRACE_PERIOD_DAYS (7) +/** How often we should check the network consensus if it is time to rotate or + * expire onion keys. */ +#define ONION_KEY_CONSENSUS_CHECK_INTERVAL (60*60) + /** How often do we rotate TLS contexts? */ #define MAX_SSL_KEY_LIFETIME_INTERNAL (2*60*60)