From 542402cd60bc6b26f43c399b238602a1f3c18d85 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 28 May 2019 13:49:03 -0400 Subject: [PATCH] hs-v3: Set extended error when missing/bad client auth Part of #30382 Signed-off-by: David Goulet --- src/feature/dirclient/dirclient.c | 39 +++++++++++++++++++++++-------- src/feature/hs/hs_client.c | 31 ++++++++++++++++++++++++ src/feature/hs/hs_client.h | 2 ++ 3 files changed, 62 insertions(+), 10 deletions(-) diff --git a/src/feature/dirclient/dirclient.c b/src/feature/dirclient/dirclient.c index 64205a44e3..abece62dd4 100644 --- a/src/feature/dirclient/dirclient.c +++ b/src/feature/dirclient/dirclient.c @@ -2734,21 +2734,40 @@ handle_response_fetch_hsdesc_v3(dir_connection_t *conn, /* We got something: Try storing it in the cache. */ decode_status = hs_cache_store_as_client(body, &conn->hs_ident->identity_pk); - if (decode_status != HS_DESC_DECODE_OK) { - log_info(LD_REND, "Failed to store hidden service descriptor"); + switch (decode_status) { + case HS_DESC_DECODE_OK: + case HS_DESC_DECODE_NEED_CLIENT_AUTH: + case HS_DESC_DECODE_BAD_CLIENT_AUTH: + log_info(LD_REND, "Stored hidden service descriptor successfully."); + TO_CONN(conn)->purpose = DIR_PURPOSE_HAS_FETCHED_HSDESC; + if (decode_status == HS_DESC_DECODE_OK) { + hs_client_desc_has_arrived(conn->hs_ident); + } else { + /* This handles both client auth decode status. */ + hs_client_desc_missing_bad_client_auth(conn->hs_ident, decode_status); + log_info(LD_REND, "Stored hidden service descriptor requires " + "%s client authorization.", + decode_status == HS_DESC_DECODE_NEED_CLIENT_AUTH ? "missing" + : "new"); + } + /* Fire control port RECEIVED event. */ + hs_control_desc_event_received(conn->hs_ident, conn->identity_digest); + hs_control_desc_event_content(conn->hs_ident, conn->identity_digest, + body); + break; + case HS_DESC_DECODE_ENCRYPTED_ERROR: + case HS_DESC_DECODE_SUPERENC_ERROR: + case HS_DESC_DECODE_PLAINTEXT_ERROR: + case HS_DESC_DECODE_GENERIC_ERROR: + default: + log_info(LD_REND, "Failed to store hidden service descriptor. " + "Descriptor decoding status: %d", decode_status); /* Fire control port FAILED event. */ hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest, "BAD_DESC"); hs_control_desc_event_content(conn->hs_ident, conn->identity_digest, NULL); - } else { - log_info(LD_REND, "Stored hidden service descriptor successfully."); - TO_CONN(conn)->purpose = DIR_PURPOSE_HAS_FETCHED_HSDESC; - hs_client_desc_has_arrived(conn->hs_ident); - /* Fire control port RECEIVED event. */ - hs_control_desc_event_received(conn->hs_ident, conn->identity_digest); - hs_control_desc_event_content(conn->hs_ident, conn->identity_digest, - body); + break; } break; case 404: diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c index 0e4df73b9f..0a10492e07 100644 --- a/src/feature/hs/hs_client.c +++ b/src/feature/hs/hs_client.c @@ -1782,6 +1782,37 @@ hs_client_desc_not_found(const hs_ident_dir_conn_t *ident) smartlist_free(entry_conns); } +/* This is called when a descriptor fetch was successful but the descriptor + * couldn't be decrypted due to missing or bad client authorization. */ +void +hs_client_desc_missing_bad_client_auth(const hs_ident_dir_conn_t *ident, + hs_desc_decode_status_t status) +{ + smartlist_t *entry_conns; + + tor_assert(ident); + + entry_conns = find_entry_conns(&ident->identity_pk); + + SMARTLIST_FOREACH_BEGIN(entry_conns, entry_connection_t *, entry_conn) { + socks5_reply_status_t code; + if (status == HS_DESC_DECODE_BAD_CLIENT_AUTH) { + code = SOCKS5_HS_BAD_CLIENT_AUTH; + } else if (status == HS_DESC_DECODE_NEED_CLIENT_AUTH) { + code = SOCKS5_HS_MISSING_CLIENT_AUTH; + } else { + /* We should not be called with another type of status. Recover by + * sending a generic error. */ + tor_assert_nonfatal_unreached(); + code = HS_DESC_DECODE_GENERIC_ERROR; + } + entry_conn->socks_request->socks_extended_error_code = code; + } SMARTLIST_FOREACH_END(entry_conn); + + /* We don't have ownership of the objects in this list. */ + smartlist_free(entry_conns); +} + /** Return a newly allocated extend_info_t for a randomly chosen introduction * point for the given edge connection identifier ident. Return NULL if we * can't pick any usable introduction points. */ diff --git a/src/feature/hs/hs_client.h b/src/feature/hs/hs_client.h index 6bd6e5748f..616d31a011 100644 --- a/src/feature/hs/hs_client.h +++ b/src/feature/hs/hs_client.h @@ -74,6 +74,8 @@ int hs_client_receive_rendezvous2(origin_circuit_t *circ, void hs_client_desc_has_arrived(const hs_ident_dir_conn_t *ident); void hs_client_desc_not_found(const hs_ident_dir_conn_t *ident); +void hs_client_desc_missing_bad_client_auth(const hs_ident_dir_conn_t *ident, + hs_desc_decode_status_t status); extend_info_t *hs_client_get_random_intro_from_edge( const edge_connection_t *edge_conn);