From 7e8891b861d832867f428c77b4060a44835ce8e7 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 28 Oct 2021 10:21:56 -0400 Subject: [PATCH] tor-dirmgr: Test for GetCertsState --- crates/tor-dirmgr/src/state.rs | 120 ++++++++++++++++++++++- crates/tor-dirmgr/testdata/cert-5696.txt | 46 +++++++++ crates/tor-dirmgr/testdata/cert-5A23.txt | 46 +++++++++ crates/tor-dirmgr/testdata/cert-7C47.txt | 46 +++++++++ 4 files changed, 253 insertions(+), 5 deletions(-) create mode 100644 crates/tor-dirmgr/testdata/cert-5696.txt create mode 100644 crates/tor-dirmgr/testdata/cert-5A23.txt create mode 100644 crates/tor-dirmgr/testdata/cert-7C47.txt diff --git a/crates/tor-dirmgr/src/state.rs b/crates/tor-dirmgr/src/state.rs index bf4997882..92bae35ce 100644 --- a/crates/tor-dirmgr/src/state.rs +++ b/crates/tor-dirmgr/src/state.rs @@ -744,6 +744,8 @@ mod test { atomic::{self, AtomicBool}, Arc, }; + use time::macros::datetime; + use tor_netdoc::doc::authcert::AuthCertKeyIds; struct DirRcv { cfg: DirMgrConfig, @@ -796,24 +798,53 @@ mod test { // Test data const CONSENSUS: &str = include_str!("../testdata/mdconsensus1.txt"); + const AUTHCERT_5696: &str = include_str!("../testdata/cert-5696.txt"); + const AUTHCERT_5A23: &str = include_str!("../testdata/cert-5A23.txt"); + #[allow(unused)] + const AUTHCERT_7C47: &str = include_str!("../testdata/cert-7C47.txt"); fn test_time() -> SystemTime { - time::macros::datetime!(2020-08-07 12:42:45 UTC).into() + datetime!(2020-08-07 12:42:45 UTC).into() + } + fn rsa(s: &str) -> RsaIdentity { + let k = hex::decode(s).unwrap(); + RsaIdentity::from_bytes(&k[..]).unwrap() } fn test_authorities() -> Vec { fn a(s: &str) -> Authority { - let k = hex::decode(s).unwrap(); Authority::builder() .name("ignore") - .v3ident(RsaIdentity::from_bytes(&k[..]).unwrap()) + .v3ident(rsa(s)) .build() .unwrap() } vec![ a("5696AB38CB3852AFA476A5C07B2D4788963D5567"), a("5A23BA701776C9C1AB1C06E734E92AB3D5350D64"), - a("7C47DCB4A90E2C2B7C7AD27BD641D038CF5D7EBE"), + // This is an authority according to the consensus, but we'll + // pretend we don't recognize it, to make sure that we + // don't fetch or accept it. + // a("7C47DCB4A90E2C2B7C7AD27BD641D038CF5D7EBE"), ] } + fn authcert_id_5696() -> AuthCertKeyIds { + AuthCertKeyIds { + id_fingerprint: rsa("5696ab38cb3852afa476a5c07b2d4788963d5567"), + sk_fingerprint: rsa("f6ed4aa64d83caede34e19693a7fcf331aae8a6a"), + } + } + fn authcert_id_5a23() -> AuthCertKeyIds { + AuthCertKeyIds { + id_fingerprint: rsa("5a23ba701776c9c1ab1c06e734e92ab3d5350d64"), + sk_fingerprint: rsa("d08e965cc6dcb6cb6ed776db43e616e93af61177"), + } + } + // remember, we're saying that we don't recognize this one as an authority. + fn authcert_id_7c47() -> AuthCertKeyIds { + AuthCertKeyIds { + id_fingerprint: rsa("7C47DCB4A90E2C2B7C7AD27BD641D038CF5D7EBE"), + sk_fingerprint: rsa("D3C013E0E6C82E246090D1C0798B75FCB7ACF120"), + } + } #[test] fn get_consensus_state() { @@ -866,10 +897,11 @@ mod test { assert!(outcome.unwrap()); // And with that, we should be asking for certificates + assert!(state.can_advance()); let next = Box::new(state).advance().unwrap(); assert_eq!( &next.describe(), - "Downloading certificates for consensus (we are missing 3/3)." + "Downloading certificates for consensus (we are missing 2/2)." ); // Try again, but this time get the state from the cache. @@ -880,5 +912,83 @@ mod test { let map = vec![(docid, text.into())].into_iter().collect(); let outcome = state.add_from_cache(map, None); assert!(outcome.unwrap()); + assert!(state.can_advance()); + } + + #[test] + fn get_certs_state() { + /// Construct a GetCertsState with our test data + fn new_getcerts_state() -> (Arc, Box) { + let rcv = Arc::new(DirRcv::new(test_time(), Some(test_authorities()))); + let mut state = + GetConsensusState::new(Arc::downgrade(&rcv), CacheUsage::CacheOkay).unwrap(); + let req = tor_dirclient::request::ConsensusRequest::new(ConsensusFlavor::Microdesc); + let req = crate::docid::ClientRequest::Consensus(req); + let outcome = state.add_from_download(CONSENSUS, &req, None); + assert!(outcome.unwrap()); + (rcv, Box::new(state).advance().unwrap()) + } + + let (_rcv, mut state) = new_getcerts_state(); + // Basic properties: description, status, reset time. + assert_eq!( + &state.describe(), + "Downloading certificates for consensus (we are missing 2/2)." + ); + assert!(!state.can_advance()); + assert!(!state.is_ready(Readiness::Complete)); + assert!(!state.is_ready(Readiness::Usable)); + let consensus_expires = datetime!(2020-08-07 12:43:20 UTC).into(); + assert_eq!(state.reset_time(), Some(consensus_expires)); + + // Check that we get the right list of missing docs. + let missing = state.missing_docs(); + assert_eq!(missing.len(), 2); // We are missing two certificates. + assert!(missing.contains(&DocId::AuthCert(authcert_id_5696()))); + assert!(missing.contains(&DocId::AuthCert(authcert_id_5a23()))); + // we don't ask for this one because we don't recognize its authority + assert!(!missing.contains(&DocId::AuthCert(authcert_id_7c47()))); + + // Add one from the cache; make sure the list is still right + let text1: crate::storage::InputString = AUTHCERT_5696.to_owned().into(); + // let text2: crate::storage::InputString = AUTHCERT_5A23.to_owned().into(); + let docs = vec![(DocId::AuthCert(authcert_id_5696()), text1.into())] + .into_iter() + .collect(); + let outcome = state.add_from_cache(docs, None); + assert!(outcome.unwrap()); // no error, and something changed. + assert!(!state.can_advance()); // But we aren't done yet. + let missing = state.missing_docs(); + assert_eq!(missing.len(), 1); // Now we're only missing one! + assert!(missing.contains(&DocId::AuthCert(authcert_id_5a23()))); + + // Now try to add the other from a download ... but fail + // because we didn't ask for it. + let mut req = tor_dirclient::request::AuthCertRequest::new(); + req.push(authcert_id_5696()); // it's the wrong id. + let req = ClientRequest::AuthCert(req); + let outcome = state.add_from_download(AUTHCERT_5A23, &req, None); + assert!(!outcome.unwrap()); // no error, but nothing changed. + let missing2 = state.missing_docs(); + assert_eq!(missing, missing2); // No change. + + // Now try to add the other from a download ... for real! + let mut req = tor_dirclient::request::AuthCertRequest::new(); + req.push(authcert_id_5a23()); // Right idea this time! + let req = ClientRequest::AuthCert(req); + let outcome = state.add_from_download(AUTHCERT_5A23, &req, None); + assert!(outcome.unwrap()); // No error, _and_ something changed! + let missing3 = state.missing_docs(); + assert!(missing3.is_empty()); + assert!(state.can_advance()); + + let next = state.advance().unwrap(); + assert_eq!( + &next.describe(), + "Downloading microdescriptors (we are missing 6)." + ); + + // TODO: I'd like even more tests to make sure that we never + // accept a certificate for an authority we don't believe in. } } diff --git a/crates/tor-dirmgr/testdata/cert-5696.txt b/crates/tor-dirmgr/testdata/cert-5696.txt new file mode 100644 index 000000000..5f9625307 --- /dev/null +++ b/crates/tor-dirmgr/testdata/cert-5696.txt @@ -0,0 +1,46 @@ +dir-key-certificate-version 3 +dir-address 127.0.0.1:7001 +fingerprint 5696AB38CB3852AFA476A5C07B2D4788963D5567 +dir-key-published 2020-08-07 12:40:25 +dir-key-expires 2021-08-07 12:40:25 +dir-identity-key +-----BEGIN RSA PUBLIC KEY----- +MIIBigKCAYEA5uDA8p4NhKPwOX/sMeMn6RtZLmNM2Ye4a1EPk2LQ7LYWQyeBZqsq +GzZnQANclC0YbGi7cw7GiGY6NKXZNWtaPxX5rCWOw8IhGjNo56/kSfHJX+Gvtzzp +dbxW/9JIYi8WyXQfMBhmfWtUrkdNIEyuW//H08haH+viCMePSv6zmPoc0xV//+XK +ycHe/hLQZMKHIhHLGz0k3fRtousy+3y/vQFjw2PVwMB7xXnbHFPc0b+jUU3QO2V6 +jUAXVdIyHU+y1FzynUPo6C5d8mVQIlz/NcL1k0IKGUn1ItaQicYs28ooC+/I/lvV +yub7LHHN7HX2IBwKLf135DQvSwXBWBFYwaYWGKDyN6IOGxCncKp9Cplz+Dk8P93m +vTPYdpF0F0M1kP5dmakVqXyivJZMHGsQr2V0qGXr6I1wwu3SOdO0fmogWmEOmeT+ +3L4elBnC9BjPhCfX7vnzksLp6BZe20Btiu1TqxA0SUTk3t2kOJulwDcgYAyUbKeJ +NSKK8YOMyhvrAgMBAAE= +-----END RSA PUBLIC KEY----- +dir-signing-key +-----BEGIN RSA PUBLIC KEY----- +MIIBCgKCAQEAld61NikA0aqQnT2rO6YRelSnWCZjC3axXlrRV5QP1vJrPOdRRS53 +xHgkFEo8dX63X1bl67MBiZmgcP+cD/p9aFi9XGJyTU84wdBvmNU65LJ4sH0jKL1E +DBt9RiDFCh9MhxqniVBp91is7m5RKV34Cwyco3Ti54uLO0FNGAh49nvNyANO0FlQ +YFdM9yRQRciv20rWYO9M6brxK7LQMYVTg899yFnqa/vc+3USonKVLnmXeViNYyui +bekkmN6E9EtSujpsfVAwsMSZy73n0n/PTRfXa+58npNgNbxX6mgQ6i7Nhy9KyFP4 +9BzKA9Q3CmeM/Z339awAtCtSaLoEb0Vh3QIDAQAB +-----END RSA PUBLIC KEY----- +dir-key-crosscert +-----BEGIN ID SIGNATURE----- +WKrcO0K/e8XWRhTD0fh7+fqTJvL3A296/Yad16SS6Bdz1yh/QihSpffdS3PBi+ka +WhHdXNYZJ68BPr4kNUC6xwlObeVlt0SVVpE2avqpfFtZL1pV6he2dNKZ5MMv6Ctm +7BOaavpLwcEyXs2H1XxH6wjQU719FCbvJvBESclAAIq3K3D5fmFg68RNWHHz3r3F +MyXnaR5bylKkgQHwwz5Q3HVjWUJ6S7Fz8KTfO1Q7rvfgHpXzYJqAyXivhaGnJmWQ ++zHVscRSI3NpGgqnzeqylXkZVqrHWNO5mkVSeMXt2hMYP61Zkm7KO6lqtOBON7Db +AKOs+q8j2T3XoR5VD9YtAQ== +-----END ID SIGNATURE----- +dir-key-certification +-----BEGIN SIGNATURE----- +fJEeVmr7caG8pfwO9XFeCGnWVgyqKSg90xpIfcWbPHrn5brAXEwJm/+dX7V9tazx +8y6i43ULt3MI+7Et2o46A3wYGA0a3OqpxAHdJjxeafJ9bDXRyVETh2MHsd0I337A +JhSuufKyGS+K2y20s2VYMPXkX2AFKpN1H0Stc7RdpssGyrmidZSXXzCgTitqn52g +Ms9iWjCU6Ra5AjMzp/D93CFZ0fYMhKot42ZXYJga8drQHdY06+5Fb7RSTpFs9vhf +t4XdeMef+N9ty/yaLNDmYiLJbKTTAarfkM2czXuuk3s+qwLN7+O4yGUNQz4tPJ8E +h7VALUNE80QNDLb4rXiIUE+EI3tCqo9mQ/tnCVVofM6sQyTFjTWyIIRBABnaODlO +meOIIEIR6ht2qSseZDe4dme7cg5/misTnIv7BNbErpYO5r9C2yHHFqSe8sivExCo +tEkNtxufKS2mn6Tkm7wcJfp1Temxk/INUtvPA6Dlf3wNTnwzuGfk7LWCQ9BPeFqv +-----END SIGNATURE----- diff --git a/crates/tor-dirmgr/testdata/cert-5A23.txt b/crates/tor-dirmgr/testdata/cert-5A23.txt new file mode 100644 index 000000000..68d32745f --- /dev/null +++ b/crates/tor-dirmgr/testdata/cert-5A23.txt @@ -0,0 +1,46 @@ +dir-key-certificate-version 3 +dir-address 127.0.0.1:7000 +fingerprint 5A23BA701776C9C1AB1C06E734E92AB3D5350D64 +dir-key-published 2020-08-07 12:40:25 +dir-key-expires 2021-08-07 12:40:25 +dir-identity-key +-----BEGIN RSA PUBLIC KEY----- +MIIBigKCAYEAtitks3CQo7QOYYhJmYJGOJoA9XOREzl38tl6zrGq4XtwOioTUivP +M51l483083x5DsBw6+Ec9LOkVSClETOIHDzjIzg78O4a6uEr7HemTI7JKEbIXUtj +bu1/JxOb7Bd8HrA/9Vw6hp3GJT7wqO33K/XhmRVzH2SMhmLP0cZT5MfaaE38QViI +eWrTFze+U1Z16RPWx8djaepCgLaVT2tP9WXKtk+6O0Kyjz1toF9wfZUb4jfEHNQ2 +6Np5IaJcpsMaaovx2ClNOy23MadsLhBQxquCC1IFilMwKDDjVN9BIUd3eZJDBgyy +yY4PvO6fMsVxtK+7dlw2pWpdc2YSTGh9TY+UfWyPn+7oUD2AB/liJ/HOSqdXw5kl +YLeu2DwVUkv4ZieExUjyCmjmwkAdpEfMRE77hru+hbAV3E/vUj7571I1alMRZQU3 +PItAQkfygL+0yI0Ysk4kVt0zxkFv19o1YD6yS+vBkY2oVGflBS6TVl2v/YsVDBEU +L6ifTkCQ8zIPAgMBAAE= +-----END RSA PUBLIC KEY----- +dir-signing-key +-----BEGIN RSA PUBLIC KEY----- +MIIBCgKCAQEAuMZaaW/p0CyTxWmr3SkBdrLz1uRiTZFadYNQmVcyeEfHw+siOO2Z +GZCpLW14AilxrGgIqacbj4p1bnP1Fqt48SW06TJpfg8LL5u9A0taBTrvl4d+y0PU +muk5/Y03QDUQ0Mqa5wFqXwq0gpFYNAF60fUcILU+RfC/eLF8p/8tMH6VqHbYJNvA +amHoi5b/cSX26y2AJG9NeRuljx9kGBKcQ3nyIUr5KtNmMAxtznnz6cxsXneCtfxo +H4Ubwy3NhSEfrjlSE4B/iASKalXgmQSSXR/PA+iBsG+zZ8+6/kKtxc5MQmnEQ3Qg +q6M1hfp9K89K/EzaxQ06PLvY1FylGqpc1wIDAQAB +-----END RSA PUBLIC KEY----- +dir-key-crosscert +-----BEGIN ID SIGNATURE----- +UrMAQ97L/Aoz0pY+IahRnlTYFdJ3jLM28WxRvZ3eP8ShCmDHYYN7fMwnstDjZZ8N +mGL8PuYP4mYfIRGjCBrMr5doLKtaOoyxnuuE81y08Yd8xWkIt9zelc5baGj1iJjn +1kxRCeClli0v05M31Z5zTNAfdMDD+yai4husa/0oEIMBJvjEAmeRcyjxfWIV8R0D +e+PR7+GAxprbJFGRL9bn27PlR7Lbm03jZIpBhCdTAeBxyGHyS8wgaXaIJCR7e3GH +uJytP7OvPoWLAggHSBp1LwsY++lLayJrTjm3/yoWv7BOXnXP0XHwDoPoXySS519p +lxq5rwk1RrSwa93+nwnEXw== +-----END ID SIGNATURE----- +dir-key-certification +-----BEGIN SIGNATURE----- +fp1nrLUFamnIg6rZnG/hMuM00SpBVTW6/XgEgMw9QIfE3lQxzR/hKF6iFcasYi2z +gg6r2JAvGevQxzajV8nDgKcLSnDurh6Q7OJw9p4v1ksXLJazHbLAhKi+Aa/daSmb +6Klp3XVDgVNhYzTleN26/El+Z1oEjbqRs72Vvlazem5lKaOZvm7jolgWQn5TiWZY +TQ9D7cP9TDAm7WBvYQ97CUnSDobVJyVBtCQrNb5vppTQw6+FON0U2h75Vl+T/Qhd +wugYKJ+UbZhwBCy0EOM23BU7QS6jbYW2bBjeo5I7/K32Cci8YZKuib9N/j3NPuFz +7jRAYSgiEd4uwktG4RP55EV7RVTO28/XeEvvlM/iVVYoqS+bMoCRkO8LqHvKB6+0 +Wkei7KASZzIVe5YcgRHzts/oBt8w59DIaGUtEPQQ2BEIYtkl4N3mfR9VgW5HpTUI +2kPs1DjukQslB6Ilz6G+qOaZtJyOhdkWtwdR/fMcDWmTEifLZDbAdiLUpg/xc26p +-----END SIGNATURE----- diff --git a/crates/tor-dirmgr/testdata/cert-7C47.txt b/crates/tor-dirmgr/testdata/cert-7C47.txt new file mode 100644 index 000000000..10e2a1f26 --- /dev/null +++ b/crates/tor-dirmgr/testdata/cert-7C47.txt @@ -0,0 +1,46 @@ +dir-key-certificate-version 3 +dir-address 127.0.0.1:7002 +fingerprint 7C47DCB4A90E2C2B7C7AD27BD641D038CF5D7EBE +dir-key-published 2020-08-07 12:40:26 +dir-key-expires 2021-08-07 12:40:26 +dir-identity-key +-----BEGIN RSA PUBLIC KEY----- +MIIBigKCAYEAyE1/XqjBgaNCSp36thnqlRzzt/4vEXXUIcutCkGAsI/An408vj+Z +tSo844vMMtSb8z1z0xDzApz2GPe7n5BTdPGjV1YQUd3Vr0z3z1j9EolV8NoXlUod +Mj9pSa2dB9Hpz1ZooAEX+egRXPXOp6kHb2QyUIVupKUo/kCRwyUcqV6M52oPZ0i4 +o2uhhExXkExY1f7y6yee7QzLOxIgDhtWpkBhfMjRfa856ULXcRPwsQ99A1RclWTb +c1i6aU3NIt+AYthamu6G4jnYTrg4tPUyr7Gc4+j34rT/SwLS5waKZwZFObGNitK0 +dLMMgPHfeJMW7wVN/scNDXCwZ19XzYEdat+SGP9jUaxPoabdOgzibfQINanw7pzm +G5bEmOuqWr1vYy3oRs1rIJJ18vy6yTF379sKdkB1gSau6svSIJfvUpnVA2pjvjL0 +UGxXCCMozU+ctoe1PtXAEDFTE30vHo2pDe0pvJI+7bO09NAbTpIFfoxILqKRstJ7 +PcU/6Ncbmfd7AgMBAAE= +-----END RSA PUBLIC KEY----- +dir-signing-key +-----BEGIN RSA PUBLIC KEY----- +MIIBCgKCAQEAy+3L8ISKlSQ7nOmHgi1rNSpSp00e4VrMcgXU8+kn0yjYZB6jOSMs +/LZDk14eX8jlvPsJg/SIl4c2OD+AYJtiyB1DZnZY/QbZ48faVwi9FkfCcZLkrD1i +PiiYmpM+DS+sh1oiBZX/wTSvx0MeEjyd9t8ZhH5R86k7QA7TW7Fe9rRrLshPSGFp +4ipj1fG+NuEG58kXeWSLwXJvNl4Hdezvvjii5la9b2S37/D6DZDfRLib35tXfA4T +y/zUK1pjzEQaAUeuIOgB+olX6bsOyL2eQORd5y5MtfF4x4FklPcz/e1l7gmahWGp +RpSUIRszrEbfxgCA8zCz/ta+jrrXq1lkpQIDAQAB +-----END RSA PUBLIC KEY----- +dir-key-crosscert +-----BEGIN ID SIGNATURE----- +HvUJXA95l45NFYuD5y5jSf4aFE0f3TlABjKK159WeSjDD/4Vn1GJQQjX6ske8MDh +x54GpTllhLmPLRq5GXn/DRCvxG9TGpyP3vL8pq2TWLBscCVxg4D9xj6OSYvbBKRw +QolqW8wfGKPj2OgCnTB3jzvnshP9rDq/ruEzlZfJTrb4pxQrPzOAlwaKEDCoO9zy +IW/gmVn1/vGNU/qhuGAKa4FGKUjvTg699MFE2SIF7gLo+oOGkFfL37WhHDlh7HPR +JiAHgTp6nHp+2+B/EHR5u94b3g66qPRNN6KxWcTAqcUxX9t0dKlsROZksr1268P6 +PEN3+GtdwiA4n3reP+Wsxw== +-----END ID SIGNATURE----- +dir-key-certification +-----BEGIN SIGNATURE----- +FqKvXdB2bcwFYEWdQDW0eot/5cRTBnb8frAzoA/khWUSLhYIE55b/xtDg2OMWMhx +/yBiGuNGHT82+jKDh92RfxVKH8D32/r6p1SP1ot8POGWU/ke6/lABZkd5Aa5xSb7 +Hcqik24bbnlvePtqze7UlvJQZN3ktYHUV2LTyw4ZbY1NEmMoPGE7FWe1iHSCiAvn +I8u3ePREY2gQ4ZzkcjuPzIMX4Th18OEQFTanNgJqmW5l4XDkXO4yAOaO21/7kdTg +iTqQnoWn8PfoVRvXVYvrgWKMyRUT/6R2zUnNWaP9z7JKv3SSZSXyMowbcyb5QFTX +KKhfO7fLMdGUs/yhXvqVgaQdguOcLfTUU7rV8aZjKsGiDPsFJKTBw9Xt5obGGJN4 +4CLP+J9lSi/aZ2M4/qD5tkuE0kUNzeHuZuhze3MOObRZxLC5I3skwzTuflODVtTP +llMKUqZjbySFnSHEMvs+rhPOiUPNzXDl7/hQAVbWrzIyjjJ0WpoIUyHcIETWsv6Y +-----END SIGNATURE-----