From 4a754ae76ad8e08edc64cffb408c59c557c0b462 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 28 Mar 2023 15:08:15 +0100 Subject: [PATCH 1/3] tor-dirclient: Provide HsDescDownloadRequest In my tests this seems to do the right thing, but I'm getting 404s. I'm not sure if actually this URL is wrong. --- Cargo.lock | 1 + crates/tor-dirclient/Cargo.toml | 3 ++ crates/tor-dirclient/src/request.rs | 43 +++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 4164deda2..3326a9352 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3865,6 +3865,7 @@ dependencies = [ "thiserror", "tor-circmgr", "tor-error", + "tor-hscrypto", "tor-linkspec", "tor-llcrypto", "tor-netdoc", diff --git a/crates/tor-dirclient/Cargo.toml b/crates/tor-dirclient/Cargo.toml index 17fb9f83b..97a1b909c 100644 --- a/crates/tor-dirclient/Cargo.toml +++ b/crates/tor-dirclient/Cargo.toml @@ -13,6 +13,8 @@ repository = "https://gitlab.torproject.org/tpo/core/arti.git/" [features] default = ["xz", "zstd"] +# Enable support for hidden service descriptor downloads. +hs-client = ["tor-hscrypto"] xz = ["async-compression/xz"] zstd = ["async-compression/zstd"] # Enable support for router descriptor downloads. @@ -32,6 +34,7 @@ memchr = "2" thiserror = "1" tor-circmgr = { path = "../tor-circmgr", version = "0.7.3" } tor-error = { path = "../tor-error", version = "0.4.1" } +tor-hscrypto = { path = "../tor-hscrypto", version = "0.1.2", optional = true } tor-linkspec = { path = "../tor-linkspec", version = "0.6.3" } tor-llcrypto = { path = "../tor-llcrypto", version = "0.4.3" } tor-netdoc = { path = "../tor-netdoc", version = "0.6.3" } diff --git a/crates/tor-dirclient/src/request.rs b/crates/tor-dirclient/src/request.rs index b735a6471..7ceb853b7 100644 --- a/crates/tor-dirclient/src/request.rs +++ b/crates/tor-dirclient/src/request.rs @@ -9,6 +9,9 @@ use tor_netdoc::doc::netstatus::ConsensusFlavor; use tor_netdoc::doc::routerdesc::RdDigest; use tor_proto::circuit::ClientCirc; +#[cfg(feature = "hs-client")] +use tor_hscrypto::pk::HsBlindId; + /// Alias for a result with a `RequestError`. type Result = std::result::Result; @@ -485,6 +488,46 @@ impl Requestable for RoutersOwnDescRequest { } } +/// A request to download a hidden service descriptor +/// +/// rend-spec-v3 2.2.6 +#[derive(Debug, Clone)] +#[cfg(feature = "hs-client")] +pub struct HsDescDownloadRequest { + /// What hidden service? + hsid: HsBlindId, +} + +#[cfg(feature = "hs-client")] +impl HsDescDownloadRequest { + /// Construct a request for all router descriptors. + pub fn new(hsid: HsBlindId) -> Self { + HsDescDownloadRequest { hsid } + } +} + +#[cfg(feature = "hs-client")] +impl Requestable for HsDescDownloadRequest { + fn make_request(&self) -> Result> { + // TODO HS this should have a unit test + let hsid = Base64Unpadded::encode_string(self.hsid.as_ref()); + // TODO HS: is it OK to hardcode the version for now? + let uri = format!("/tor/hs/3/{}", hsid); + let req = http::Request::builder().method("GET").uri(uri); + let req = add_common_headers(req); + Ok(req.body(())?) + } + + fn partial_docs_ok(&self) -> bool { + false + } + + fn max_response_len(&self) -> usize { + // rend-spec-v3 2.5.1.4 + // TODO HS: spec says this should be a consensus parameter, but we have no netdir here + 50 * 1024 + } +} /// List the encodings we accept fn encodings() -> String { #[allow(unused_mut)] From 91b3b79fed6bca0728c4a0cebf502b0cd0325b7c Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Fri, 31 Mar 2023 17:38:43 +0100 Subject: [PATCH 2/3] tor-dirclient: Add test case for HsDescDownloadRequest I couldn't find a test vector in C Tor. This test case was generated from the code here. I'm fairly sure it's right since I managed to get my descriptor downloader to work. (That's not an MR yet, but uses this code.) --- crates/tor-dirclient/src/request.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/crates/tor-dirclient/src/request.rs b/crates/tor-dirclient/src/request.rs index 7ceb853b7..a20cac9da 100644 --- a/crates/tor-dirclient/src/request.rs +++ b/crates/tor-dirclient/src/request.rs @@ -509,7 +509,6 @@ impl HsDescDownloadRequest { #[cfg(feature = "hs-client")] impl Requestable for HsDescDownloadRequest { fn make_request(&self) -> Result> { - // TODO HS this should have a unit test let hsid = Base64Unpadded::encode_string(self.hsid.as_ref()); // TODO HS: is it OK to hardcode the version for now? let uri = format!("/tor/hs/3/{}", hsid); @@ -565,6 +564,7 @@ mod test { #![allow(clippy::unchecked_duration_subtraction)] //! use super::*; + use tor_llcrypto::pk::ed25519::Ed25519Identity; #[test] fn test_md_request() -> Result<()> { @@ -713,4 +713,24 @@ mod test { assert_eq!(req, req2); Ok(()) } + + #[test] + #[cfg(feature = "hs-client")] + fn test_hs_desc_download_request() -> Result<()> { + let hsid = [1, 2, 3, 4].iter().cycle().take(32).cloned().collect_vec(); + let hsid = Ed25519Identity::new(hsid[..].try_into().unwrap()); + let hsid = HsBlindId::from(hsid); + let req = HsDescDownloadRequest::new(hsid); + assert!(!req.partial_docs_ok()); + assert_eq!(req.max_response_len(), 50 * 1024); + + let req = crate::util::encode_request(&req.make_request()?); + + assert_eq!( + req, + format!("GET /tor/hs/3/AQIDBAECAwQBAgMEAQIDBAECAwQBAgMEAQIDBAECAwQ HTTP/1.0\r\naccept-encoding: {}\r\n\r\n", encodings()) + ); + + Ok(()) + } } From fd13a26a00e4ceb1c26ec112101c109573c88bee Mon Sep 17 00:00:00 2001 From: gabi-250 Date: Thu, 30 Mar 2023 16:05:51 +0000 Subject: [PATCH 3/3] tor-dirclient: Add a comment about 50 x 1024 --- crates/tor-dirclient/src/request.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/tor-dirclient/src/request.rs b/crates/tor-dirclient/src/request.rs index a20cac9da..364f008cc 100644 --- a/crates/tor-dirclient/src/request.rs +++ b/crates/tor-dirclient/src/request.rs @@ -524,6 +524,7 @@ impl Requestable for HsDescDownloadRequest { fn max_response_len(&self) -> usize { // rend-spec-v3 2.5.1.4 // TODO HS: spec says this should be a consensus parameter, but we have no netdir here + // 50 KiB 50 * 1024 } }