From 2834cc9c18230c36278ffa94a252abeb91b6cff9 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sat, 11 Nov 2017 13:40:21 -0500 Subject: [PATCH 1/7] Fix length of replaycache-checked data. This is a regression; we should have been checking only the public-key encrypted portion. Fixes bug 24244, TROVE-2017-009, and CVE-2017-8819. --- changes/trove-2017-009 | 10 ++++++++++ src/or/rendservice.c | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 changes/trove-2017-009 diff --git a/changes/trove-2017-009 b/changes/trove-2017-009 new file mode 100644 index 000000000..512d18c29 --- /dev/null +++ b/changes/trove-2017-009 @@ -0,0 +1,10 @@ + o Major fixes (security): + - When checking for replays in the INTRODUCE1 cell data for a (legacy) + hiddden service, correctly detect replays in the RSA-encrypted part of + the cell. We were previously checking for replays on the entire cell, + but those can be circumvented due to the malleability of Tor's legacy + hybrid encryption. This fix helps prevent a traffic confirmation + attack. Fixes bug 24244; bugfix on 0.2.4.1-alpha. This issue is also + tracked as TROVE-2017-009 and CVE-2017-8819. + + diff --git a/src/or/rendservice.c b/src/or/rendservice.c index d958de9df..ba8891ead 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -1162,6 +1162,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, time_t now = time(NULL); time_t elapsed; int replay; + size_t keylen; /* Do some initial validation and logging before we parse the cell */ if (circuit->base_.purpose != CIRCUIT_PURPOSE_S_INTRO) { @@ -1245,9 +1246,10 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request, } /* check for replay of PK-encrypted portion. */ + keylen = crypto_pk_keysize(intro_key); replay = replaycache_add_test_and_elapsed( intro_point->accepted_intro_rsa_parts, - parsed_req->ciphertext, parsed_req->ciphertext_len, + parsed_req->ciphertext, MIN(parsed_req->ciphertext_len, keylen), &elapsed); if (replay) { From 2c0487ecfb410d1361b114e60d8e9ffd2ed092ec Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sat, 11 Nov 2017 13:56:35 -0500 Subject: [PATCH 2/7] Handle NULL input to protover_compute_for_old_tor() Fixes bug 24245; bugfix on 0.2.9.4-alpha. TROVE-2017-010. --- changes/trove-2017-010 | 6 ++++++ src/or/protover.c | 5 +++++ 2 files changed, 11 insertions(+) create mode 100644 changes/trove-2017-010 diff --git a/changes/trove-2017-010 b/changes/trove-2017-010 new file mode 100644 index 000000000..d5bf9333d --- /dev/null +++ b/changes/trove-2017-010 @@ -0,0 +1,6 @@ + o Major bugfixes (security): + - Fix a denial-of-service issue where an attacker could crash + a directory authority using a malformed router descriptor. + Fixes bug 24245; bugfix on 0.2.9.4-alpha. Also tracked + as TROVE-2017-010 and CVE-2017-8820. + diff --git a/src/or/protover.c b/src/or/protover.c index 0a4d4fb8f..98957cabd 100644 --- a/src/or/protover.c +++ b/src/or/protover.c @@ -694,6 +694,11 @@ protocol_list_contains(const smartlist_t *protos, const char * protover_compute_for_old_tor(const char *version) { + if (version == NULL) { + /* No known version; guess the oldest series that is still supported. */ + version = "0.2.5.15"; + } + if (tor_version_as_new_as(version, FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS)) { return ""; From 1880a6a88e240556a8e6b169f1160aa8220ab0ec Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sat, 11 Nov 2017 14:21:37 -0500 Subject: [PATCH 3/7] Avoid asking for passphrase on junky PEM input Fixes bug 24246 and TROVE-2017-011. This bug is so old, it's in Matej's code. Seems to have been introduced with e01522bbed6eea. --- changes/trove-2017-011 | 8 ++++++++ src/common/crypto.c | 16 +++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 changes/trove-2017-011 diff --git a/changes/trove-2017-011 b/changes/trove-2017-011 new file mode 100644 index 000000000..82d20d9e7 --- /dev/null +++ b/changes/trove-2017-011 @@ -0,0 +1,8 @@ + o Major bugfixes (security): + - Fix a denial of service bug where an attacker could use a malformed + directory object to cause a Tor instance to pause while OpenSSL would + try to read a passphrase from the terminal. (If the terminal was not + available, tor would continue running.) Fixes bug 24246; bugfix on + every version of Tor. Also tracked as TROVE-2017-011 and + CVE-2017-8821. Found by OSS-Fuzz as testcase 6360145429790720. + diff --git a/src/common/crypto.c b/src/common/crypto.c index f7362765d..8d816652d 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -592,11 +592,21 @@ crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits) return 0; } +/** A PEM callback that always reports a failure to get a password */ +static int +pem_no_password_cb(char *buf, int size, int rwflag, void *u) +{ + (void)buf; + (void)size; + (void)rwflag; + (void)u; + return 0; +} + /** Read a PEM-encoded private key from the len-byte string s * into env. Return 0 on success, -1 on failure. If len is -1, * the string is nul-terminated. */ -/* Used here, and used for testing. */ int crypto_pk_read_private_key_from_string(crypto_pk_t *env, const char *s, ssize_t len) @@ -615,7 +625,7 @@ crypto_pk_read_private_key_from_string(crypto_pk_t *env, if (env->key) RSA_free(env->key); - env->key = PEM_read_bio_RSAPrivateKey(b,NULL,NULL,NULL); + env->key = PEM_read_bio_RSAPrivateKey(b,NULL,pem_no_password_cb,NULL); BIO_free(b); @@ -747,7 +757,7 @@ crypto_pk_read_public_key_from_string(crypto_pk_t *env, const char *src, if (env->key) RSA_free(env->key); - env->key = PEM_read_bio_RSAPublicKey(b, NULL, NULL, NULL); + env->key = PEM_read_bio_RSAPublicKey(b, NULL, pem_no_password_cb, NULL); BIO_free(b); if (!env->key) { crypto_log_errors(LOG_WARN, "reading public key from string"); From 3030741b5d24e9ae36e6d72c6a8c7d035fde9d2a Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 21 Nov 2017 10:16:08 -0500 Subject: [PATCH 4/7] hs-v2: Remove any expiring intro from the retry list TROVE-2017-13. Severity: High. In the unlikely case that a hidden service could be missing intro circuit(s), that it didn't have enough directory information to open new circuits and that an intro point was about to expire, a use-after-free is possible because of the intro point object being both in the retry list and expiring list at the same time. The intro object would get freed after the circuit failed to open and then access a second time when cleaned up from the expiring list. Fixes #24313 --- changes/bug24313 | 5 +++++ src/or/rendservice.c | 4 ++++ 2 files changed, 9 insertions(+) create mode 100644 changes/bug24313 diff --git a/changes/bug24313 b/changes/bug24313 new file mode 100644 index 000000000..b927ec3ba --- /dev/null +++ b/changes/bug24313 @@ -0,0 +1,5 @@ + o Major bugfixes (security, hidden service v2): + - Fix a use-after-free error that could crash v2 Tor hidden services + when it failed to open circuits while expiring introductions + points. Fixes bug 24313; bugfix on 0.2.7.2-alpha. This + issue is also tracked as TROVE-2017-013 and CVE-2017-8823. diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 0a5b5efd5..cbf998136 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -3444,6 +3444,10 @@ remove_invalid_intro_points(rend_service_t *service, log_info(LD_REND, "Expiring %s as intro point for %s.", safe_str_client(extend_info_describe(intro->extend_info)), safe_str_client(service->service_id)); + /* We might have put it in the retry list if so, undo. */ + if (retry_nodes) { + smartlist_remove(retry_nodes, intro); + } smartlist_add(service->expiring_nodes, intro); SMARTLIST_DEL_CURRENT(service->intro_nodes, intro); /* Intro point is expired, we need a new one thus don't consider it From 91cee3c9e73aba089804cd88305115fc3ab1f76c Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 28 Nov 2017 19:09:13 -0500 Subject: [PATCH 5/7] Guard: Don't pick ourselves as a possible Guard TROVE-2017-12. Severity: Medium Thankfully, tor will close any circuits that we try to extend to ourselves so this is not problematic but annoying. Part of #21534. --- changes/trove-2017-012-part2 | 5 +++++ src/or/entrynodes.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 changes/trove-2017-012-part2 diff --git a/changes/trove-2017-012-part2 b/changes/trove-2017-012-part2 new file mode 100644 index 000000000..ed994c5b0 --- /dev/null +++ b/changes/trove-2017-012-part2 @@ -0,0 +1,5 @@ + o Major bugfixes (security, relay): + - When running as a relay, make sure that we never ever choose ourselves + as a guard. Previously, this was possible. Fixes part of bug 21534; + bugfix on 0.3.0.1-alpha. This issue is also tracked as TROVE-2017-012 + and CVE-2017-8822. diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index d762afdcf..0109da8e0 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -740,7 +740,8 @@ node_is_possible_guard(const node_t *node) node->is_stable && node->is_fast && node->is_valid && - node_is_dir(node)); + node_is_dir(node) && + !router_digest_is_me(node->identity)); } /** From 6ab07419c88e35c6d8610e20fb3cea16e39c8acd Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 28 Nov 2017 19:02:00 -0500 Subject: [PATCH 6/7] Use local descriptor object to exclude self in path selection TROVE-2017-12. Severity: Medium When choosing a random node for a circuit, directly use our router descriptor to exclude ourself instead of the one in the global descriptor list. That list could be empty because tor could be downloading them which could lead to not excluding ourself. Closes #21534 --- changes/trove-2017-012-part1 | 6 ++++++ src/or/routerlist.c | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 changes/trove-2017-012-part1 diff --git a/changes/trove-2017-012-part1 b/changes/trove-2017-012-part1 new file mode 100644 index 000000000..9fccc2cf6 --- /dev/null +++ b/changes/trove-2017-012-part1 @@ -0,0 +1,6 @@ + o Major bugfixes (security, relay): + - When running as a relay, make sure that we never build a path through + ourselves, even in the case where we have somehow lost the version of + our descriptor appearing in the consensus. Fixes part of bug 21534; + bugfix on 0.2.0.1-alpha. This issue is also tracked as TROVE-2017-012 + and CVE-2017-8822. diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 07e87724b..3bf1eb895 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -2411,7 +2411,10 @@ router_choose_random_node(smartlist_t *excludedsmartlist, }); } - if ((r = routerlist_find_my_routerinfo())) + /* If the node_t is not found we won't be to exclude ourself but we + * won't be able to pick ourself in router_choose_random_node() so + * this is fine to at least try with our routerinfo_t object. */ + if ((r = router_get_my_routerinfo())) routerlist_add_node_and_family(excludednodes, r); router_add_running_nodes_to_smartlist(sl, allow_invalid, From 75509dc82778a3bb866dca0fa86ae3e179ad78fa Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 30 Nov 2017 11:52:40 -0500 Subject: [PATCH 7/7] Fix changes file --- changes/trove-2017-009 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changes/trove-2017-009 b/changes/trove-2017-009 index 512d18c29..166a5faec 100644 --- a/changes/trove-2017-009 +++ b/changes/trove-2017-009 @@ -1,4 +1,4 @@ - o Major fixes (security): + o Major bugfixes (security): - When checking for replays in the INTRODUCE1 cell data for a (legacy) hiddden service, correctly detect replays in the RSA-encrypted part of the cell. We were previously checking for replays on the entire cell,