run tree from tal pass
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use std::time::Duration;
|
||||
|
||||
use rpki::data_model::crl::RpkixCrl;
|
||||
use rpki::fetch::http::{BlockingHttpFetcher, HttpFetcherConfig};
|
||||
@@ -59,7 +60,9 @@ impl LiveStats {
|
||||
fn record(&mut self, res: &PublicationPointRunResult) {
|
||||
self.publication_points_processed += 1;
|
||||
match res.source {
|
||||
rpki::validation::manifest::PublicationPointSource::Fresh => self.publication_points_fresh += 1,
|
||||
rpki::validation::manifest::PublicationPointSource::Fresh => {
|
||||
self.publication_points_fresh += 1
|
||||
}
|
||||
rpki::validation::manifest::PublicationPointSource::VerifiedCache => {
|
||||
self.publication_points_cached += 1
|
||||
}
|
||||
@@ -139,8 +142,15 @@ impl<'a> PublicationPointRunner for CountingRunner<'a> {
|
||||
#[test]
|
||||
#[ignore = "live network + rsync full-tree stats (APNIC TAL); may take minutes"]
|
||||
fn apnic_tree_full_stats_serial() {
|
||||
let http = BlockingHttpFetcher::new(HttpFetcherConfig::default()).expect("http fetcher");
|
||||
let rsync = SystemRsyncFetcher::new(SystemRsyncConfig::default());
|
||||
let http = BlockingHttpFetcher::new(HttpFetcherConfig {
|
||||
timeout: Duration::from_secs(30 * 60),
|
||||
..HttpFetcherConfig::default()
|
||||
})
|
||||
.expect("http fetcher");
|
||||
let rsync = SystemRsyncFetcher::new(SystemRsyncConfig {
|
||||
timeout: Duration::from_secs(30 * 60),
|
||||
..SystemRsyncConfig::default()
|
||||
});
|
||||
let validation_time = time::OffsetDateTime::now_utc();
|
||||
|
||||
let temp = tempfile::tempdir().expect("tempdir");
|
||||
@@ -202,7 +212,12 @@ fn apnic_tree_full_stats_serial() {
|
||||
|
||||
println!("APNIC Stage2 full-tree serial stats");
|
||||
println!("tal_url={APNIC_TAL_URL}");
|
||||
println!("validation_time={}", validation_time.format(&time::format_description::well_known::Rfc3339).unwrap());
|
||||
println!(
|
||||
"validation_time={}",
|
||||
validation_time
|
||||
.format(&time::format_description::well_known::Rfc3339)
|
||||
.unwrap()
|
||||
);
|
||||
println!();
|
||||
println!(
|
||||
"publication_points_processed={} publication_points_failed={} fresh={} cached={}",
|
||||
@@ -212,7 +227,10 @@ fn apnic_tree_full_stats_serial() {
|
||||
stats.publication_points_cached
|
||||
);
|
||||
println!("rrdp_repos_unique={}", stats.rrdp_repos_unique.len());
|
||||
println!("objects_dropped_publication_points={}", stats.objects_dropped_publication_points);
|
||||
println!(
|
||||
"objects_dropped_publication_points={}",
|
||||
stats.objects_dropped_publication_points
|
||||
);
|
||||
println!();
|
||||
println!(
|
||||
"pack_uris_total={} pack_uris_unique={}",
|
||||
@@ -242,12 +260,24 @@ fn apnic_tree_full_stats_serial() {
|
||||
out.aspas.len()
|
||||
);
|
||||
println!();
|
||||
println!("rocksdb_raw_objects_total={} raw_by_ext={:?}", raw_total, raw_by_ext);
|
||||
println!(
|
||||
"rocksdb_raw_objects_total={} raw_by_ext={:?}",
|
||||
raw_total, raw_by_ext
|
||||
);
|
||||
println!("rocksdb_verified_packs_total={}", verified_total);
|
||||
|
||||
// Loose sanity assertions (avoid flakiness due to repository churn).
|
||||
//
|
||||
// This test supports bounded manual runs via env vars:
|
||||
// - `RPKI_APNIC_MAX_DEPTH=0` or `RPKI_APNIC_MAX_INSTANCES=1` implies root-only.
|
||||
// Otherwise we expect to reach at least one child.
|
||||
let min_expected = if max_depth == Some(0) || max_instances.is_some_and(|n| n <= 1) {
|
||||
1
|
||||
} else {
|
||||
2
|
||||
};
|
||||
assert!(
|
||||
out.instances_processed >= 2,
|
||||
"expected to process root + at least one child"
|
||||
out.instances_processed >= min_expected,
|
||||
"expected to process at least {min_expected} publication point(s)"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use rpki::fetch::http::{BlockingHttpFetcher, HttpFetcherConfig};
|
||||
use rpki::fetch::rsync_system::{SystemRsyncConfig, SystemRsyncFetcher};
|
||||
use rpki::policy::Policy;
|
||||
use rpki::storage::RocksStore;
|
||||
use rpki::validation::run_tree_from_tal::run_tree_from_tal_url_serial;
|
||||
use rpki::validation::run_tree_from_tal::run_tree_from_tal_url_serial_audit;
|
||||
use rpki::validation::tree::TreeRunConfig;
|
||||
|
||||
const APNIC_TAL_URL: &str = "https://tal.apnic.net/tal-archive/apnic-rfc7730-https.tal";
|
||||
@@ -10,8 +13,15 @@ const APNIC_TAL_URL: &str = "https://tal.apnic.net/tal-archive/apnic-rfc7730-htt
|
||||
#[test]
|
||||
#[ignore = "live network + rsync smoke test (APNIC TAL)"]
|
||||
fn apnic_tree_depth1_processes_more_than_root() {
|
||||
let http = BlockingHttpFetcher::new(HttpFetcherConfig::default()).expect("http fetcher");
|
||||
let rsync = SystemRsyncFetcher::new(SystemRsyncConfig::default());
|
||||
let http = BlockingHttpFetcher::new(HttpFetcherConfig {
|
||||
timeout: Duration::from_secs(30 * 60),
|
||||
..HttpFetcherConfig::default()
|
||||
})
|
||||
.expect("http fetcher");
|
||||
let rsync = SystemRsyncFetcher::new(SystemRsyncConfig {
|
||||
timeout: Duration::from_secs(30 * 60),
|
||||
..SystemRsyncConfig::default()
|
||||
});
|
||||
|
||||
let temp = tempfile::tempdir().expect("tempdir");
|
||||
let store = RocksStore::open(temp.path()).expect("open rocksdb");
|
||||
@@ -35,3 +45,46 @@ fn apnic_tree_depth1_processes_more_than_root() {
|
||||
"expected to process root + at least one child"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "live network + rsync root-only smoke test (APNIC TAL); 30min timeouts"]
|
||||
fn apnic_tree_root_only_processes_root_with_long_timeouts() {
|
||||
let http = BlockingHttpFetcher::new(HttpFetcherConfig {
|
||||
timeout: Duration::from_secs(30 * 60),
|
||||
..HttpFetcherConfig::default()
|
||||
})
|
||||
.expect("http fetcher");
|
||||
let rsync = SystemRsyncFetcher::new(SystemRsyncConfig {
|
||||
timeout: Duration::from_secs(30 * 60),
|
||||
..SystemRsyncConfig::default()
|
||||
});
|
||||
|
||||
let temp = tempfile::tempdir().expect("tempdir");
|
||||
let store = RocksStore::open(temp.path()).expect("open rocksdb");
|
||||
let policy = Policy::default();
|
||||
let validation_time = time::OffsetDateTime::now_utc();
|
||||
|
||||
let out = run_tree_from_tal_url_serial_audit(
|
||||
&store,
|
||||
&policy,
|
||||
APNIC_TAL_URL,
|
||||
&http,
|
||||
&rsync,
|
||||
validation_time,
|
||||
&TreeRunConfig {
|
||||
max_depth: Some(0),
|
||||
max_instances: Some(1),
|
||||
},
|
||||
)
|
||||
.expect("run APNIC root-only");
|
||||
|
||||
assert_eq!(
|
||||
out.tree.instances_processed, 1,
|
||||
"expected to process exactly the root publication point"
|
||||
);
|
||||
assert_eq!(
|
||||
out.publication_points.len(),
|
||||
out.tree.instances_processed,
|
||||
"audit should include one publication point"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@ fn load_tal_and_ta_fixture(tal_name: &str, ta_name: &str) -> TrustAnchor {
|
||||
std::fs::read(format!("tests/fixtures/tal/{tal_name}")).expect("read TAL fixture");
|
||||
let tal = Tal::decode_bytes(&tal_bytes).expect("decode TAL");
|
||||
|
||||
let ta_der =
|
||||
std::fs::read(format!("tests/fixtures/ta/{ta_name}")).expect("read TA fixture");
|
||||
let ta_der = std::fs::read(format!("tests/fixtures/ta/{ta_name}")).expect("read TA fixture");
|
||||
let resolved = tal.ta_uris[0].clone();
|
||||
|
||||
TrustAnchor::bind_der(tal, &ta_der, Some(&resolved)).expect("bind TAL and TA")
|
||||
|
||||
@@ -106,122 +106,102 @@ authorityKeyIdentifier = keyid:always
|
||||
write(&dir.join("openssl.cnf"), &cnf);
|
||||
|
||||
// Issuer CA key + self-signed CA cert (DER later).
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("genrsa")
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.key"))
|
||||
.arg("2048"),
|
||||
);
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("req")
|
||||
.arg("-new")
|
||||
.arg("-x509")
|
||||
.arg("-sha256")
|
||||
.arg("-days")
|
||||
.arg("365")
|
||||
.arg("-key")
|
||||
.arg(dir.join("issuer.key"))
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.pem"))
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf"))
|
||||
.arg("-extensions")
|
||||
.arg("v3_issuer_ca"),
|
||||
);
|
||||
run(Command::new("openssl")
|
||||
.arg("genrsa")
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.key"))
|
||||
.arg("2048"));
|
||||
run(Command::new("openssl")
|
||||
.arg("req")
|
||||
.arg("-new")
|
||||
.arg("-x509")
|
||||
.arg("-sha256")
|
||||
.arg("-days")
|
||||
.arg("365")
|
||||
.arg("-key")
|
||||
.arg(dir.join("issuer.key"))
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.pem"))
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf"))
|
||||
.arg("-extensions")
|
||||
.arg("v3_issuer_ca"));
|
||||
|
||||
// Child CA key + CSR.
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("genrsa")
|
||||
.arg("-out")
|
||||
.arg(dir.join("child.key"))
|
||||
.arg("2048"),
|
||||
);
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("req")
|
||||
.arg("-new")
|
||||
.arg("-key")
|
||||
.arg(dir.join("child.key"))
|
||||
.arg("-subj")
|
||||
.arg("/CN=Child CA")
|
||||
.arg("-out")
|
||||
.arg(dir.join("child.csr"))
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf")),
|
||||
);
|
||||
run(Command::new("openssl")
|
||||
.arg("genrsa")
|
||||
.arg("-out")
|
||||
.arg(dir.join("child.key"))
|
||||
.arg("2048"));
|
||||
run(Command::new("openssl")
|
||||
.arg("req")
|
||||
.arg("-new")
|
||||
.arg("-key")
|
||||
.arg(dir.join("child.key"))
|
||||
.arg("-subj")
|
||||
.arg("/CN=Child CA")
|
||||
.arg("-out")
|
||||
.arg(dir.join("child.csr"))
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf")));
|
||||
|
||||
// Issue child CA cert using openssl ca (so it appears in the CA database for CRL).
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("ca")
|
||||
.arg("-batch")
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf"))
|
||||
.arg("-extensions")
|
||||
.arg("v3_child_ca")
|
||||
.arg("-in")
|
||||
.arg(dir.join("child.csr"))
|
||||
.arg("-out")
|
||||
.arg(dir.join("child.pem"))
|
||||
.arg("-notext"),
|
||||
);
|
||||
run(Command::new("openssl")
|
||||
.arg("ca")
|
||||
.arg("-batch")
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf"))
|
||||
.arg("-extensions")
|
||||
.arg("v3_child_ca")
|
||||
.arg("-in")
|
||||
.arg(dir.join("child.csr"))
|
||||
.arg("-out")
|
||||
.arg(dir.join("child.pem"))
|
||||
.arg("-notext"));
|
||||
|
||||
if revoke_child {
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("ca")
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf"))
|
||||
.arg("-revoke")
|
||||
.arg(dir.join("child.pem")),
|
||||
);
|
||||
run(Command::new("openssl")
|
||||
.arg("ca")
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf"))
|
||||
.arg("-revoke")
|
||||
.arg(dir.join("child.pem")));
|
||||
}
|
||||
|
||||
// Generate CRL.
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("ca")
|
||||
.arg("-gencrl")
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf"))
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.crl.pem")),
|
||||
);
|
||||
run(Command::new("openssl")
|
||||
.arg("ca")
|
||||
.arg("-gencrl")
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf"))
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.crl.pem")));
|
||||
|
||||
// Convert to DER.
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("x509")
|
||||
.arg("-in")
|
||||
.arg(dir.join("issuer.pem"))
|
||||
.arg("-outform")
|
||||
.arg("DER")
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.cer")),
|
||||
);
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("x509")
|
||||
.arg("-in")
|
||||
.arg(dir.join("child.pem"))
|
||||
.arg("-outform")
|
||||
.arg("DER")
|
||||
.arg("-out")
|
||||
.arg(dir.join("child.cer")),
|
||||
);
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("crl")
|
||||
.arg("-in")
|
||||
.arg(dir.join("issuer.crl.pem"))
|
||||
.arg("-outform")
|
||||
.arg("DER")
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.crl")),
|
||||
);
|
||||
run(Command::new("openssl")
|
||||
.arg("x509")
|
||||
.arg("-in")
|
||||
.arg(dir.join("issuer.pem"))
|
||||
.arg("-outform")
|
||||
.arg("DER")
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.cer")));
|
||||
run(Command::new("openssl")
|
||||
.arg("x509")
|
||||
.arg("-in")
|
||||
.arg(dir.join("child.pem"))
|
||||
.arg("-outform")
|
||||
.arg("DER")
|
||||
.arg("-out")
|
||||
.arg(dir.join("child.cer")));
|
||||
run(Command::new("openssl")
|
||||
.arg("crl")
|
||||
.arg("-in")
|
||||
.arg(dir.join("issuer.crl.pem"))
|
||||
.arg("-outform")
|
||||
.arg("DER")
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.crl")));
|
||||
|
||||
Generated {
|
||||
issuer_ca_der: std::fs::read(dir.join("issuer.cer")).expect("read issuer der"),
|
||||
|
||||
@@ -93,104 +93,86 @@ authorityKeyIdentifier = keyid:always
|
||||
);
|
||||
std::fs::write(dir.join("openssl.cnf"), cnf.as_bytes()).expect("write cnf");
|
||||
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("genrsa")
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.key"))
|
||||
.arg("2048"),
|
||||
);
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("req")
|
||||
.arg("-new")
|
||||
.arg("-x509")
|
||||
.arg("-sha256")
|
||||
.arg("-days")
|
||||
.arg("365")
|
||||
.arg("-key")
|
||||
.arg(dir.join("issuer.key"))
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf"))
|
||||
.arg("-extensions")
|
||||
.arg("v3_issuer_ca")
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.pem")),
|
||||
);
|
||||
run(Command::new("openssl")
|
||||
.arg("genrsa")
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.key"))
|
||||
.arg("2048"));
|
||||
run(Command::new("openssl")
|
||||
.arg("req")
|
||||
.arg("-new")
|
||||
.arg("-x509")
|
||||
.arg("-sha256")
|
||||
.arg("-days")
|
||||
.arg("365")
|
||||
.arg("-key")
|
||||
.arg(dir.join("issuer.key"))
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf"))
|
||||
.arg("-extensions")
|
||||
.arg("v3_issuer_ca")
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.pem")));
|
||||
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("genrsa")
|
||||
.arg("-out")
|
||||
.arg(dir.join("ee.key"))
|
||||
.arg("2048"),
|
||||
);
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("req")
|
||||
.arg("-new")
|
||||
.arg("-key")
|
||||
.arg(dir.join("ee.key"))
|
||||
.arg("-subj")
|
||||
.arg("/CN=Test EE")
|
||||
.arg("-out")
|
||||
.arg(dir.join("ee.csr")),
|
||||
);
|
||||
run(Command::new("openssl")
|
||||
.arg("genrsa")
|
||||
.arg("-out")
|
||||
.arg(dir.join("ee.key"))
|
||||
.arg("2048"));
|
||||
run(Command::new("openssl")
|
||||
.arg("req")
|
||||
.arg("-new")
|
||||
.arg("-key")
|
||||
.arg(dir.join("ee.key"))
|
||||
.arg("-subj")
|
||||
.arg("/CN=Test EE")
|
||||
.arg("-out")
|
||||
.arg(dir.join("ee.csr")));
|
||||
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("ca")
|
||||
.arg("-batch")
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf"))
|
||||
.arg("-in")
|
||||
.arg(dir.join("ee.csr"))
|
||||
.arg("-extensions")
|
||||
.arg("v3_ee")
|
||||
.arg("-out")
|
||||
.arg(dir.join("ee.pem")),
|
||||
);
|
||||
run(Command::new("openssl")
|
||||
.arg("ca")
|
||||
.arg("-batch")
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf"))
|
||||
.arg("-in")
|
||||
.arg(dir.join("ee.csr"))
|
||||
.arg("-extensions")
|
||||
.arg("v3_ee")
|
||||
.arg("-out")
|
||||
.arg(dir.join("ee.pem")));
|
||||
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("x509")
|
||||
.arg("-in")
|
||||
.arg(dir.join("issuer.pem"))
|
||||
.arg("-outform")
|
||||
.arg("DER")
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.cer")),
|
||||
);
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("x509")
|
||||
.arg("-in")
|
||||
.arg(dir.join("ee.pem"))
|
||||
.arg("-outform")
|
||||
.arg("DER")
|
||||
.arg("-out")
|
||||
.arg(dir.join("ee.cer")),
|
||||
);
|
||||
run(Command::new("openssl")
|
||||
.arg("x509")
|
||||
.arg("-in")
|
||||
.arg(dir.join("issuer.pem"))
|
||||
.arg("-outform")
|
||||
.arg("DER")
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.cer")));
|
||||
run(Command::new("openssl")
|
||||
.arg("x509")
|
||||
.arg("-in")
|
||||
.arg(dir.join("ee.pem"))
|
||||
.arg("-outform")
|
||||
.arg("DER")
|
||||
.arg("-out")
|
||||
.arg(dir.join("ee.cer")));
|
||||
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("ca")
|
||||
.arg("-gencrl")
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf"))
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.crl.pem")),
|
||||
);
|
||||
run(
|
||||
Command::new("openssl")
|
||||
.arg("crl")
|
||||
.arg("-in")
|
||||
.arg(dir.join("issuer.crl.pem"))
|
||||
.arg("-outform")
|
||||
.arg("DER")
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.crl")),
|
||||
);
|
||||
run(Command::new("openssl")
|
||||
.arg("ca")
|
||||
.arg("-gencrl")
|
||||
.arg("-config")
|
||||
.arg(dir.join("openssl.cnf"))
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.crl.pem")));
|
||||
run(Command::new("openssl")
|
||||
.arg("crl")
|
||||
.arg("-in")
|
||||
.arg(dir.join("issuer.crl.pem"))
|
||||
.arg("-outform")
|
||||
.arg("DER")
|
||||
.arg("-out")
|
||||
.arg(dir.join("issuer.crl")));
|
||||
|
||||
Generated {
|
||||
issuer_ca_der: std::fs::read(dir.join("issuer.cer")).expect("read issuer der"),
|
||||
@@ -203,16 +185,30 @@ authorityKeyIdentifier = keyid:always
|
||||
fn ee_key_usage_digital_signature_only_is_accepted() {
|
||||
let g = generate_issuer_ca_ee_and_crl("keyUsage = critical, digitalSignature\n");
|
||||
let now = time::OffsetDateTime::now_utc();
|
||||
validate_ee_cert_path(&g.ee_der, &g.issuer_ca_der, &g.issuer_crl_der, None, None, now)
|
||||
.expect("valid EE path");
|
||||
validate_ee_cert_path(
|
||||
&g.ee_der,
|
||||
&g.issuer_ca_der,
|
||||
&g.issuer_crl_der,
|
||||
None,
|
||||
None,
|
||||
now,
|
||||
)
|
||||
.expect("valid EE path");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ee_key_usage_missing_is_rejected() {
|
||||
let g = generate_issuer_ca_ee_and_crl("");
|
||||
let now = time::OffsetDateTime::now_utc();
|
||||
let err = validate_ee_cert_path(&g.ee_der, &g.issuer_ca_der, &g.issuer_crl_der, None, None, now)
|
||||
.unwrap_err();
|
||||
let err = validate_ee_cert_path(
|
||||
&g.ee_der,
|
||||
&g.issuer_ca_der,
|
||||
&g.issuer_crl_der,
|
||||
None,
|
||||
None,
|
||||
now,
|
||||
)
|
||||
.unwrap_err();
|
||||
assert!(matches!(err, CertPathError::KeyUsageMissing), "{err}");
|
||||
}
|
||||
|
||||
@@ -220,16 +216,31 @@ fn ee_key_usage_missing_is_rejected() {
|
||||
fn ee_key_usage_not_critical_is_rejected() {
|
||||
let g = generate_issuer_ca_ee_and_crl("keyUsage = digitalSignature\n");
|
||||
let now = time::OffsetDateTime::now_utc();
|
||||
let err = validate_ee_cert_path(&g.ee_der, &g.issuer_ca_der, &g.issuer_crl_der, None, None, now)
|
||||
.unwrap_err();
|
||||
let err = validate_ee_cert_path(
|
||||
&g.ee_der,
|
||||
&g.issuer_ca_der,
|
||||
&g.issuer_crl_der,
|
||||
None,
|
||||
None,
|
||||
now,
|
||||
)
|
||||
.unwrap_err();
|
||||
assert!(matches!(err, CertPathError::KeyUsageNotCritical), "{err}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ee_key_usage_wrong_bits_is_rejected() {
|
||||
let g = generate_issuer_ca_ee_and_crl("keyUsage = critical, digitalSignature, keyEncipherment\n");
|
||||
let g =
|
||||
generate_issuer_ca_ee_and_crl("keyUsage = critical, digitalSignature, keyEncipherment\n");
|
||||
let now = time::OffsetDateTime::now_utc();
|
||||
let err = validate_ee_cert_path(&g.ee_der, &g.issuer_ca_der, &g.issuer_crl_der, None, None, now)
|
||||
.unwrap_err();
|
||||
let err = validate_ee_cert_path(
|
||||
&g.ee_der,
|
||||
&g.issuer_ca_der,
|
||||
&g.issuer_crl_der,
|
||||
None,
|
||||
None,
|
||||
now,
|
||||
)
|
||||
.unwrap_err();
|
||||
assert!(matches!(err, CertPathError::KeyUsageInvalidBits), "{err}");
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ fn cli_run_offline_mode_executes_and_writes_json() {
|
||||
|
||||
let tal_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("tests/fixtures/tal/apnic-rfc7730-https.tal");
|
||||
let ta_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("tests/fixtures/ta/apnic-ta.cer");
|
||||
let ta_path =
|
||||
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/ta/apnic-ta.cer");
|
||||
|
||||
let argv = vec![
|
||||
"rpki".to_string(),
|
||||
@@ -39,4 +39,3 @@ fn cli_run_offline_mode_executes_and_writes_json() {
|
||||
let v: serde_json::Value = serde_json::from_slice(&bytes).expect("parse report json");
|
||||
assert_eq!(v["format_version"], 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ fn cli_offline_smoke_writes_report_json() {
|
||||
|
||||
let tal_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("tests/fixtures/tal/apnic-rfc7730-https.tal");
|
||||
let ta_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("tests/fixtures/ta/apnic-ta.cer");
|
||||
let ta_path =
|
||||
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/ta/apnic-ta.cer");
|
||||
|
||||
let out = Command::new(bin)
|
||||
.args([
|
||||
@@ -51,4 +51,3 @@ fn cli_offline_smoke_writes_report_json() {
|
||||
assert!(v.get("vrps").is_some());
|
||||
assert!(v.get("aspas").is_some());
|
||||
}
|
||||
|
||||
|
||||
136
tests/test_deterministic_semantics_m4.rs
Normal file
136
tests/test_deterministic_semantics_m4.rs
Normal file
@@ -0,0 +1,136 @@
|
||||
use rpki::audit::PublicationPointAudit;
|
||||
use rpki::policy::{Policy, SignedObjectFailurePolicy};
|
||||
use rpki::storage::{PackFile, PackTime, VerifiedPublicationPointPack};
|
||||
use rpki::validation::manifest::PublicationPointSource;
|
||||
use rpki::validation::objects::process_verified_publication_point_pack_for_issuer;
|
||||
use rpki::validation::tree::{
|
||||
CaInstanceHandle, PublicationPointRunResult, PublicationPointRunner, TreeRunConfig,
|
||||
run_tree_serial_audit,
|
||||
};
|
||||
|
||||
fn fixture_bytes(path: &str) -> Vec<u8> {
|
||||
std::fs::read(std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(path))
|
||||
.unwrap_or_else(|e| panic!("read fixture {path}: {e}"))
|
||||
}
|
||||
|
||||
fn dummy_pack(files: Vec<PackFile>) -> VerifiedPublicationPointPack {
|
||||
let now = time::OffsetDateTime::now_utc();
|
||||
let manifest_rsync_uri =
|
||||
"rsync://rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft";
|
||||
VerifiedPublicationPointPack {
|
||||
format_version: VerifiedPublicationPointPack::FORMAT_VERSION_V1,
|
||||
manifest_rsync_uri: manifest_rsync_uri.to_string(),
|
||||
publication_point_rsync_uri: "rsync://rpki.cernet.net/repo/cernet/0/".to_string(),
|
||||
this_update: PackTime::from_utc_offset_datetime(now),
|
||||
next_update: PackTime::from_utc_offset_datetime(now + time::Duration::hours(1)),
|
||||
verified_at: PackTime::from_utc_offset_datetime(now),
|
||||
manifest_bytes: fixture_bytes(
|
||||
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
|
||||
),
|
||||
files,
|
||||
}
|
||||
}
|
||||
|
||||
struct SinglePackRunner {
|
||||
policy: Policy,
|
||||
pack: VerifiedPublicationPointPack,
|
||||
}
|
||||
|
||||
impl PublicationPointRunner for SinglePackRunner {
|
||||
fn run_publication_point(
|
||||
&self,
|
||||
ca: &CaInstanceHandle,
|
||||
) -> Result<PublicationPointRunResult, String> {
|
||||
let objects = process_verified_publication_point_pack_for_issuer(
|
||||
&self.pack,
|
||||
&self.policy,
|
||||
&ca.ca_certificate_der,
|
||||
ca.ca_certificate_rsync_uri.as_deref(),
|
||||
ca.effective_ip_resources.as_ref(),
|
||||
ca.effective_as_resources.as_ref(),
|
||||
time::OffsetDateTime::now_utc(),
|
||||
);
|
||||
|
||||
Ok(PublicationPointRunResult {
|
||||
source: PublicationPointSource::Fresh,
|
||||
pack: self.pack.clone(),
|
||||
warnings: Vec::new(),
|
||||
objects,
|
||||
audit: PublicationPointAudit::default(),
|
||||
discovered_children: Vec::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn crl_mismatch_drops_publication_point_and_cites_rfc_sections() {
|
||||
let roa_bytes =
|
||||
fixture_bytes("tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS4538.roa");
|
||||
|
||||
// Include at least one CRL file but with a URI that does NOT match the EE certificate's CRLDP.
|
||||
let pack = dummy_pack(vec![
|
||||
PackFile::from_bytes_compute_sha256("rsync://example.test/repo/not-it.crl", vec![0x01]),
|
||||
PackFile::from_bytes_compute_sha256("rsync://example.test/repo/a.roa", roa_bytes),
|
||||
]);
|
||||
|
||||
let mut policy = Policy::default();
|
||||
policy.signed_object_failure_policy = SignedObjectFailurePolicy::DropPublicationPoint;
|
||||
|
||||
let runner = SinglePackRunner { policy, pack };
|
||||
|
||||
let root = CaInstanceHandle {
|
||||
depth: 0,
|
||||
ca_certificate_der: vec![0x01, 0x02, 0x03],
|
||||
ca_certificate_rsync_uri: None,
|
||||
effective_ip_resources: None,
|
||||
effective_as_resources: None,
|
||||
rsync_base_uri: "rsync://example.test/repo/".to_string(),
|
||||
manifest_rsync_uri:
|
||||
"rsync://rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft"
|
||||
.to_string(),
|
||||
publication_point_rsync_uri: "rsync://example.test/repo/".to_string(),
|
||||
rrdp_notification_uri: None,
|
||||
};
|
||||
|
||||
let out = run_tree_serial_audit(
|
||||
root,
|
||||
&runner,
|
||||
&TreeRunConfig {
|
||||
max_depth: Some(0),
|
||||
max_instances: Some(1),
|
||||
},
|
||||
)
|
||||
.expect("run tree audit");
|
||||
|
||||
assert_eq!(out.tree.instances_processed, 1);
|
||||
assert_eq!(out.tree.instances_failed, 0);
|
||||
|
||||
assert!(
|
||||
out.tree.warnings.iter().any(|w| w
|
||||
.message
|
||||
.contains("dropping publication point due to invalid ROA")),
|
||||
"expected publication point drop warning"
|
||||
);
|
||||
let w = out
|
||||
.tree
|
||||
.warnings
|
||||
.iter()
|
||||
.find(|w| {
|
||||
w.message
|
||||
.contains("dropping publication point due to invalid ROA")
|
||||
})
|
||||
.expect("warning present");
|
||||
let refs = w.rfc_refs.iter().map(|r| r.0).collect::<Vec<_>>();
|
||||
assert!(
|
||||
refs.contains(&"RFC 6487 §4.8.6"),
|
||||
"expected CRLDP RFC reference in warning: {refs:?}"
|
||||
);
|
||||
assert!(
|
||||
refs.contains(&"RFC 9286 §4.2.1"),
|
||||
"expected manifest locked-pack RFC reference in warning: {refs:?}"
|
||||
);
|
||||
|
||||
assert_eq!(out.publication_points.len(), 1);
|
||||
assert_eq!(out.publication_points[0].node_id, Some(0));
|
||||
assert_eq!(out.publication_points[0].parent_node_id, None);
|
||||
}
|
||||
@@ -22,4 +22,3 @@ fn local_dir_rsync_fetcher_normalizes_base_and_skips_non_files() {
|
||||
assert!(uris.contains(&"rsync://example.test/repo/a.txt"));
|
||||
assert!(!uris.iter().any(|u| u.ends_with("/sock")));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ use rpki::policy::{Policy, SyncPreference};
|
||||
use rpki::storage::RocksStore;
|
||||
use rpki::sync::rrdp::Fetcher;
|
||||
use rpki::validation::from_tal::{
|
||||
FromTalError, discover_root_ca_instance_from_tal, discover_root_ca_instance_from_tal_and_ta_der,
|
||||
discover_root_ca_instance_from_tal_url, run_root_from_tal_url_once,
|
||||
FromTalError, discover_root_ca_instance_from_tal,
|
||||
discover_root_ca_instance_from_tal_and_ta_der, discover_root_ca_instance_from_tal_url,
|
||||
run_root_from_tal_url_once,
|
||||
};
|
||||
use rpki::validation::objects::IssuerCaCertificateResolver;
|
||||
use url::Url;
|
||||
|
||||
struct MapFetcher {
|
||||
@@ -34,19 +34,14 @@ impl Fetcher for MapFetcher {
|
||||
struct EmptyRsync;
|
||||
|
||||
impl RsyncFetcher for EmptyRsync {
|
||||
fn fetch_objects(&self, _rsync_base_uri: &str) -> Result<Vec<(String, Vec<u8>)>, RsyncFetchError> {
|
||||
fn fetch_objects(
|
||||
&self,
|
||||
_rsync_base_uri: &str,
|
||||
) -> Result<Vec<(String, Vec<u8>)>, RsyncFetchError> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
struct NullResolver;
|
||||
|
||||
impl IssuerCaCertificateResolver for NullResolver {
|
||||
fn resolve_by_subject_dn(&self, _subject_dn: &str) -> Option<Vec<u8>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn apnic_tal_bytes() -> Vec<u8> {
|
||||
std::fs::read("tests/fixtures/tal/apnic-rfc7730-https.tal").expect("read apnic TAL fixture")
|
||||
}
|
||||
@@ -94,7 +89,8 @@ fn discover_root_tries_multiple_ta_uris_until_one_succeeds() {
|
||||
let tal_bytes = apnic_tal_bytes();
|
||||
let mut tal = Tal::decode_bytes(&tal_bytes).expect("decode TAL");
|
||||
let good_uri = tal.ta_uris[0].clone();
|
||||
tal.ta_uris.insert(0, Url::parse("https://example.invalid/bad.cer").unwrap());
|
||||
tal.ta_uris
|
||||
.insert(0, Url::parse("https://example.invalid/bad.cer").unwrap());
|
||||
|
||||
let mut map = HashMap::new();
|
||||
map.insert(good_uri.as_str().to_string(), apnic_ta_der());
|
||||
@@ -171,11 +167,9 @@ fn run_root_from_tal_url_once_propagates_run_error_when_repo_is_empty() {
|
||||
"https://example.test/apnic.tal",
|
||||
&fetcher,
|
||||
&EmptyRsync,
|
||||
&NullResolver,
|
||||
time::OffsetDateTime::now_utc(),
|
||||
)
|
||||
.unwrap_err();
|
||||
|
||||
assert!(matches!(err, FromTalError::Run(_)));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
use rpki::data_model::crl::RpkixCrl;
|
||||
@@ -7,9 +6,7 @@ use rpki::data_model::rc::ResourceCertificate;
|
||||
use rpki::policy::{Policy, SignedObjectFailurePolicy};
|
||||
use rpki::storage::{PackFile, RocksStore};
|
||||
use rpki::validation::manifest::process_manifest_publication_point;
|
||||
use rpki::validation::objects::{
|
||||
IssuerCaCertificateResolver, process_verified_publication_point_pack,
|
||||
};
|
||||
use rpki::validation::objects::process_verified_publication_point_pack_for_issuer;
|
||||
|
||||
fn fixture_to_rsync_uri(path: &Path) -> String {
|
||||
let rel = path
|
||||
@@ -33,28 +30,11 @@ fn fixture_dir_to_rsync_uri(dir: &Path) -> String {
|
||||
s
|
||||
}
|
||||
|
||||
struct EmptyResolver;
|
||||
|
||||
impl IssuerCaCertificateResolver for EmptyResolver {
|
||||
fn resolve_by_subject_dn(&self, _subject_dn: &str) -> Option<Vec<u8>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
struct MapResolver {
|
||||
by_subject_dn: HashMap<String, Vec<u8>>,
|
||||
}
|
||||
|
||||
impl IssuerCaCertificateResolver for MapResolver {
|
||||
fn resolve_by_subject_dn(&self, subject_dn: &str) -> Option<Vec<u8>> {
|
||||
self.by_subject_dn.get(subject_dn).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
fn build_cernet_pack_and_validation_time() -> (
|
||||
rpki::storage::VerifiedPublicationPointPack,
|
||||
time::OffsetDateTime,
|
||||
MapResolver,
|
||||
Vec<u8>,
|
||||
ResourceCertificate,
|
||||
) {
|
||||
let manifest_path = Path::new(
|
||||
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
|
||||
@@ -112,44 +92,60 @@ fn build_cernet_pack_and_validation_time() -> (
|
||||
}
|
||||
t += time::Duration::seconds(1);
|
||||
|
||||
let resolver = MapResolver {
|
||||
by_subject_dn: HashMap::from([(issuer_ca.tbs.subject_dn, issuer_ca_der)]),
|
||||
};
|
||||
|
||||
(out.pack, t, resolver)
|
||||
(out.pack, t, issuer_ca_der, issuer_ca)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_crl_causes_roas_to_be_dropped_under_drop_object_policy() {
|
||||
let (mut pack, validation_time, resolver) = build_cernet_pack_and_validation_time();
|
||||
let (mut pack, validation_time, issuer_ca_der, issuer_ca) =
|
||||
build_cernet_pack_and_validation_time();
|
||||
pack.files.retain(|f| !f.rsync_uri.ends_with(".crl"));
|
||||
|
||||
let mut policy = Policy::default();
|
||||
policy.signed_object_failure_policy = SignedObjectFailurePolicy::DropObject;
|
||||
|
||||
let out = process_verified_publication_point_pack(&pack, &policy, &resolver, validation_time)
|
||||
.expect("drop_object should not fail the publication point");
|
||||
let out = process_verified_publication_point_pack_for_issuer(
|
||||
&pack,
|
||||
&policy,
|
||||
&issuer_ca_der,
|
||||
None,
|
||||
issuer_ca.tbs.extensions.ip_resources.as_ref(),
|
||||
issuer_ca.tbs.extensions.as_resources.as_ref(),
|
||||
validation_time,
|
||||
);
|
||||
assert!(out.vrps.is_empty());
|
||||
assert!(!out.warnings.is_empty());
|
||||
assert!(out.stats.publication_point_dropped);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_issuer_ca_cert_causes_roas_to_be_dropped_under_drop_object_policy() {
|
||||
let (pack, validation_time, _resolver) = build_cernet_pack_and_validation_time();
|
||||
fn wrong_issuer_ca_cert_causes_roas_to_be_dropped_under_drop_object_policy() {
|
||||
let (pack, validation_time, _issuer_ca_der, _issuer_ca) =
|
||||
build_cernet_pack_and_validation_time();
|
||||
|
||||
let mut policy = Policy::default();
|
||||
policy.signed_object_failure_policy = SignedObjectFailurePolicy::DropObject;
|
||||
|
||||
let out =
|
||||
process_verified_publication_point_pack(&pack, &policy, &EmptyResolver, validation_time)
|
||||
.expect("drop_object should not fail the publication point");
|
||||
// Use an unrelated trust anchor certificate as the issuer to force EE cert path validation to fail.
|
||||
let wrong_issuer_ca_der =
|
||||
std::fs::read("tests/fixtures/ta/arin-ta.cer").expect("read wrong issuer ca");
|
||||
let out = process_verified_publication_point_pack_for_issuer(
|
||||
&pack,
|
||||
&policy,
|
||||
&wrong_issuer_ca_der,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
validation_time,
|
||||
);
|
||||
assert!(out.vrps.is_empty());
|
||||
assert!(!out.warnings.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_aspa_object_is_reported_as_warning_under_drop_object_policy() {
|
||||
let (mut pack, validation_time, resolver) = build_cernet_pack_and_validation_time();
|
||||
let (mut pack, validation_time, issuer_ca_der, issuer_ca) =
|
||||
build_cernet_pack_and_validation_time();
|
||||
|
||||
let uri = "rsync://rpki.cernet.net/repo/cernet/0/INVALID.asa".to_string();
|
||||
pack.files.push(PackFile::from_bytes_compute_sha256(
|
||||
@@ -160,8 +156,15 @@ fn invalid_aspa_object_is_reported_as_warning_under_drop_object_policy() {
|
||||
let mut policy = Policy::default();
|
||||
policy.signed_object_failure_policy = SignedObjectFailurePolicy::DropObject;
|
||||
|
||||
let out = process_verified_publication_point_pack(&pack, &policy, &resolver, validation_time)
|
||||
.expect("drop_object should not fail");
|
||||
let out = process_verified_publication_point_pack_for_issuer(
|
||||
&pack,
|
||||
&policy,
|
||||
&issuer_ca_der,
|
||||
None,
|
||||
issuer_ca.tbs.extensions.ip_resources.as_ref(),
|
||||
issuer_ca.tbs.extensions.as_resources.as_ref(),
|
||||
validation_time,
|
||||
);
|
||||
|
||||
assert!(
|
||||
out.warnings
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
use rpki::data_model::crl::RpkixCrl;
|
||||
@@ -7,9 +6,7 @@ use rpki::data_model::rc::ResourceCertificate;
|
||||
use rpki::policy::{Policy, SignedObjectFailurePolicy};
|
||||
use rpki::storage::{PackFile, RocksStore};
|
||||
use rpki::validation::manifest::process_manifest_publication_point;
|
||||
use rpki::validation::objects::{
|
||||
IssuerCaCertificateResolver, ObjectsProcessError, process_verified_publication_point_pack,
|
||||
};
|
||||
use rpki::validation::objects::process_verified_publication_point_pack_for_issuer;
|
||||
|
||||
fn fixture_to_rsync_uri(path: &Path) -> String {
|
||||
let rel = path
|
||||
@@ -33,20 +30,11 @@ fn fixture_dir_to_rsync_uri(dir: &Path) -> String {
|
||||
s
|
||||
}
|
||||
|
||||
struct MapResolver {
|
||||
by_subject_dn: HashMap<String, Vec<u8>>,
|
||||
}
|
||||
|
||||
impl IssuerCaCertificateResolver for MapResolver {
|
||||
fn resolve_by_subject_dn(&self, subject_dn: &str) -> Option<Vec<u8>> {
|
||||
self.by_subject_dn.get(subject_dn).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
fn build_cernet_pack_and_validation_time() -> (
|
||||
rpki::storage::VerifiedPublicationPointPack,
|
||||
time::OffsetDateTime,
|
||||
MapResolver,
|
||||
Vec<u8>,
|
||||
ResourceCertificate,
|
||||
) {
|
||||
let manifest_path = Path::new(
|
||||
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
|
||||
@@ -109,19 +97,13 @@ fn build_cernet_pack_and_validation_time() -> (
|
||||
}
|
||||
t += time::Duration::seconds(1);
|
||||
|
||||
let mut resolver = MapResolver {
|
||||
by_subject_dn: HashMap::new(),
|
||||
};
|
||||
resolver
|
||||
.by_subject_dn
|
||||
.insert(issuer_ca.tbs.subject_dn, issuer_ca_der);
|
||||
|
||||
(out.pack, t, resolver)
|
||||
(out.pack, t, issuer_ca_der, issuer_ca)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_object_policy_drops_only_failing_object() {
|
||||
let (mut pack, validation_time, resolver) = build_cernet_pack_and_validation_time();
|
||||
let (mut pack, validation_time, issuer_ca_der, issuer_ca) =
|
||||
build_cernet_pack_and_validation_time();
|
||||
|
||||
let valid_roa_uri = pack
|
||||
.files
|
||||
@@ -145,8 +127,15 @@ fn drop_object_policy_drops_only_failing_object() {
|
||||
let mut policy = Policy::default();
|
||||
policy.signed_object_failure_policy = SignedObjectFailurePolicy::DropObject;
|
||||
|
||||
let out = process_verified_publication_point_pack(&pack, &policy, &resolver, validation_time)
|
||||
.expect("drop_object should succeed");
|
||||
let out = process_verified_publication_point_pack_for_issuer(
|
||||
&pack,
|
||||
&policy,
|
||||
&issuer_ca_der,
|
||||
None,
|
||||
issuer_ca.tbs.extensions.ip_resources.as_ref(),
|
||||
issuer_ca.tbs.extensions.as_resources.as_ref(),
|
||||
validation_time,
|
||||
);
|
||||
|
||||
assert!(
|
||||
out.vrps.iter().any(|v| v.asn == 4538),
|
||||
@@ -161,8 +150,9 @@ fn drop_object_policy_drops_only_failing_object() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drop_publication_point_policy_fails_the_publication_point() {
|
||||
let (mut pack, validation_time, resolver) = build_cernet_pack_and_validation_time();
|
||||
fn drop_publication_point_policy_drops_the_publication_point() {
|
||||
let (mut pack, validation_time, issuer_ca_der, issuer_ca) =
|
||||
build_cernet_pack_and_validation_time();
|
||||
|
||||
let tamper_idx = pack
|
||||
.files
|
||||
@@ -179,11 +169,19 @@ fn drop_publication_point_policy_fails_the_publication_point() {
|
||||
let mut policy = Policy::default();
|
||||
policy.signed_object_failure_policy = SignedObjectFailurePolicy::DropPublicationPoint;
|
||||
|
||||
let err = process_verified_publication_point_pack(&pack, &policy, &resolver, validation_time)
|
||||
.expect_err("drop_publication_point should fail");
|
||||
match err {
|
||||
ObjectsProcessError::PublicationPointDropped { rsync_uri, .. } => {
|
||||
assert_eq!(rsync_uri, victim_uri);
|
||||
}
|
||||
}
|
||||
let out = process_verified_publication_point_pack_for_issuer(
|
||||
&pack,
|
||||
&policy,
|
||||
&issuer_ca_der,
|
||||
None,
|
||||
issuer_ca.tbs.extensions.ip_resources.as_ref(),
|
||||
issuer_ca.tbs.extensions.as_resources.as_ref(),
|
||||
validation_time,
|
||||
);
|
||||
assert!(out.stats.publication_point_dropped);
|
||||
assert!(out.vrps.is_empty(), "expected publication point dropped");
|
||||
assert!(
|
||||
out.audit.iter().any(|a| a.rsync_uri == victim_uri),
|
||||
"expected audit entry for victim object"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,10 +4,7 @@ use rpki::storage::{PackFile, PackTime, RocksStore, VerifiedPublicationPointPack
|
||||
use rpki::sync::repo::sync_publication_point;
|
||||
use rpki::sync::rrdp::Fetcher;
|
||||
use rpki::validation::manifest::process_manifest_publication_point;
|
||||
use rpki::validation::objects::{
|
||||
IssuerCaCertificateResolver, process_verified_publication_point_pack,
|
||||
process_verified_publication_point_pack_for_issuer,
|
||||
};
|
||||
use rpki::validation::objects::process_verified_publication_point_pack_for_issuer;
|
||||
|
||||
struct NoopHttpFetcher;
|
||||
impl Fetcher for NoopHttpFetcher {
|
||||
@@ -24,13 +21,20 @@ fn cernet_fixture() -> (std::path::PathBuf, String, String) {
|
||||
(dir, rsync_base_uri, manifest_file)
|
||||
}
|
||||
|
||||
fn validation_time_from_manifest_fixture(dir: &std::path::Path, manifest_file: &str) -> time::OffsetDateTime {
|
||||
fn validation_time_from_manifest_fixture(
|
||||
dir: &std::path::Path,
|
||||
manifest_file: &str,
|
||||
) -> time::OffsetDateTime {
|
||||
let bytes = std::fs::read(dir.join(manifest_file)).expect("read manifest fixture");
|
||||
let mft = rpki::data_model::manifest::ManifestObject::decode_der(&bytes).expect("decode mft");
|
||||
let this_update = mft.manifest.this_update;
|
||||
let next_update = mft.manifest.next_update;
|
||||
let candidate = this_update + time::Duration::seconds(60);
|
||||
if candidate < next_update { candidate } else { this_update }
|
||||
if candidate < next_update {
|
||||
candidate
|
||||
} else {
|
||||
this_update
|
||||
}
|
||||
}
|
||||
|
||||
fn issuer_ca_fixture() -> Vec<u8> {
|
||||
@@ -129,7 +133,11 @@ fn process_pack_for_issuer_extracts_vrps_from_real_cernet_fixture() {
|
||||
validation_time,
|
||||
);
|
||||
|
||||
assert!(out.vrps.len() > 10, "expected many VRPs, got {}", out.vrps.len());
|
||||
assert!(
|
||||
out.vrps.len() > 10,
|
||||
"expected many VRPs, got {}",
|
||||
out.vrps.len()
|
||||
);
|
||||
assert!(out.aspas.is_empty());
|
||||
}
|
||||
|
||||
@@ -187,7 +195,10 @@ fn signed_object_failure_policy_drop_object_drops_only_bad_object() {
|
||||
"expected one audit entry per ROA"
|
||||
);
|
||||
assert!(
|
||||
out.audit.iter().any(|e| e.rsync_uri == pack.files[bad_idx].rsync_uri && matches!(e.result, rpki::audit::AuditObjectResult::Error)),
|
||||
out.audit
|
||||
.iter()
|
||||
.any(|e| e.rsync_uri == pack.files[bad_idx].rsync_uri
|
||||
&& matches!(e.result, rpki::audit::AuditObjectResult::Error)),
|
||||
"expected audit error for the corrupted ROA"
|
||||
);
|
||||
}
|
||||
@@ -303,10 +314,8 @@ fn process_pack_for_issuer_handles_invalid_aspa_bytes() {
|
||||
let manifest_rsync_uri = format!("{rsync_base_uri}{manifest_file}");
|
||||
let validation_time = validation_time_from_manifest_fixture(&dir, &manifest_file);
|
||||
let manifest_bytes = std::fs::read(dir.join(&manifest_file)).expect("read mft");
|
||||
let crl_bytes = std::fs::read(dir.join(
|
||||
"05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl",
|
||||
))
|
||||
.expect("read crl");
|
||||
let crl_bytes =
|
||||
std::fs::read(dir.join("05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl")).expect("read crl");
|
||||
|
||||
let pack = minimal_pack(
|
||||
&manifest_rsync_uri,
|
||||
@@ -345,10 +354,8 @@ fn process_pack_for_issuer_drop_publication_point_on_invalid_aspa_bytes() {
|
||||
let manifest_rsync_uri = format!("{rsync_base_uri}{manifest_file}");
|
||||
let validation_time = validation_time_from_manifest_fixture(&dir, &manifest_file);
|
||||
let manifest_bytes = std::fs::read(dir.join(&manifest_file)).expect("read mft");
|
||||
let crl_bytes = std::fs::read(dir.join(
|
||||
"05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl",
|
||||
))
|
||||
.expect("read crl");
|
||||
let crl_bytes =
|
||||
std::fs::read(dir.join("05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl")).expect("read crl");
|
||||
|
||||
let pack = minimal_pack(
|
||||
&manifest_rsync_uri,
|
||||
@@ -384,80 +391,4 @@ fn process_pack_for_issuer_drop_publication_point_on_invalid_aspa_bytes() {
|
||||
assert!(!out.warnings.is_empty());
|
||||
}
|
||||
|
||||
struct NoIssuerResolver;
|
||||
impl IssuerCaCertificateResolver for NoIssuerResolver {
|
||||
fn resolve_by_subject_dn(&self, _subject_dn: &str) -> Option<Vec<u8>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
struct AlwaysIssuerResolver {
|
||||
issuer_ca_der: Vec<u8>,
|
||||
}
|
||||
|
||||
impl IssuerCaCertificateResolver for AlwaysIssuerResolver {
|
||||
fn resolve_by_subject_dn(&self, _subject_dn: &str) -> Option<Vec<u8>> {
|
||||
Some(self.issuer_ca_der.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_verified_pack_indexes_ca_certs_by_subject() {
|
||||
let (dir, rsync_base_uri, manifest_file) = cernet_fixture();
|
||||
let manifest_rsync_uri = format!("{rsync_base_uri}{manifest_file}");
|
||||
let validation_time = validation_time_from_manifest_fixture(&dir, &manifest_file);
|
||||
let manifest_bytes = std::fs::read(dir.join(&manifest_file)).expect("read mft");
|
||||
|
||||
// Add a real CA certificate to exercise CA indexing logic.
|
||||
let ca_der = issuer_ca_fixture();
|
||||
|
||||
let pack = minimal_pack(
|
||||
&manifest_rsync_uri,
|
||||
&rsync_base_uri,
|
||||
manifest_bytes,
|
||||
vec![PackFile::from_bytes_compute_sha256(
|
||||
format!("{rsync_base_uri}some-ca.cer"),
|
||||
ca_der,
|
||||
)],
|
||||
validation_time,
|
||||
);
|
||||
|
||||
let policy = Policy::default();
|
||||
let out = process_verified_publication_point_pack(
|
||||
&pack,
|
||||
&policy,
|
||||
&NoIssuerResolver,
|
||||
validation_time,
|
||||
)
|
||||
.expect("process pack");
|
||||
assert!(out.vrps.is_empty());
|
||||
assert!(out.aspas.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_pack_with_resolver_extracts_vrps_from_real_cernet_fixture() {
|
||||
let (dir, rsync_base_uri, manifest_file) = cernet_fixture();
|
||||
let manifest_rsync_uri = format!("{rsync_base_uri}{manifest_file}");
|
||||
let validation_time = validation_time_from_manifest_fixture(&dir, &manifest_file);
|
||||
|
||||
let pack = build_verified_pack_from_local_rsync_fixture(
|
||||
&dir,
|
||||
&rsync_base_uri,
|
||||
&manifest_rsync_uri,
|
||||
validation_time,
|
||||
);
|
||||
|
||||
let policy = Policy::default();
|
||||
let issuer_ca_der = issuer_ca_fixture();
|
||||
let resolver = AlwaysIssuerResolver {
|
||||
issuer_ca_der: issuer_ca_der.clone(),
|
||||
};
|
||||
|
||||
let out = process_verified_publication_point_pack(&pack, &policy, &resolver, validation_time)
|
||||
.expect("process pack");
|
||||
assert!(out.vrps.len() > 10, "expected many VRPs, got {}", out.vrps.len());
|
||||
assert!(
|
||||
out.audit.len() >= pack.files.iter().filter(|f| f.rsync_uri.ends_with(".roa")).count(),
|
||||
"expected ROA audit entries"
|
||||
);
|
||||
}
|
||||
// NOTE: DN-based issuer resolution and pack-local CA indexing have been removed for determinism.
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use rpki::policy::{Policy, SignedObjectFailurePolicy};
|
||||
use rpki::storage::{PackFile, PackTime, VerifiedPublicationPointPack};
|
||||
use rpki::validation::objects::{
|
||||
IssuerCaCertificateResolver, ObjectsProcessError, process_verified_publication_point_pack,
|
||||
process_verified_publication_point_pack_for_issuer,
|
||||
};
|
||||
use rpki::validation::objects::process_verified_publication_point_pack_for_issuer;
|
||||
|
||||
fn fixture_bytes(path: &str) -> Vec<u8> {
|
||||
std::fs::read(std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(path))
|
||||
@@ -24,28 +21,36 @@ fn dummy_pack(manifest_bytes: Vec<u8>, files: Vec<PackFile>) -> VerifiedPublicat
|
||||
}
|
||||
}
|
||||
|
||||
struct NoneResolver;
|
||||
|
||||
impl IssuerCaCertificateResolver for NoneResolver {
|
||||
fn resolve_by_subject_dn(&self, _subject_dn: &str) -> Option<Vec<u8>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_pack_drop_object_on_missing_issuer_ca_for_roa() {
|
||||
fn process_pack_drop_object_on_wrong_issuer_ca_for_roa() {
|
||||
let manifest_bytes = fixture_bytes(
|
||||
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
|
||||
);
|
||||
let roa_bytes =
|
||||
fixture_bytes("tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS4538.roa");
|
||||
let roa = rpki::data_model::roa::RoaObject::decode_der(&roa_bytes).expect("decode roa");
|
||||
let ee_crldp = roa.signed_object.signed_data.certificates[0]
|
||||
.resource_cert
|
||||
.tbs
|
||||
.extensions
|
||||
.crl_distribution_points_uris
|
||||
.as_ref()
|
||||
.expect("ee crldp")[0]
|
||||
.as_str()
|
||||
.to_string();
|
||||
let crl_bytes = fixture_bytes(
|
||||
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl",
|
||||
);
|
||||
|
||||
let pack = dummy_pack(
|
||||
manifest_bytes,
|
||||
vec![PackFile::from_bytes_compute_sha256(
|
||||
"rsync://rpki.cernet.net/repo/cernet/0/AS4538.roa",
|
||||
roa_bytes,
|
||||
)],
|
||||
vec![
|
||||
PackFile::from_bytes_compute_sha256(ee_crldp, crl_bytes),
|
||||
PackFile::from_bytes_compute_sha256(
|
||||
"rsync://rpki.cernet.net/repo/cernet/0/AS4538.roa",
|
||||
roa_bytes,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
let policy = Policy {
|
||||
@@ -53,9 +58,16 @@ fn process_pack_drop_object_on_missing_issuer_ca_for_roa() {
|
||||
..Policy::default()
|
||||
};
|
||||
|
||||
let out =
|
||||
process_verified_publication_point_pack(&pack, &policy, &NoneResolver, time::OffsetDateTime::now_utc())
|
||||
.expect("drop_object should not error");
|
||||
let wrong_issuer_ca_der = fixture_bytes("tests/fixtures/ta/arin-ta.cer");
|
||||
let out = process_verified_publication_point_pack_for_issuer(
|
||||
&pack,
|
||||
&policy,
|
||||
&wrong_issuer_ca_der,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
time::OffsetDateTime::now_utc(),
|
||||
);
|
||||
|
||||
assert_eq!(out.stats.roa_total, 1);
|
||||
assert_eq!(out.stats.roa_ok, 0);
|
||||
@@ -64,12 +76,25 @@ fn process_pack_drop_object_on_missing_issuer_ca_for_roa() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_pack_drop_publication_point_on_missing_issuer_ca_for_roa_skips_rest() {
|
||||
fn process_pack_drop_publication_point_on_wrong_issuer_ca_for_roa_skips_rest() {
|
||||
let manifest_bytes = fixture_bytes(
|
||||
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
|
||||
);
|
||||
let roa_bytes =
|
||||
fixture_bytes("tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS4538.roa");
|
||||
let roa = rpki::data_model::roa::RoaObject::decode_der(&roa_bytes).expect("decode roa");
|
||||
let ee_crldp = roa.signed_object.signed_data.certificates[0]
|
||||
.resource_cert
|
||||
.tbs
|
||||
.extensions
|
||||
.crl_distribution_points_uris
|
||||
.as_ref()
|
||||
.expect("ee crldp")[0]
|
||||
.as_str()
|
||||
.to_string();
|
||||
let crl_bytes = fixture_bytes(
|
||||
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl",
|
||||
);
|
||||
let aspa_bytes = fixture_bytes(
|
||||
"tests/fixtures/repository/chloe.sobornost.net/rpki/RIPE-nljobsnijders/5m80fwYws_3FiFD7JiQjAqZ1RYQ.asa",
|
||||
);
|
||||
@@ -77,6 +102,7 @@ fn process_pack_drop_publication_point_on_missing_issuer_ca_for_roa_skips_rest()
|
||||
let pack = dummy_pack(
|
||||
manifest_bytes,
|
||||
vec![
|
||||
PackFile::from_bytes_compute_sha256(ee_crldp, crl_bytes),
|
||||
PackFile::from_bytes_compute_sha256(
|
||||
"rsync://example.test/repo/pp/first.roa",
|
||||
roa_bytes.clone(),
|
||||
@@ -85,10 +111,7 @@ fn process_pack_drop_publication_point_on_missing_issuer_ca_for_roa_skips_rest()
|
||||
"rsync://example.test/repo/pp/second.roa",
|
||||
roa_bytes,
|
||||
),
|
||||
PackFile::from_bytes_compute_sha256(
|
||||
"rsync://example.test/repo/pp/x.asa",
|
||||
aspa_bytes,
|
||||
),
|
||||
PackFile::from_bytes_compute_sha256("rsync://example.test/repo/pp/x.asa", aspa_bytes),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -97,28 +120,48 @@ fn process_pack_drop_publication_point_on_missing_issuer_ca_for_roa_skips_rest()
|
||||
..Policy::default()
|
||||
};
|
||||
|
||||
let err =
|
||||
process_verified_publication_point_pack(&pack, &policy, &NoneResolver, time::OffsetDateTime::now_utc())
|
||||
.unwrap_err();
|
||||
assert!(matches!(err, ObjectsProcessError::PublicationPointDropped { .. }));
|
||||
assert!(err.to_string().contains("drop_publication_point"));
|
||||
let wrong_issuer_ca_der = fixture_bytes("tests/fixtures/ta/arin-ta.cer");
|
||||
let out = process_verified_publication_point_pack_for_issuer(
|
||||
&pack,
|
||||
&policy,
|
||||
&wrong_issuer_ca_der,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
time::OffsetDateTime::now_utc(),
|
||||
);
|
||||
assert!(out.stats.publication_point_dropped);
|
||||
assert_eq!(out.warnings.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_pack_drop_object_on_missing_issuer_ca_for_aspa() {
|
||||
fn process_pack_drop_object_on_wrong_issuer_ca_for_aspa() {
|
||||
let manifest_bytes = fixture_bytes(
|
||||
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
|
||||
);
|
||||
let aspa_bytes = fixture_bytes(
|
||||
"tests/fixtures/repository/chloe.sobornost.net/rpki/RIPE-nljobsnijders/5m80fwYws_3FiFD7JiQjAqZ1RYQ.asa",
|
||||
);
|
||||
let aspa = rpki::data_model::aspa::AspaObject::decode_der(&aspa_bytes).expect("decode aspa");
|
||||
let ee_crldp = aspa.signed_object.signed_data.certificates[0]
|
||||
.resource_cert
|
||||
.tbs
|
||||
.extensions
|
||||
.crl_distribution_points_uris
|
||||
.as_ref()
|
||||
.expect("ee crldp")[0]
|
||||
.as_str()
|
||||
.to_string();
|
||||
let crl_bytes = fixture_bytes(
|
||||
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl",
|
||||
);
|
||||
|
||||
let pack = dummy_pack(
|
||||
manifest_bytes,
|
||||
vec![PackFile::from_bytes_compute_sha256(
|
||||
"rsync://example.test/repo/pp/x.asa",
|
||||
aspa_bytes,
|
||||
)],
|
||||
vec![
|
||||
PackFile::from_bytes_compute_sha256(ee_crldp, crl_bytes),
|
||||
PackFile::from_bytes_compute_sha256("rsync://example.test/repo/pp/x.asa", aspa_bytes),
|
||||
],
|
||||
);
|
||||
|
||||
let policy = Policy {
|
||||
@@ -126,9 +169,16 @@ fn process_pack_drop_object_on_missing_issuer_ca_for_aspa() {
|
||||
..Policy::default()
|
||||
};
|
||||
|
||||
let out =
|
||||
process_verified_publication_point_pack(&pack, &policy, &NoneResolver, time::OffsetDateTime::now_utc())
|
||||
.expect("drop_object should not error");
|
||||
let wrong_issuer_ca_der = fixture_bytes("tests/fixtures/ta/arin-ta.cer");
|
||||
let out = process_verified_publication_point_pack_for_issuer(
|
||||
&pack,
|
||||
&policy,
|
||||
&wrong_issuer_ca_der,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
time::OffsetDateTime::now_utc(),
|
||||
);
|
||||
|
||||
assert_eq!(out.stats.aspa_total, 1);
|
||||
assert_eq!(out.stats.aspa_ok, 0);
|
||||
@@ -137,7 +187,7 @@ fn process_pack_drop_object_on_missing_issuer_ca_for_aspa() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_pack_drop_publication_point_on_missing_issuer_ca_for_aspa_skips_rest() {
|
||||
fn process_pack_drop_publication_point_on_wrong_issuer_ca_for_aspa_skips_rest() {
|
||||
let manifest_bytes = fixture_bytes(
|
||||
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
|
||||
);
|
||||
@@ -146,18 +196,26 @@ fn process_pack_drop_publication_point_on_missing_issuer_ca_for_aspa_skips_rest(
|
||||
let aspa_bytes = fixture_bytes(
|
||||
"tests/fixtures/repository/chloe.sobornost.net/rpki/RIPE-nljobsnijders/5m80fwYws_3FiFD7JiQjAqZ1RYQ.asa",
|
||||
);
|
||||
let aspa = rpki::data_model::aspa::AspaObject::decode_der(&aspa_bytes).expect("decode aspa");
|
||||
let ee_crldp = aspa.signed_object.signed_data.certificates[0]
|
||||
.resource_cert
|
||||
.tbs
|
||||
.extensions
|
||||
.crl_distribution_points_uris
|
||||
.as_ref()
|
||||
.expect("ee crldp")[0]
|
||||
.as_str()
|
||||
.to_string();
|
||||
let crl_bytes = fixture_bytes(
|
||||
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.crl",
|
||||
);
|
||||
|
||||
let pack = dummy_pack(
|
||||
manifest_bytes,
|
||||
vec![
|
||||
PackFile::from_bytes_compute_sha256(
|
||||
"rsync://example.test/repo/pp/x.asa",
|
||||
aspa_bytes,
|
||||
),
|
||||
PackFile::from_bytes_compute_sha256(
|
||||
"rsync://example.test/repo/pp/y.roa",
|
||||
roa_bytes,
|
||||
),
|
||||
PackFile::from_bytes_compute_sha256(ee_crldp, crl_bytes),
|
||||
PackFile::from_bytes_compute_sha256("rsync://example.test/repo/pp/x.asa", aspa_bytes),
|
||||
PackFile::from_bytes_compute_sha256("rsync://example.test/repo/pp/y.roa", roa_bytes),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -166,10 +224,17 @@ fn process_pack_drop_publication_point_on_missing_issuer_ca_for_aspa_skips_rest(
|
||||
..Policy::default()
|
||||
};
|
||||
|
||||
let err =
|
||||
process_verified_publication_point_pack(&pack, &policy, &NoneResolver, time::OffsetDateTime::now_utc())
|
||||
.unwrap_err();
|
||||
assert!(matches!(err, ObjectsProcessError::PublicationPointDropped { .. }));
|
||||
let wrong_issuer_ca_der = fixture_bytes("tests/fixtures/ta/arin-ta.cer");
|
||||
let out = process_verified_publication_point_pack_for_issuer(
|
||||
&pack,
|
||||
&policy,
|
||||
&wrong_issuer_ca_der,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
time::OffsetDateTime::now_utc(),
|
||||
);
|
||||
assert!(out.stats.publication_point_dropped);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -186,14 +251,8 @@ fn process_pack_for_issuer_marks_objects_skipped_when_missing_issuer_crl() {
|
||||
let pack = dummy_pack(
|
||||
manifest_bytes,
|
||||
vec![
|
||||
PackFile::from_bytes_compute_sha256(
|
||||
"rsync://example.test/repo/pp/a.roa",
|
||||
roa_bytes,
|
||||
),
|
||||
PackFile::from_bytes_compute_sha256(
|
||||
"rsync://example.test/repo/pp/a.asa",
|
||||
aspa_bytes,
|
||||
),
|
||||
PackFile::from_bytes_compute_sha256("rsync://example.test/repo/pp/a.roa", roa_bytes),
|
||||
PackFile::from_bytes_compute_sha256("rsync://example.test/repo/pp/a.asa", aspa_bytes),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -302,3 +361,147 @@ fn process_pack_for_issuer_drop_publication_point_records_skips_for_rest() {
|
||||
assert_eq!(out.warnings.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_pack_for_issuer_selects_crl_by_ee_crldp_uri_roa() {
|
||||
let manifest_bytes = fixture_bytes(
|
||||
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
|
||||
);
|
||||
let roa_bytes =
|
||||
fixture_bytes("tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS4538.roa");
|
||||
let roa = rpki::data_model::roa::RoaObject::decode_der(&roa_bytes).expect("decode roa");
|
||||
let ee_crldp = roa.signed_object.signed_data.certificates[0]
|
||||
.resource_cert
|
||||
.tbs
|
||||
.extensions
|
||||
.crl_distribution_points_uris
|
||||
.as_ref()
|
||||
.expect("ee crldp")[0]
|
||||
.as_str()
|
||||
.to_string();
|
||||
|
||||
// Provide a CRL file with the *exact* rsync URI referenced by the embedded EE certificate.
|
||||
// Bytes need not be valid for this test: we just want to cover deterministic selection.
|
||||
let pack = dummy_pack(
|
||||
manifest_bytes,
|
||||
vec![
|
||||
PackFile::from_bytes_compute_sha256(ee_crldp, vec![0x01]),
|
||||
PackFile::from_bytes_compute_sha256("rsync://example.test/repo/pp/a.roa", roa_bytes),
|
||||
],
|
||||
);
|
||||
|
||||
let policy = Policy {
|
||||
signed_object_failure_policy: SignedObjectFailurePolicy::DropObject,
|
||||
..Policy::default()
|
||||
};
|
||||
|
||||
let out = process_verified_publication_point_pack_for_issuer(
|
||||
&pack,
|
||||
&policy,
|
||||
&[0x01, 0x02, 0x03],
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
time::OffsetDateTime::now_utc(),
|
||||
);
|
||||
|
||||
assert_eq!(out.stats.roa_total, 1);
|
||||
assert_eq!(out.stats.roa_ok, 0, "expected validation to fail later");
|
||||
assert_eq!(out.audit.len(), 1);
|
||||
assert_eq!(out.warnings.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_pack_for_issuer_rejects_roa_when_crldp_crl_missing() {
|
||||
let manifest_bytes = fixture_bytes(
|
||||
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
|
||||
);
|
||||
let roa_bytes =
|
||||
fixture_bytes("tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS4538.roa");
|
||||
|
||||
// Pack has a CRL, but its URI does not match the embedded EE certificate CRLDP.
|
||||
let pack = dummy_pack(
|
||||
manifest_bytes,
|
||||
vec![
|
||||
PackFile::from_bytes_compute_sha256(
|
||||
"rsync://example.test/repo/pp/not-it.crl",
|
||||
vec![0x01],
|
||||
),
|
||||
PackFile::from_bytes_compute_sha256("rsync://example.test/repo/pp/a.roa", roa_bytes),
|
||||
],
|
||||
);
|
||||
|
||||
let policy = Policy {
|
||||
signed_object_failure_policy: SignedObjectFailurePolicy::DropObject,
|
||||
..Policy::default()
|
||||
};
|
||||
|
||||
let out = process_verified_publication_point_pack_for_issuer(
|
||||
&pack,
|
||||
&policy,
|
||||
&[0x01, 0x02, 0x03],
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
time::OffsetDateTime::now_utc(),
|
||||
);
|
||||
|
||||
assert_eq!(out.stats.roa_total, 1);
|
||||
assert_eq!(out.stats.roa_ok, 0);
|
||||
assert_eq!(out.audit.len(), 1);
|
||||
assert_eq!(out.warnings.len(), 1);
|
||||
assert!(
|
||||
out.warnings[0].message.contains("dropping invalid ROA")
|
||||
|| out.warnings[0]
|
||||
.message
|
||||
.contains("dropping publication point"),
|
||||
"expected deterministic CRL selection failure to surface as an invalid ROA warning"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_pack_for_issuer_selects_crl_by_ee_crldp_uri_aspa() {
|
||||
let manifest_bytes = fixture_bytes(
|
||||
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
|
||||
);
|
||||
let aspa_bytes = fixture_bytes(
|
||||
"tests/fixtures/repository/chloe.sobornost.net/rpki/RIPE-nljobsnijders/5m80fwYws_3FiFD7JiQjAqZ1RYQ.asa",
|
||||
);
|
||||
let aspa = rpki::data_model::aspa::AspaObject::decode_der(&aspa_bytes).expect("decode aspa");
|
||||
let ee_crldp = aspa.signed_object.signed_data.certificates[0]
|
||||
.resource_cert
|
||||
.tbs
|
||||
.extensions
|
||||
.crl_distribution_points_uris
|
||||
.as_ref()
|
||||
.expect("ee crldp")[0]
|
||||
.as_str()
|
||||
.to_string();
|
||||
|
||||
let pack = dummy_pack(
|
||||
manifest_bytes,
|
||||
vec![
|
||||
PackFile::from_bytes_compute_sha256(ee_crldp, vec![0x01]),
|
||||
PackFile::from_bytes_compute_sha256("rsync://example.test/repo/pp/a.asa", aspa_bytes),
|
||||
],
|
||||
);
|
||||
|
||||
let policy = Policy {
|
||||
signed_object_failure_policy: SignedObjectFailurePolicy::DropObject,
|
||||
..Policy::default()
|
||||
};
|
||||
|
||||
let out = process_verified_publication_point_pack_for_issuer(
|
||||
&pack,
|
||||
&policy,
|
||||
&[0x01, 0x02, 0x03],
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
time::OffsetDateTime::now_utc(),
|
||||
);
|
||||
|
||||
assert_eq!(out.stats.aspa_total, 1);
|
||||
assert_eq!(out.stats.aspa_ok, 0);
|
||||
assert_eq!(out.audit.len(), 1);
|
||||
assert_eq!(out.warnings.len(), 1);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
use rpki::data_model::crl::RpkixCrl;
|
||||
@@ -8,7 +7,6 @@ use rpki::fetch::rsync::LocalDirRsyncFetcher;
|
||||
use rpki::policy::{Policy, SyncPreference};
|
||||
use rpki::storage::RocksStore;
|
||||
use rpki::sync::rrdp::Fetcher;
|
||||
use rpki::validation::objects::IssuerCaCertificateResolver;
|
||||
use rpki::validation::run::{run_publication_point_once, verified_pack_exists};
|
||||
|
||||
fn fixture_to_rsync_uri(path: &Path) -> String {
|
||||
@@ -41,16 +39,6 @@ impl Fetcher for NeverHttpFetcher {
|
||||
}
|
||||
}
|
||||
|
||||
struct MapResolver {
|
||||
by_subject_dn: HashMap<String, Vec<u8>>,
|
||||
}
|
||||
|
||||
impl IssuerCaCertificateResolver for MapResolver {
|
||||
fn resolve_by_subject_dn(&self, subject_dn: &str) -> Option<Vec<u8>> {
|
||||
self.by_subject_dn.get(subject_dn).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn e2e_offline_uses_rsync_then_writes_verified_pack_then_outputs_vrps() {
|
||||
let fixture_dir = Path::new("tests/fixtures/repository/rpki.cernet.net/repo/cernet/0");
|
||||
@@ -89,10 +77,6 @@ fn e2e_offline_uses_rsync_then_writes_verified_pack_then_outputs_vrps() {
|
||||
let rsync_fetcher = LocalDirRsyncFetcher::new(fixture_dir);
|
||||
let http_fetcher = NeverHttpFetcher;
|
||||
|
||||
let resolver = MapResolver {
|
||||
by_subject_dn: HashMap::from([(issuer_ca.tbs.subject_dn, issuer_ca_der)]),
|
||||
};
|
||||
|
||||
let temp = tempfile::tempdir().expect("tempdir");
|
||||
let store = RocksStore::open(temp.path()).expect("open rocksdb");
|
||||
|
||||
@@ -113,7 +97,10 @@ fn e2e_offline_uses_rsync_then_writes_verified_pack_then_outputs_vrps() {
|
||||
&publication_point_rsync_uri,
|
||||
&http_fetcher,
|
||||
&rsync_fetcher,
|
||||
&resolver,
|
||||
&issuer_ca_der,
|
||||
None,
|
||||
issuer_ca.tbs.extensions.ip_resources.as_ref(),
|
||||
issuer_ca.tbs.extensions.as_resources.as_ref(),
|
||||
t,
|
||||
)
|
||||
.expect("run publication point once");
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use rpki::validation::from_tal::discover_root_ca_instance_from_tal_and_ta_der;
|
||||
use rpki::validation::run_tree_from_tal::root_handle_from_trust_anchor;
|
||||
use rpki::validation::run_tree_from_tal::{
|
||||
run_tree_from_tal_and_ta_der_serial, run_tree_from_tal_url_serial,
|
||||
run_tree_from_tal_and_ta_der_serial_audit, run_tree_from_tal_url_serial_audit,
|
||||
run_tree_from_tal_and_ta_der_serial, run_tree_from_tal_and_ta_der_serial_audit,
|
||||
run_tree_from_tal_url_serial, run_tree_from_tal_url_serial_audit,
|
||||
};
|
||||
use rpki::validation::tree::TreeRunConfig;
|
||||
|
||||
@@ -23,7 +23,10 @@ impl rpki::sync::rrdp::Fetcher for MapHttpFetcher {
|
||||
|
||||
struct EmptyRsyncFetcher;
|
||||
impl rpki::fetch::rsync::RsyncFetcher for EmptyRsyncFetcher {
|
||||
fn fetch_objects(&self, _rsync_base_uri: &str) -> Result<Vec<(String, Vec<u8>)>, rpki::fetch::rsync::RsyncFetchError> {
|
||||
fn fetch_objects(
|
||||
&self,
|
||||
_rsync_base_uri: &str,
|
||||
) -> Result<Vec<(String, Vec<u8>)>, rpki::fetch::rsync::RsyncFetchError> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
}
|
||||
@@ -37,13 +40,18 @@ fn root_handle_is_constructible_from_fixture_tal_and_ta() {
|
||||
let discovery =
|
||||
discover_root_ca_instance_from_tal_and_ta_der(&tal_bytes, &ta_der, None).expect("discover");
|
||||
|
||||
let root =
|
||||
root_handle_from_trust_anchor(&discovery.trust_anchor, None, &discovery.ca_instance);
|
||||
let root = root_handle_from_trust_anchor(&discovery.trust_anchor, None, &discovery.ca_instance);
|
||||
|
||||
assert_eq!(root.depth, 0);
|
||||
assert_eq!(root.manifest_rsync_uri, discovery.ca_instance.manifest_rsync_uri);
|
||||
assert_eq!(
|
||||
root.manifest_rsync_uri,
|
||||
discovery.ca_instance.manifest_rsync_uri
|
||||
);
|
||||
assert_eq!(root.rsync_base_uri, discovery.ca_instance.rsync_base_uri);
|
||||
assert!(root.ca_certificate_der.len() > 100, "TA der should be non-empty");
|
||||
assert!(
|
||||
root.ca_certificate_der.len() > 100,
|
||||
"TA der should be non-empty"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -103,7 +111,9 @@ fn run_tree_from_tal_and_ta_der_entry_executes_and_records_failure_when_repo_emp
|
||||
.expect("read apnic tal fixture");
|
||||
let ta_der = std::fs::read("tests/fixtures/ta/apnic-ta.cer").expect("read apnic ta fixture");
|
||||
|
||||
let http = MapHttpFetcher { map: HashMap::new() };
|
||||
let http = MapHttpFetcher {
|
||||
map: HashMap::new(),
|
||||
};
|
||||
let rsync = EmptyRsyncFetcher;
|
||||
let temp = tempfile::tempdir().expect("tempdir");
|
||||
let store = rpki::storage::RocksStore::open(temp.path()).expect("open rocksdb");
|
||||
@@ -190,7 +200,9 @@ fn run_tree_from_tal_and_ta_der_audit_entry_collects_no_publication_points_when_
|
||||
.expect("read apnic tal fixture");
|
||||
let ta_der = std::fs::read("tests/fixtures/ta/apnic-ta.cer").expect("read apnic ta fixture");
|
||||
|
||||
let http = MapHttpFetcher { map: HashMap::new() };
|
||||
let http = MapHttpFetcher {
|
||||
map: HashMap::new(),
|
||||
};
|
||||
let rsync = EmptyRsyncFetcher;
|
||||
|
||||
let temp = tempfile::tempdir().expect("tempdir");
|
||||
|
||||
@@ -31,4 +31,3 @@ fn storage_iter_all_lists_raw_and_verified_entries() {
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(verified_keys, vec![key.as_str().to_string()]);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,4 +100,3 @@ fn ta_rc_constraints_reject_as_inherit() {
|
||||
Err(TaCertificateProfileError::AsResourcesInherit)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -44,4 +44,3 @@ fn ta_verify_self_signature_rejects_tampered_signature() {
|
||||
TaCertificateVerifyError::InvalidSelfSignature(_) | TaCertificateVerifyError::Parse(_)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rpki::audit::{DiscoveredFrom, PublicationPointAudit};
|
||||
use rpki::report::Warning;
|
||||
use rpki::storage::{PackTime, VerifiedPublicationPointPack};
|
||||
use rpki::validation::manifest::PublicationPointSource;
|
||||
use rpki::validation::objects::{ObjectsOutput, ObjectsStats};
|
||||
use rpki::validation::tree::{
|
||||
CaInstanceHandle, PublicationPointRunResult, PublicationPointRunner, TreeRunConfig,
|
||||
run_tree_serial,
|
||||
CaInstanceHandle, DiscoveredChildCaInstance, PublicationPointRunResult, PublicationPointRunner,
|
||||
TreeRunConfig, run_tree_serial,
|
||||
};
|
||||
use rpki::audit::PublicationPointAudit;
|
||||
|
||||
fn empty_pack(manifest_uri: &str, pp_uri: &str) -> VerifiedPublicationPointPack {
|
||||
VerifiedPublicationPointPack {
|
||||
@@ -43,6 +43,25 @@ fn ca_handle(manifest_uri: &str) -> CaInstanceHandle {
|
||||
}
|
||||
}
|
||||
|
||||
fn discovered_child(
|
||||
parent_manifest_uri: &str,
|
||||
child_manifest_uri: &str,
|
||||
) -> DiscoveredChildCaInstance {
|
||||
let name = child_manifest_uri
|
||||
.rsplit('/')
|
||||
.next()
|
||||
.unwrap_or("child.mft")
|
||||
.trim_end_matches(".mft");
|
||||
DiscoveredChildCaInstance {
|
||||
handle: ca_handle(child_manifest_uri),
|
||||
discovered_from: DiscoveredFrom {
|
||||
parent_manifest_rsync_uri: parent_manifest_uri.to_string(),
|
||||
child_ca_certificate_rsync_uri: format!("rsync://example.test/repo/{name}.cer"),
|
||||
child_ca_certificate_sha256_hex: "00".repeat(32),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ResultRunner {
|
||||
by_manifest: HashMap<String, Result<PublicationPointRunResult, String>>,
|
||||
@@ -94,7 +113,10 @@ fn tree_continues_when_a_publication_point_fails() {
|
||||
audit: Vec::new(),
|
||||
},
|
||||
audit: PublicationPointAudit::default(),
|
||||
discovered_children: vec![ca_handle(bad_child_manifest), ca_handle(ok_child_manifest)],
|
||||
discovered_children: vec![
|
||||
discovered_child(root_manifest, bad_child_manifest),
|
||||
discovered_child(root_manifest, ok_child_manifest),
|
||||
],
|
||||
},
|
||||
)
|
||||
.with_err(bad_child_manifest, "synthetic failure")
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rpki::audit::{DiscoveredFrom, PublicationPointAudit};
|
||||
use rpki::report::Warning;
|
||||
use rpki::storage::{PackFile, PackTime, VerifiedPublicationPointPack};
|
||||
use rpki::validation::manifest::PublicationPointSource;
|
||||
use rpki::validation::tree::{
|
||||
CaInstanceHandle, PublicationPointRunResult, PublicationPointRunner, TreeRunConfig,
|
||||
run_tree_serial,
|
||||
};
|
||||
use rpki::validation::objects::{ObjectsOutput, ObjectsStats};
|
||||
use rpki::audit::PublicationPointAudit;
|
||||
use rpki::validation::tree::{
|
||||
CaInstanceHandle, DiscoveredChildCaInstance, PublicationPointRunResult, PublicationPointRunner,
|
||||
TreeRunConfig, run_tree_serial, run_tree_serial_audit,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
struct MockRunner {
|
||||
@@ -58,10 +58,7 @@ fn empty_pack(manifest_uri: &str, pp_uri: &str) -> VerifiedPublicationPointPack
|
||||
rfc3339_utc: "2026-02-06T00:00:00Z".to_string(),
|
||||
},
|
||||
manifest_bytes: vec![1, 2, 3],
|
||||
files: vec![PackFile::from_bytes_compute_sha256(
|
||||
manifest_uri,
|
||||
vec![1],
|
||||
)],
|
||||
files: vec![PackFile::from_bytes_compute_sha256(manifest_uri, vec![1])],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +76,25 @@ fn ca_handle(manifest_uri: &str) -> CaInstanceHandle {
|
||||
}
|
||||
}
|
||||
|
||||
fn discovered_child(
|
||||
parent_manifest_uri: &str,
|
||||
child_manifest_uri: &str,
|
||||
) -> DiscoveredChildCaInstance {
|
||||
let name = child_manifest_uri
|
||||
.rsplit('/')
|
||||
.next()
|
||||
.unwrap_or("child.mft")
|
||||
.trim_end_matches(".mft");
|
||||
DiscoveredChildCaInstance {
|
||||
handle: ca_handle(child_manifest_uri),
|
||||
discovered_from: DiscoveredFrom {
|
||||
parent_manifest_rsync_uri: parent_manifest_uri.to_string(),
|
||||
child_ca_certificate_rsync_uri: format!("rsync://example.test/repo/{name}.cer"),
|
||||
child_ca_certificate_sha256_hex: "00".repeat(32),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tree_enqueues_children_only_for_fresh_publication_points() {
|
||||
let root_manifest = "rsync://example.test/repo/root.mft";
|
||||
@@ -86,8 +102,11 @@ fn tree_enqueues_children_only_for_fresh_publication_points() {
|
||||
let child2_manifest = "rsync://example.test/repo/child2.mft";
|
||||
let grandchild_manifest = "rsync://example.test/repo/grandchild.mft";
|
||||
|
||||
let root_children = vec![ca_handle(child1_manifest), ca_handle(child2_manifest)];
|
||||
let child1_children = vec![ca_handle(grandchild_manifest)];
|
||||
let root_children = vec![
|
||||
discovered_child(root_manifest, child1_manifest),
|
||||
discovered_child(root_manifest, child2_manifest),
|
||||
];
|
||||
let child1_children = vec![discovered_child(child1_manifest, grandchild_manifest)];
|
||||
|
||||
let runner = MockRunner::default()
|
||||
.with(
|
||||
@@ -150,10 +169,15 @@ fn tree_enqueues_children_only_for_fresh_publication_points() {
|
||||
assert_eq!(out.instances_failed, 0);
|
||||
|
||||
let called = runner.called();
|
||||
assert_eq!(called, vec![root_manifest, child1_manifest, child2_manifest]);
|
||||
assert_eq!(
|
||||
called,
|
||||
vec![root_manifest, child1_manifest, child2_manifest]
|
||||
);
|
||||
|
||||
assert!(
|
||||
out.warnings.iter().any(|w| w.message.contains("child1 warning")),
|
||||
out.warnings
|
||||
.iter()
|
||||
.any(|w| w.message.contains("child1 warning")),
|
||||
"expected child1 warning propagated"
|
||||
);
|
||||
assert!(
|
||||
@@ -184,7 +208,7 @@ fn tree_respects_max_depth_and_max_instances() {
|
||||
audit: Vec::new(),
|
||||
},
|
||||
audit: PublicationPointAudit::default(),
|
||||
discovered_children: vec![ca_handle(child_manifest)],
|
||||
discovered_children: vec![discovered_child(root_manifest, child_manifest)],
|
||||
},
|
||||
)
|
||||
.with(
|
||||
@@ -229,3 +253,65 @@ fn tree_respects_max_depth_and_max_instances() {
|
||||
assert_eq!(out.instances_processed, 1);
|
||||
assert_eq!(out.instances_failed, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tree_audit_includes_parent_and_discovered_from_for_non_root_nodes() {
|
||||
let root_manifest = "rsync://example.test/repo/root.mft";
|
||||
let child_manifest = "rsync://example.test/repo/child.mft";
|
||||
|
||||
let runner = MockRunner::default()
|
||||
.with(
|
||||
root_manifest,
|
||||
PublicationPointRunResult {
|
||||
source: PublicationPointSource::Fresh,
|
||||
pack: empty_pack(root_manifest, "rsync://example.test/repo/"),
|
||||
warnings: Vec::new(),
|
||||
objects: ObjectsOutput {
|
||||
vrps: Vec::new(),
|
||||
aspas: Vec::new(),
|
||||
warnings: Vec::new(),
|
||||
stats: ObjectsStats::default(),
|
||||
audit: Vec::new(),
|
||||
},
|
||||
audit: PublicationPointAudit::default(),
|
||||
discovered_children: vec![discovered_child(root_manifest, child_manifest)],
|
||||
},
|
||||
)
|
||||
.with(
|
||||
child_manifest,
|
||||
PublicationPointRunResult {
|
||||
source: PublicationPointSource::Fresh,
|
||||
pack: empty_pack(child_manifest, "rsync://example.test/repo/child/"),
|
||||
warnings: Vec::new(),
|
||||
objects: ObjectsOutput {
|
||||
vrps: Vec::new(),
|
||||
aspas: Vec::new(),
|
||||
warnings: Vec::new(),
|
||||
stats: ObjectsStats::default(),
|
||||
audit: Vec::new(),
|
||||
},
|
||||
audit: PublicationPointAudit::default(),
|
||||
discovered_children: Vec::new(),
|
||||
},
|
||||
);
|
||||
|
||||
let out = run_tree_serial_audit(ca_handle(root_manifest), &runner, &TreeRunConfig::default())
|
||||
.expect("run tree audit");
|
||||
|
||||
assert_eq!(out.tree.instances_processed, 2);
|
||||
assert_eq!(out.publication_points.len(), 2);
|
||||
|
||||
let root_audit = &out.publication_points[0];
|
||||
assert_eq!(root_audit.node_id, Some(0));
|
||||
assert_eq!(root_audit.parent_node_id, None);
|
||||
assert!(root_audit.discovered_from.is_none());
|
||||
|
||||
let child_audit = &out.publication_points[1];
|
||||
assert_eq!(child_audit.node_id, Some(1));
|
||||
assert_eq!(child_audit.parent_node_id, Some(0));
|
||||
let df = child_audit
|
||||
.discovered_from
|
||||
.as_ref()
|
||||
.expect("child discovered_from");
|
||||
assert_eq!(df.parent_manifest_rsync_uri, root_manifest);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use rpki::data_model::manifest::ManifestObject;
|
||||
use rpki::data_model::rc::{AsIdOrRange, AsIdentifierChoice, AsResourceSet, ResourceCertificate};
|
||||
use rpki::data_model::roa::{IpPrefix, RoaAfi};
|
||||
use rpki::data_model::ta::{TaCertificate, TaCertificateParsed, TaCertificateProfileError};
|
||||
use rpki::data_model::tal::{Tal, TalDecodeError, TalProfileError};
|
||||
use rpki::data_model::roa::{IpPrefix, RoaAfi};
|
||||
|
||||
#[test]
|
||||
fn tal_validate_profile_noop_is_callable() {
|
||||
|
||||
Reference in New Issue
Block a user