rpki/tests/test_objects_errors_more.rs
2026-02-10 12:09:59 +08:00

176 lines
5.9 KiB
Rust

use std::path::Path;
use rpki::data_model::crl::RpkixCrl;
use rpki::data_model::manifest::ManifestObject;
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::process_verified_publication_point_pack_for_issuer;
fn fixture_to_rsync_uri(path: &Path) -> String {
let rel = path
.strip_prefix("tests/fixtures/repository")
.expect("path under tests/fixtures/repository");
let mut it = rel.components();
let host = it
.next()
.expect("host component")
.as_os_str()
.to_string_lossy();
let rest = it.as_path().to_string_lossy();
format!("rsync://{host}/{rest}")
}
fn fixture_dir_to_rsync_uri(dir: &Path) -> String {
let mut s = fixture_to_rsync_uri(dir);
if !s.ends_with('/') {
s.push('/');
}
s
}
fn build_cernet_pack_and_validation_time() -> (
rpki::storage::VerifiedPublicationPointPack,
time::OffsetDateTime,
Vec<u8>,
ResourceCertificate,
) {
let manifest_path = Path::new(
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
);
let manifest_bytes = std::fs::read(manifest_path).expect("read manifest fixture");
let manifest = ManifestObject::decode_der(&manifest_bytes).expect("decode manifest fixture");
let manifest_rsync_uri = fixture_to_rsync_uri(manifest_path);
let publication_point_rsync_uri = fixture_dir_to_rsync_uri(manifest_path.parent().unwrap());
let temp = tempfile::tempdir().expect("tempdir");
let store = RocksStore::open(temp.path()).expect("open rocksdb");
store
.put_raw(&manifest_rsync_uri, &manifest_bytes)
.expect("store manifest");
for entry in &manifest.manifest.files {
let file_path = manifest_path.parent().unwrap().join(&entry.file_name);
let bytes = std::fs::read(&file_path)
.unwrap_or_else(|_| panic!("read fixture file referenced by manifest: {file_path:?}"));
let rsync_uri = format!("{publication_point_rsync_uri}{}", entry.file_name);
store.put_raw(&rsync_uri, &bytes).expect("store file");
}
let policy = Policy::default();
let out = process_manifest_publication_point(
&store,
&policy,
&manifest_rsync_uri,
&publication_point_rsync_uri,
manifest.manifest.this_update + time::Duration::seconds(1),
)
.expect("process manifest publication point");
let issuer_ca_der = std::fs::read(
"tests/fixtures/repository/rpki.apnic.net/repository/B527EF581D6611E2BB468F7C72FD1FF2/BfycW4hQb3wNP4YsiJW-1n6fjro.cer",
)
.expect("read issuer CA cert fixture");
let issuer_ca = ResourceCertificate::decode_der(&issuer_ca_der).expect("decode issuer CA cert");
let crl_file = out
.pack
.files
.iter()
.find(|f| f.rsync_uri.ends_with(".crl"))
.expect("crl present in pack");
let crl = RpkixCrl::decode_der(&crl_file.bytes).expect("decode crl");
let mut t = manifest.manifest.this_update;
if issuer_ca.tbs.validity_not_before > t {
t = issuer_ca.tbs.validity_not_before;
}
if crl.this_update.utc > t {
t = crl.this_update.utc;
}
t += time::Duration::seconds(1);
(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, 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_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 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;
// 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, 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(
uri.clone(),
b"\0\0".to_vec(),
));
let mut policy = Policy::default();
policy.signed_object_failure_policy = SignedObjectFailurePolicy::DropObject;
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
.iter()
.any(|w| w.context.as_deref() == Some(&uri)),
"expected warning for invalid ASPA"
);
}