This is an automated email from the git hooks/post-receive script.
dgoulet pushed a change to branch main in repository tor.
from 6afe03aa51 Merge branch 'tor-gitlab/mr/708' new 459b775a7e hs_pow: fix insufficient length check in pow-params new 71b2958a62 test_hs_descriptor: Add a test case that fails without the fix for 40793 new 0781c2968d Merge branch 'tor-gitlab/mr/710'
The 3 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "add" were already present in the repository and have only been added to this reference.
Summary of changes: src/feature/hs/hs_descriptor.c | 21 ++++++++++--- src/feature/hs/hs_descriptor.h | 7 +++++ src/test/hs_test_helpers.c | 12 ++++++++ src/test/test_hs_descriptor.c | 69 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 4 deletions(-)
This is an automated email from the git hooks/post-receive script.
dgoulet pushed a commit to branch main in repository tor.
commit 459b775a7eb5b26fb73b56c1a0f02548e53c45cc Author: Micah Elizabeth Scott beth@torproject.org AuthorDate: Mon May 15 12:11:00 2023 -0700
hs_pow: fix insufficient length check in pow-params
The descriptor validation table had an out of date minimum length for pow-params (3) whereas the spec and the current code expect at least 4 parameters. This was an opportunity for a malicious service to cause an assert failure in clients which attempted to parse its descriptor.
Addresses issue #40793
Signed-off-by: Micah Elizabeth Scott beth@torproject.org --- src/feature/hs/hs_descriptor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c index d07f900e3a..7b519e4c78 100644 --- a/src/feature/hs/hs_descriptor.c +++ b/src/feature/hs/hs_descriptor.c @@ -155,7 +155,7 @@ static token_rule_t hs_desc_encrypted_v3_token_table[] = { T01(str_intro_auth_required, R3_INTRO_AUTH_REQUIRED, GE(1), NO_OBJ), T01(str_single_onion, R3_SINGLE_ONION_SERVICE, ARGS, NO_OBJ), T01(str_flow_control, R3_FLOW_CONTROL, GE(2), NO_OBJ), - T01(str_pow_params, R3_POW_PARAMS, GE(3), NO_OBJ), + T01(str_pow_params, R3_POW_PARAMS, GE(4), NO_OBJ), END_OF_TABLE };
This is an automated email from the git hooks/post-receive script.
dgoulet pushed a commit to branch main in repository tor.
commit 71b2958a624259ac4a10a67b76a12b0064f17616 Author: Micah Elizabeth Scott beth@torproject.org AuthorDate: Wed May 17 18:33:19 2023 -0700
test_hs_descriptor: Add a test case that fails without the fix for 40793
This adds a bit more to hs_descriptor/test_decode_descriptor, mostly testing pow-params and triggering the tor_assert() in issue #40793.
There was no mechanism for adding arbitrary test strings to the encrypted portion of the desc without duplicating encode logic. One option might be to publicize get_inner_encrypted_layer_plaintext enough to add a mock implementation. In this patch I opt for what seems like the simplest solution, at the cost of a small amount of #ifdef noise. The unpacked descriptor grows a new test-only member that's used for dropping arbitrary data in at encode time.
Signed-off-by: Micah Elizabeth Scott beth@torproject.org --- src/feature/hs/hs_descriptor.c | 19 ++++++++++-- src/feature/hs/hs_descriptor.h | 7 +++++ src/test/hs_test_helpers.c | 12 ++++++++ src/test/test_hs_descriptor.c | 69 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 3 deletions(-)
diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c index 7b519e4c78..93fc1cf674 100644 --- a/src/feature/hs/hs_descriptor.c +++ b/src/feature/hs/hs_descriptor.c @@ -771,6 +771,13 @@ get_inner_encrypted_layer_plaintext(const hs_descriptor_t *desc) smartlist_add_asprintf(lines, "%s %d\n", str_create2_formats, ONION_HANDSHAKE_TYPE_NTOR);
+#ifdef TOR_UNIT_TESTS + if (desc->encrypted_data.test_extra_plaintext) { + smartlist_add(lines, + tor_strdup(desc->encrypted_data.test_extra_plaintext)); + } +#endif + if (desc->encrypted_data.intro_auth_types && smartlist_len(desc->encrypted_data.intro_auth_types)) { /* Put the authentication-required line. */ @@ -2817,9 +2824,15 @@ hs_desc_encode_descriptor,(const hs_descriptor_t *desc, }
/* Try to decode what we just encoded. Symmetry is nice!, but it is - * symmetric only if the client auth is disabled. That is, the descriptor - * cookie will be NULL. */ - if (!descriptor_cookie) { + * symmetric only if the client auth is disabled (That is, the descriptor + * cookie will be NULL) and the test-only mock plaintext isn't in use. */ + bool do_round_trip_test = !descriptor_cookie; +#ifdef TOR_UNIT_TESTS + if (desc->encrypted_data.test_extra_plaintext) { + do_round_trip_test = false; + } +#endif + if (do_round_trip_test) { ret = hs_desc_decode_descriptor(*encoded_out, &desc->subcredential, NULL, NULL); if (BUG(ret != HS_DESC_DECODE_OK)) { diff --git a/src/feature/hs/hs_descriptor.h b/src/feature/hs/hs_descriptor.h index c89dc0b580..ca87972de1 100644 --- a/src/feature/hs/hs_descriptor.h +++ b/src/feature/hs/hs_descriptor.h @@ -177,6 +177,13 @@ typedef struct hs_desc_encrypted_data_t {
/** A list of intro points. Contains hs_desc_intro_point_t objects. */ smartlist_t *intro_points; + +#ifdef TOR_UNIT_TESTS + /** In unit tests only, we can include additional arbitrary plaintext. + * This is used to test parser validation by adding invalid inner data to + * descriptors that are otherwise correct and correctly encrypted. */ + const char *test_extra_plaintext; +#endif } hs_desc_encrypted_data_t;
/** The superencrypted data section of a descriptor. Obviously the data in diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c index 20b225ba4a..4ef2398095 100644 --- a/src/test/hs_test_helpers.c +++ b/src/test/hs_test_helpers.c @@ -354,6 +354,18 @@ hs_helper_desc_equal(const hs_descriptor_t *desc1, } }
+ /* Proof of Work DoS mitigation options */ + tt_int_op(!!desc1->encrypted_data.pow_params, OP_EQ, + !!desc2->encrypted_data.pow_params); + if (desc1->encrypted_data.pow_params && desc2->encrypted_data.pow_params) { + hs_pow_desc_params_t *params1 = desc1->encrypted_data.pow_params; + hs_pow_desc_params_t *params2 = desc2->encrypted_data.pow_params; + tt_int_op(params1->type, OP_EQ, params2->type); + tt_mem_op(params1->seed, OP_EQ, params2->seed, HS_POW_SEED_LEN); + tt_int_op(params1->suggested_effort, OP_EQ, params2->suggested_effort); + tt_int_op(params1->expiration_time, OP_EQ, params2->expiration_time); + } + /* Introduction points. */ { tt_assert(desc1->encrypted_data.intro_points); diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c index 469e3c39f9..d96048a0f6 100644 --- a/src/test/test_hs_descriptor.c +++ b/src/test/test_hs_descriptor.c @@ -364,6 +364,75 @@ test_decode_descriptor(void *arg) hs_helper_desc_equal(desc, decoded); }
+ /* Decode a descriptor without auth clients, and with PoW data added via + * test_extra_plaintext to test both the normal case of PoW decoding and the + * extra plaintext mechanism itself. */ + { + tor_assert(!desc->encrypted_data.pow_params); + + char pow_seed_base64[HS_POW_SEED_LEN*2]; + uint8_t pow_seed[HS_POW_SEED_LEN]; + crypto_strongest_rand(pow_seed, sizeof pow_seed); + tt_int_op(base64_encode_nopad(pow_seed_base64, sizeof pow_seed_base64, + pow_seed, sizeof pow_seed), OP_GT, 0); + + time_t expiration_time = time(NULL); + char time_buf[ISO_TIME_LEN + 1]; + format_iso_time_nospace(time_buf, expiration_time); + + const unsigned suggested_effort = 123456; + char *extra_plaintext = NULL; + tor_asprintf(&extra_plaintext, + "pow-params v1 %s %u %s\n", + pow_seed_base64, suggested_effort, time_buf); + + tor_free(encoded); + desc->encrypted_data.test_extra_plaintext = extra_plaintext; + ret = hs_desc_encode_descriptor(desc, &signing_kp, NULL, &encoded); + tor_free(extra_plaintext); + desc->encrypted_data.test_extra_plaintext = extra_plaintext; + + tt_int_op(ret, OP_EQ, 0); + tt_assert(encoded); + + desc->encrypted_data.pow_params = + tor_malloc_zero(sizeof(hs_pow_desc_params_t)); + desc->encrypted_data.pow_params->type = HS_POW_DESC_V1; + memcpy(desc->encrypted_data.pow_params->seed, pow_seed, HS_POW_SEED_LEN); + desc->encrypted_data.pow_params->suggested_effort = suggested_effort; + desc->encrypted_data.pow_params->expiration_time = expiration_time; + + hs_descriptor_free(decoded); + ret = hs_desc_decode_descriptor(encoded, &subcredential, NULL, &decoded); + tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK); + tt_assert(decoded); + + hs_helper_desc_equal(desc, decoded); + + tor_free(desc->encrypted_data.pow_params); + } + + /* Now a version of the above that's expected to fail. This reproduces the + * issue from ticket tor#40793, in which pow_params gets too few parameters + * but this would cause an assert instead of an early validation fail. + * Make sure it fails to parse. Prior to the fix for #40793 this fails + * an assertion instead. */ + { + tor_free(encoded); + tor_assert(!desc->encrypted_data.pow_params); + desc->encrypted_data.test_extra_plaintext = "pow-params v1 a a\n"; + ret = hs_desc_encode_descriptor(desc, &signing_kp, NULL, &encoded); + desc->encrypted_data.test_extra_plaintext = NULL; + + tt_int_op(ret, OP_EQ, 0); + tt_assert(encoded); + + hs_descriptor_free(decoded); + ret = hs_desc_decode_descriptor(encoded, &subcredential, NULL, &decoded); + tt_int_op(ret, OP_EQ, HS_DESC_DECODE_ENCRYPTED_ERROR); + tt_assert(!decoded); + } + done: hs_descriptor_free(desc); hs_descriptor_free(desc_no_ip);
This is an automated email from the git hooks/post-receive script.
dgoulet pushed a commit to branch main in repository tor.
commit 0781c2968d26fba999a00c3989c10964f492f9dc Merge: 6afe03aa51 71b2958a62 Author: David Goulet dgoulet@torproject.org AuthorDate: Wed May 24 11:12:22 2023 -0400
Merge branch 'tor-gitlab/mr/710'
src/feature/hs/hs_descriptor.c | 21 ++++++++++--- src/feature/hs/hs_descriptor.h | 7 +++++ src/test/hs_test_helpers.c | 12 ++++++++ src/test/test_hs_descriptor.c | 69 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 4 deletions(-)
tor-commits@lists.torproject.org