From 30983c764f6a646782f51fd540f205dba0347933 Mon Sep 17 00:00:00 2001 From: Gabriela Moldovan Date: Wed, 26 Apr 2023 18:25:05 +0100 Subject: [PATCH] tor-netdir: Update tests to parse the descriptor, make test consensus lifetime configurable. Signed-off-by: Gabriela Moldovan --- Cargo.lock | 2 + .../tor-chanmgr/src/mgr/state/padding_test.rs | 3 +- crates/tor-hsclient/Cargo.toml | 2 + crates/tor-hsclient/src/connect.rs | 68 ++++++++++++++++--- crates/tor-netdir/src/lib.rs | 19 +++--- crates/tor-netdir/src/testnet.rs | 25 ++++--- 6 files changed, 93 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19a3d258a..7631089ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4165,6 +4165,7 @@ dependencies = [ "educe", "either", "futures", + "humantime 2.1.0", "itertools", "postage", "rand_core 0.6.4", @@ -4190,6 +4191,7 @@ dependencies = [ "tor-persist", "tor-proto", "tor-rtcompat", + "tor-rtmock", "tracing", "tracing-test", ] diff --git a/crates/tor-chanmgr/src/mgr/state/padding_test.rs b/crates/tor-chanmgr/src/mgr/state/padding_test.rs index 5052ff0df..4904dd0f4 100644 --- a/crates/tor-chanmgr/src/mgr/state/padding_test.rs +++ b/crates/tor-chanmgr/src/mgr/state/padding_test.rs @@ -43,7 +43,7 @@ fn some_interesting_netdir<'v, V>(values: V) -> Arc where V: IntoIterator, { - tor_netdir::testnet::construct_custom_netdir_with_params(|_, _| {}, values) + tor_netdir::testnet::construct_custom_netdir_with_params(|_, _| {}, values, None) .unwrap() .unwrap_if_sufficient() .unwrap() @@ -100,6 +100,7 @@ fn padding_parameters_calculation() { tor_netdir::testnet::construct_custom_netdir_with_params( |_, _| {}, values.iter().cloned(), + None, ) .unwrap() .unwrap_if_sufficient() diff --git a/crates/tor-hsclient/Cargo.toml b/crates/tor-hsclient/Cargo.toml index 113719bae..301236712 100644 --- a/crates/tor-hsclient/Cargo.toml +++ b/crates/tor-hsclient/Cargo.toml @@ -43,6 +43,7 @@ tor-rtcompat = { version = "0.9.0", path = "../tor-rtcompat" } tracing = "0.1.36" [dev-dependencies] +humantime = "2" tokio-crate = { package = "tokio", version = "1.7", features = ["full"] } tor-async-utils = { path = "../tor-async-utils", version = "0.1.0" } tor-chanmgr = { path = "../tor-chanmgr", version = "0.9.0" } @@ -52,4 +53,5 @@ tor-netdir = { path = "../tor-netdir", version = "0.9.0", features = ["testing"] tor-netdoc = { path = "../tor-netdoc", version = "0.7.0", features = ["testing"] } tor-persist = { path = "../tor-persist", version = "0.7.0", features = ["testing"] } tor-rtcompat = { path = "../tor-rtcompat", version = "0.9.0", features = ["tokio", "native-tls"] } +tor-rtmock = { path = "../tor-rtmock", version = "0.8.0" } tracing-test = "0.2" diff --git a/crates/tor-hsclient/src/connect.rs b/crates/tor-hsclient/src/connect.rs index 6f92472b9..f04b0e35e 100644 --- a/crates/tor-hsclient/src/connect.rs +++ b/crates/tor-hsclient/src/connect.rs @@ -441,11 +441,13 @@ mod test { use super::*; use crate::*; use futures::FutureExt as _; - use std::panic::AssertUnwindSafe; + use std::{iter, panic::AssertUnwindSafe}; use tokio_crate as tokio; use tor_async_utils::JoinReadWrite; - use tor_netdoc::doc::hsdesc::test_data; - use tor_rtcompat::tokio::TokioNativeTlsRuntime; + use tor_llcrypto::pk::curve25519; + use tor_netdoc::doc::{hsdesc::test_data, netstatus::Lifetime}; + use tor_rtcompat::{tokio::TokioNativeTlsRuntime, CompoundRuntime}; + use tor_rtmock::time::MockSleepProvider; use tracing_test::traced_test; #[derive(Debug, Default)] @@ -512,15 +514,43 @@ mod test { #[traced_test] #[tokio::test] async fn test_connect() { - let netdir = tor_netdir::testnet::construct_netdir(); + let valid_after = humantime::parse_rfc3339("2023-02-09T12:00:00Z").unwrap(); + let fresh_until = valid_after + humantime::parse_duration("1 hours").unwrap(); + let valid_until = valid_after + humantime::parse_duration("24 hours").unwrap(); + let lifetime = Lifetime::new(valid_after, fresh_until, valid_until).unwrap(); + + let netdir = tor_netdir::testnet::construct_custom_netdir_with_params( + tor_netdir::testnet::simple_net_func, + iter::empty::<(&str, _)>(), + Some(lifetime), + ) + .expect("failed to build default testing netdir"); + let netdir = Arc::new(netdir.unwrap_if_sufficient().unwrap()); let runtime = TokioNativeTlsRuntime::current().unwrap(); + let now = humantime::parse_rfc3339("2023-02-09T12:00:00Z").unwrap(); + let mock_sp = MockSleepProvider::new(now); + let runtime = CompoundRuntime::new( + runtime.clone(), + mock_sp, + runtime.clone(), + runtime.clone(), + runtime, + ); + let time_period = netdir.hs_time_period(); + let mglobal = Arc::new(Mutex::new(MocksGlobal::default())); let mocks = Mocks { mglobal, id: () }; // From C Tor src/test/test_hs_common.c test_build_address let hsid = test_data::TEST_HSID_2.into(); let mut data = Data::default(); + let pk = curve25519::PublicKey::from(test_data::TEST_PUBKEY_2).into(); + let sk = curve25519::StaticSecret::from(test_data::TEST_SECKEY_2).into(); + let mut secret_keys_builder = HsClientSecretKeysBuilder::default(); + secret_keys_builder.ks_hsc_desc_enc(sk); + let secret_keys = secret_keys_builder.build().unwrap(); + let _got = AssertUnwindSafe( Context::new( &runtime, @@ -528,7 +558,7 @@ mod test { netdir, hsid, &mut data, - HsClientSecretKeys::default(), + secret_keys, mocks.clone(), ) .unwrap() @@ -537,11 +567,31 @@ mod test { .catch_unwind() // TODO HS remove this and the AssertUnwindSafe .await; + let (hs_blind_id_key, subcredential) = HsIdKey::try_from(hsid) + .unwrap() + .compute_blinded_key(time_period) + .unwrap(); + let hs_blind_id = hs_blind_id_key.id(); - // TODO hs: make the tests pass again - //let mglobal = mocks.mglobal.lock().unwrap(); - //assert_eq!(mglobal.hsdirs_asked.len(), 1); - //assert_eq!(mglobal.got_desc, Some(test_data::TEST_DATA_2.to_string())); + let sk = curve25519::StaticSecret::from(test_data::TEST_SECKEY_2).into(); + + let hsdesc = HsDesc::parse_decrypt_validate( + test_data::TEST_DATA_2, + &hs_blind_id, + now, + &subcredential, + Some((&pk, &sk)), + ) + .unwrap(); + + let mglobal = mocks.mglobal.lock().unwrap(); + assert_eq!(mglobal.hsdirs_asked.len(), 1); + // TODO hs: here and in other places, consider implementing PartialEq instead, or creating + // an assert_dbg_eq macro (which would be part of a test_helpers crate or something) + assert_eq!( + format!("{:?}", mglobal.got_desc), + format!("{:?}", Some(hsdesc)) + ); // TODO hs check the circuit in got is the one we gave out } diff --git a/crates/tor-netdir/src/lib.rs b/crates/tor-netdir/src/lib.rs index 2fc91b487..ab65166d3 100644 --- a/crates/tor-netdir/src/lib.rs +++ b/crates/tor-netdir/src/lib.rs @@ -841,7 +841,7 @@ impl NetDir { /// /// (Does not return unusable relays.) /// - /// + /// /// Note that a `None` answer is not always permanent: if a microdescriptor /// is subsequently added for a relay with this ID, the ID may become usable /// even if it was not usable before. @@ -1828,13 +1828,16 @@ mod test { #[test] fn relay_funcs() { - let (consensus, microdescs) = construct_custom_network(|pos, nb| { - if pos == 15 { - nb.rs.add_or_port("[f0f0::30]:9001".parse().unwrap()); - } else if pos == 20 { - nb.rs.add_or_port("[f0f0::3131]:9001".parse().unwrap()); - } - }) + let (consensus, microdescs) = construct_custom_network( + |pos, nb| { + if pos == 15 { + nb.rs.add_or_port("[f0f0::30]:9001".parse().unwrap()); + } else if pos == 20 { + nb.rs.add_or_port("[f0f0::3131]:9001".parse().unwrap()); + } + }, + None, + ) .unwrap(); let subnet_config = SubnetConfig::default(); let mut dir = PartialNetDir::new(consensus, None); diff --git a/crates/tor-netdir/src/testnet.rs b/crates/tor-netdir/src/testnet.rs index ae9a38f26..059863259 100644 --- a/crates/tor-netdir/src/testnet.rs +++ b/crates/tor-netdir/src/testnet.rs @@ -46,7 +46,7 @@ pub struct NodeBuilders { } /// Helper: a customization function that does nothing. -fn simple_net_func(_idx: usize, _nb: &mut NodeBuilders) {} +pub fn simple_net_func(_idx: usize, _nb: &mut NodeBuilders) {} /// As [`construct_network()`], but return a [`PartialNetDir`]. pub fn construct_netdir() -> PartialNetDir { @@ -58,13 +58,14 @@ pub fn construct_netdir() -> PartialNetDir { pub fn construct_custom_netdir_with_params( func: F, params: P, + lifetime: Option, ) -> BuildResult where F: FnMut(usize, &mut NodeBuilders), P: IntoIterator, PK: Into, { - let (consensus, microdescs) = construct_custom_network(func)?; + let (consensus, microdescs) = construct_custom_network(func, lifetime)?; let mut dir = PartialNetDir::new(consensus, Some(¶ms.into_iter().collect())); for md in microdescs { dir.add_microdesc(md); @@ -78,13 +79,13 @@ pub fn construct_custom_netdir(func: F) -> BuildResult where F: FnMut(usize, &mut NodeBuilders), { - construct_custom_netdir_with_params(func, iter::empty::<(&str, _)>()) + construct_custom_netdir_with_params(func, iter::empty::<(&str, _)>(), None) } /// As [`construct_custom_network`], but do not require a /// customization function. pub fn construct_network() -> BuildResult<(MdConsensus, Vec)> { - construct_custom_network(simple_net_func) + construct_custom_network(simple_net_func, None) } /// Build a fake network with enough information to enable some basic @@ -140,7 +141,10 @@ pub fn construct_network() -> BuildResult<(MdConsensus, Vec)> { /// Instead, refactor this function so that it takes a /// description of what kind of network to build, and then builds it from /// that description. -pub fn construct_custom_network(mut func: F) -> BuildResult<(MdConsensus, Vec)> +pub fn construct_custom_network( + mut func: F, + lifetime: Option, +) -> BuildResult<(MdConsensus, Vec)> where F: FnMut(usize, &mut NodeBuilders), { @@ -153,11 +157,16 @@ where f | RelayFlags::EXIT | RelayFlags::GUARD, ]; - let now = SystemTime::now(); - let one_day = Duration::new(86400, 0); + let lifetime = lifetime.map(Ok).unwrap_or_else(|| { + let now = SystemTime::now(); + let one_day = Duration::new(86400, 0); + + Lifetime::new(now, now + one_day / 2, now + one_day) + })?; + let mut bld = MdConsensus::builder(); bld.consensus_method(34) - .lifetime(Lifetime::new(now, now + one_day / 2, now + one_day)?) + .lifetime(lifetime) .param("bwweightscale", 1) .weights("".parse()?);