diff options
author | Nick Mathewson <nickm@torproject.org> | 2015-02-20 01:08:12 -0500 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2015-02-20 01:08:12 -0500 |
commit | 8a9d86bf05110426e05c5dde4b22e45dfa99f8e9 (patch) | |
tree | 89a61fdc3ea13d597b9f913e8b28af1a261bf7d9 | |
parent | 03a4e97c76b2021ec7246da03fb31d337fb50f9b (diff) | |
parent | 69df16e3765383bd59fd2fbedbb5301f3b58ab14 (diff) | |
download | tor-8a9d86bf05110426e05c5dde4b22e45dfa99f8e9.tar.gz tor-8a9d86bf05110426e05c5dde4b22e45dfa99f8e9.zip |
Merge remote-tracking branch 'public/bug11454_11457'
-rw-r--r-- | changes/bug11454 | 6 | ||||
-rw-r--r-- | changes/bug11457 | 5 | ||||
-rw-r--r-- | src/common/container.h | 11 | ||||
-rw-r--r-- | src/or/routerlist.c | 73 |
4 files changed, 68 insertions, 27 deletions
diff --git a/changes/bug11454 b/changes/bug11454 new file mode 100644 index 0000000000..da793de868 --- /dev/null +++ b/changes/bug11454 @@ -0,0 +1,6 @@ + o Minor bugfixes: + - Remove any old authority certificates that have been superseded + for at least two days. Previously, we would keep superseded + certificates until they expired, if they were published close + in time to the certificate that superseded them. + Fixes bug 11454; bugfix on 0.2.1.8-alpha. diff --git a/changes/bug11457 b/changes/bug11457 new file mode 100644 index 0000000000..a8b76f6d78 --- /dev/null +++ b/changes/bug11457 @@ -0,0 +1,5 @@ + o Minor bugfixes: + - If an authority operator accidentally makes a signing certificate with + a future publication time, do not discard its real signing + certificates. Fixes bug 11457; bugfix on 0.2.0.3-alpha. + diff --git a/src/common/container.h b/src/common/container.h index 6edc80f75b..d07697f019 100644 --- a/src/common/container.h +++ b/src/common/container.h @@ -247,6 +247,17 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join, STMT_END /** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed + * with the variable <b>var</b>, remove the current element in a way that + * won't confuse the loop. */ +#define SMARTLIST_DEL_CURRENT_KEEPORDER(sl, var) \ + STMT_BEGIN \ + smartlist_del_keeporder(sl, var ## _sl_idx); \ + --var ## _sl_idx; \ + --var ## _sl_len; \ + STMT_END + + +/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed * with the variable <b>var</b>, replace the current element with <b>val</b>. * Does not deallocate the current value of <b>var</b>. */ diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 375732a310..f4f6200bbc 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -449,6 +449,19 @@ trusted_dirs_flush_certs_to_disk(void) trusted_dir_servers_certs_changed = 0; } +static int +compare_certs_by_pubdates(const void **_a, const void **_b) +{ + const authority_cert_t *cert1 = *_a, *cert2=*_b; + + if (cert1->cache_info.published_on < cert2->cache_info.published_on) + return -1; + else if (cert1->cache_info.published_on > cert2->cache_info.published_on) + return 1; + else + return 0; +} + /** Remove all expired v3 authority certificates that have been superseded for * more than 48 hours or, if not expired, that were published more than 7 days * before being superseded. (If the most recent cert was published more than 48 @@ -459,38 +472,44 @@ trusted_dirs_remove_old_certs(void) { time_t now = time(NULL); #define DEAD_CERT_LIFETIME (2*24*60*60) -#define OLD_CERT_LIFETIME (7*24*60*60) +#define SUPERSEDED_CERT_LIFETIME (2*24*60*60) if (!trusted_dir_certs) return; DIGESTMAP_FOREACH(trusted_dir_certs, key, cert_list_t *, cl) { - authority_cert_t *newest = NULL; - SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert, - if (!newest || (cert->cache_info.published_on > - newest->cache_info.published_on)) - newest = cert); - if (newest) { - const time_t newest_published = newest->cache_info.published_on; - SMARTLIST_FOREACH_BEGIN(cl->certs, authority_cert_t *, cert) { - int expired; - time_t cert_published; - if (newest == cert) - continue; - /* resolve spurious clang shallow analysis null pointer errors */ - tor_assert(cert); - expired = now > cert->expires; - cert_published = cert->cache_info.published_on; - /* Store expired certs for 48 hours after a newer arrives; + /* Sort the list from first-published to last-published */ + smartlist_sort(cl->certs, compare_certs_by_pubdates); + + SMARTLIST_FOREACH_BEGIN(cl->certs, authority_cert_t *, cert) { + if (cert_sl_idx == smartlist_len(cl->certs) - 1) { + /* This is the most recently published cert. Keep it. */ + continue; + } + authority_cert_t *next_cert = smartlist_get(cl->certs, cert_sl_idx+1); + const time_t next_cert_published = next_cert->cache_info.published_on; + if (next_cert_published > now) { + /* All later certs are published in the future. Keep everything + * we didn't discard. */ + break; + } + int should_remove = 0; + if (cert->expires + DEAD_CERT_LIFETIME < now) { + /* Certificate has been expired for at least DEAD_CERT_LIFETIME. + * Remove it. */ + should_remove = 1; + } else if (next_cert_published + SUPERSEDED_CERT_LIFETIME < now) { + /* Certificate has been superseded for OLD_CERT_LIFETIME. + * Remove it. */ - if (expired ? - (newest_published + DEAD_CERT_LIFETIME < now) : - (cert_published + OLD_CERT_LIFETIME < newest_published)) { - SMARTLIST_DEL_CURRENT(cl->certs, cert); - authority_cert_free(cert); - trusted_dir_servers_certs_changed = 1; - } - } SMARTLIST_FOREACH_END(cert); - } + should_remove = 1; + } + if (should_remove) { + SMARTLIST_DEL_CURRENT_KEEPORDER(cl->certs, cert); + authority_cert_free(cert); + trusted_dir_servers_certs_changed = 1; + } + } SMARTLIST_FOREACH_END(cert); + } DIGESTMAP_FOREACH_END; #undef DEAD_CERT_LIFETIME #undef OLD_CERT_LIFETIME |