20260511 CIR V3 trust anchors self-contained
This commit is contained in:
@@ -57,7 +57,7 @@ fn real_main() -> Result<(), String> {
|
||||
let cir = rpki::cir::decode_cir(&bytes).map_err(|e| format!("decode cir failed: {e}"))?;
|
||||
|
||||
println!("object_count={}", cir.objects.len());
|
||||
println!("tal_count={}", cir.tals.len());
|
||||
println!("trust_anchor_count={}", cir.trust_anchors.len());
|
||||
for (index, item) in cir.objects.iter().take(args.limit).enumerate() {
|
||||
println!(
|
||||
"{:04} object={} sha256={}",
|
||||
|
||||
@@ -49,17 +49,23 @@ fn run(argv: Vec<String>) -> Result<(), String> {
|
||||
.map_err(|e| format!("read CIR failed: {}: {e}", cir_path.display()))?;
|
||||
let cir = rpki::cir::decode_cir(&bytes).map_err(|e| e.to_string())?;
|
||||
|
||||
std::fs::create_dir_all(&tals_dir)
|
||||
.map_err(|e| format!("create tals dir failed: {}: {e}", tals_dir.display()))?;
|
||||
std::fs::create_dir_all(&tals_dir).map_err(|e| {
|
||||
format!(
|
||||
"create trust_anchors dir failed: {}: {e}",
|
||||
tals_dir.display()
|
||||
)
|
||||
})?;
|
||||
|
||||
let mut tal_files = Vec::new();
|
||||
for (idx, tal) in cir.tals.iter().enumerate() {
|
||||
for (idx, tal) in cir.trust_anchors.iter().enumerate() {
|
||||
let filename = format!("tal-{:03}.tal", idx + 1);
|
||||
let path = tals_dir.join(filename);
|
||||
std::fs::write(&path, &tal.tal_bytes)
|
||||
.map_err(|e| format!("write TAL failed: {}: {e}", path.display()))?;
|
||||
tal_files.push(serde_json::json!({
|
||||
"talUri": tal.tal_uri,
|
||||
"taRsyncUri": tal.ta_rsync_uri,
|
||||
"taCertificateSha256": hex::encode(&tal.ta_certificate_sha256),
|
||||
"path": path,
|
||||
}));
|
||||
}
|
||||
@@ -70,6 +76,7 @@ fn run(argv: Vec<String>) -> Result<(), String> {
|
||||
.map_err(|e| format!("format validationTime failed: {e}"))?;
|
||||
let meta = serde_json::json!({
|
||||
"validationTime": validation_time,
|
||||
"trustAnchorCount": cir.trust_anchors.len(),
|
||||
"talFiles": tal_files,
|
||||
});
|
||||
if let Some(parent) = meta_json.parent() {
|
||||
|
||||
@@ -59,9 +59,11 @@ fn run(argv: Vec<String>) -> Result<(), String> {
|
||||
match result {
|
||||
Ok(summary) => {
|
||||
eprintln!(
|
||||
"materialized CIR: mirror={} objects={} linked={} copied={} keep_db={}",
|
||||
"materialized CIR: mirror={} objects={} trust_anchors={} materialized_files={} linked={} copied={} keep_db={}",
|
||||
mirror_root.display(),
|
||||
summary.object_count,
|
||||
summary.trust_anchor_count,
|
||||
summary.materialized_file_count,
|
||||
summary.linked_files,
|
||||
summary.copied_files,
|
||||
keep_db
|
||||
|
||||
@@ -443,8 +443,8 @@ fn uri_extension(uri: &str) -> String {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rpki::cir::{
|
||||
CIR_VERSION_V2, CanonicalInputRepresentation, CirHashAlgorithm, CirObject,
|
||||
CirRejectedObject, CirTal, compute_reject_list_sha256, encode_cir,
|
||||
CIR_VERSION_V3, CanonicalInputRepresentation, CirHashAlgorithm, CirObject,
|
||||
CirRejectedObject, CirTrustAnchor, compute_reject_list_sha256, encode_cir,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -664,20 +664,28 @@ mod tests {
|
||||
.collect::<Vec<_>>();
|
||||
objects.sort_by(|left, right| left.rsync_uri.cmp(&right.rsync_uri));
|
||||
CanonicalInputRepresentation {
|
||||
version: CIR_VERSION_V2,
|
||||
version: CIR_VERSION_V3,
|
||||
hash_alg: CirHashAlgorithm::Sha256,
|
||||
validation_time: time::OffsetDateTime::UNIX_EPOCH,
|
||||
objects,
|
||||
tals: vec![CirTal {
|
||||
tal_uri: "https://tal.example.test/apnic.tal".to_string(),
|
||||
tal_bytes: b"https://tal.example.test/apnic.tal\nrsync://example.test/ta.cer\nMIIB"
|
||||
.to_vec(),
|
||||
}],
|
||||
trust_anchors: vec![sample_trust_anchor()],
|
||||
reject_list_sha256: compute_reject_list_sha256(std::iter::empty::<&str>()),
|
||||
rejected_objects: Vec::<CirRejectedObject>::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn sample_trust_anchor() -> CirTrustAnchor {
|
||||
let ta_rsync_uri = "rsync://example.test/ta.cer";
|
||||
let ta_certificate_der = b"ta-der".to_vec();
|
||||
CirTrustAnchor {
|
||||
ta_rsync_uri: ta_rsync_uri.to_string(),
|
||||
tal_uri: "https://tal.example.test/apnic.tal".to_string(),
|
||||
tal_bytes: format!("{ta_rsync_uri}\n\nAQID\n").into_bytes(),
|
||||
ta_certificate_sha256: Sha256::digest(&ta_certificate_der).to_vec(),
|
||||
ta_certificate_der,
|
||||
}
|
||||
}
|
||||
|
||||
fn write_cir(path: &Path, cir: &CanonicalInputRepresentation) {
|
||||
std::fs::write(path, encode_cir(cir).expect("encode cir")).expect("write cir");
|
||||
}
|
||||
|
||||
@@ -114,40 +114,56 @@ fn run(args: Args) -> Result<(), String> {
|
||||
.iter()
|
||||
.map(|item| item.object_uri.clone())
|
||||
.collect::<BTreeSet<_>>();
|
||||
let ours_tals = ours
|
||||
.tals
|
||||
let ours_trust_anchors = ours
|
||||
.trust_anchors
|
||||
.iter()
|
||||
.map(|item| item.tal_uri.clone())
|
||||
.collect::<BTreeSet<_>>();
|
||||
let peer_tals = peer
|
||||
.tals
|
||||
.map(|item| {
|
||||
(
|
||||
item.ta_rsync_uri.clone(),
|
||||
hex::encode(&item.ta_certificate_sha256),
|
||||
)
|
||||
})
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
let peer_trust_anchors = peer
|
||||
.trust_anchors
|
||||
.iter()
|
||||
.map(|item| item.tal_uri.clone())
|
||||
.collect::<BTreeSet<_>>();
|
||||
.map(|item| {
|
||||
(
|
||||
item.ta_rsync_uri.clone(),
|
||||
hex::encode(&item.ta_certificate_sha256),
|
||||
)
|
||||
})
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
|
||||
let object_summary = compare_object_maps(&ours_objects, &peer_objects, args.sample_limit);
|
||||
let reject_summary = compare_sets(&ours_rejects, &peer_rejects, args.sample_limit);
|
||||
let tal_summary = compare_sets(&ours_tals, &peer_tals, args.sample_limit);
|
||||
let trust_anchor_summary =
|
||||
compare_object_maps(&ours_trust_anchors, &peer_trust_anchors, args.sample_limit);
|
||||
let reject_hash_match = ours.reject_list_sha256 == peer.reject_list_sha256;
|
||||
let all_match =
|
||||
object_summary.match_ && reject_summary.match_ && tal_summary.match_ && reject_hash_match;
|
||||
let all_match = object_summary.match_
|
||||
&& reject_summary.match_
|
||||
&& trust_anchor_summary.match_
|
||||
&& reject_hash_match;
|
||||
|
||||
let summary = json!({
|
||||
"allMatch": all_match,
|
||||
"objects": object_summary.to_json(),
|
||||
"rejects": reject_summary.to_json(),
|
||||
"tals": tal_summary.to_json(),
|
||||
"trustAnchors": trust_anchor_summary.to_json(),
|
||||
"trust_anchors": trust_anchor_summary.to_json(),
|
||||
"rejectListSha256Match": reject_hash_match,
|
||||
"ours": {
|
||||
"objectCount": ours.objects.len(),
|
||||
"talCount": ours.tals.len(),
|
||||
"talCount": ours.trust_anchors.len(),
|
||||
"trustAnchorCount": ours.trust_anchors.len(),
|
||||
"rejectCount": ours.rejected_objects.len(),
|
||||
"rejectListSha256": hex::encode(&ours.reject_list_sha256),
|
||||
"validationTime": ours.validation_time.to_string(),
|
||||
},
|
||||
"rpkiClient": {
|
||||
"objectCount": peer.objects.len(),
|
||||
"talCount": peer.tals.len(),
|
||||
"talCount": peer.trust_anchors.len(),
|
||||
"trustAnchorCount": peer.trust_anchors.len(),
|
||||
"rejectCount": peer.rejected_objects.len(),
|
||||
"rejectListSha256": hex::encode(&peer.reject_list_sha256),
|
||||
"validationTime": peer.validation_time.to_string(),
|
||||
@@ -200,23 +216,25 @@ fn write_markdown(path: &Path, summary: &serde_json::Value) -> Result<(), String
|
||||
summary["rejects"]["match"].as_bool().unwrap_or(false)
|
||||
),
|
||||
format!(
|
||||
"- `talsMatch`: `{}`",
|
||||
summary["tals"]["match"].as_bool().unwrap_or(false)
|
||||
"- `trustAnchorsMatch`: `{}`",
|
||||
summary["trustAnchors"]["match"].as_bool().unwrap_or(false)
|
||||
),
|
||||
format!(
|
||||
"- `rejectListSha256Match`: `{}`",
|
||||
summary["rejectListSha256Match"].as_bool().unwrap_or(false)
|
||||
),
|
||||
format!(
|
||||
"- `ours`: objects `{}`, tals `{}`, rejects `{}`",
|
||||
"- `ours`: objects `{}`, trustAnchors `{}`, rejects `{}`",
|
||||
summary["ours"]["objectCount"].as_u64().unwrap_or(0),
|
||||
summary["ours"]["talCount"].as_u64().unwrap_or(0),
|
||||
summary["ours"]["trustAnchorCount"].as_u64().unwrap_or(0),
|
||||
summary["ours"]["rejectCount"].as_u64().unwrap_or(0)
|
||||
),
|
||||
format!(
|
||||
"- `rpkiClient`: objects `{}`, tals `{}`, rejects `{}`",
|
||||
"- `rpkiClient`: objects `{}`, trustAnchors `{}`, rejects `{}`",
|
||||
summary["rpkiClient"]["objectCount"].as_u64().unwrap_or(0),
|
||||
summary["rpkiClient"]["talCount"].as_u64().unwrap_or(0),
|
||||
summary["rpkiClient"]["trustAnchorCount"]
|
||||
.as_u64()
|
||||
.unwrap_or(0),
|
||||
summary["rpkiClient"]["rejectCount"].as_u64().unwrap_or(0)
|
||||
),
|
||||
];
|
||||
@@ -410,8 +428,8 @@ fn uri_extension(uri: &str) -> String {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rpki::cir::{
|
||||
CIR_VERSION_V2, CanonicalInputRepresentation, CirHashAlgorithm, CirObject,
|
||||
CirRejectedObject, CirTal, compute_reject_list_sha256, encode_cir,
|
||||
CIR_VERSION_V3, CanonicalInputRepresentation, CirHashAlgorithm, CirObject,
|
||||
CirRejectedObject, CirTrustAnchor, compute_reject_list_sha256, encode_cir, sha256,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -513,7 +531,7 @@ mod tests {
|
||||
assert_eq!(summary["allMatch"], true);
|
||||
assert_eq!(summary["objects"]["match"], true);
|
||||
assert_eq!(summary["rejects"]["match"], true);
|
||||
assert_eq!(summary["tals"]["match"], true);
|
||||
assert_eq!(summary["trustAnchors"]["match"], true);
|
||||
assert_eq!(summary["rejectListSha256Match"], true);
|
||||
assert_eq!(summary["ours"]["objectCount"], 2);
|
||||
assert!(
|
||||
@@ -524,7 +542,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_reports_object_reject_tal_differences_with_samples() {
|
||||
fn run_reports_object_reject_trust_anchor_differences_with_samples() {
|
||||
let temp = tempfile::tempdir().expect("tempdir");
|
||||
let ours_cir = sample_cir(
|
||||
&[
|
||||
@@ -581,7 +599,7 @@ mod tests {
|
||||
1
|
||||
);
|
||||
assert_eq!(summary["rejects"]["match"], false);
|
||||
assert_eq!(summary["tals"]["match"], false);
|
||||
assert_eq!(summary["trustAnchors"]["match"], false);
|
||||
assert_eq!(summary["rejectListSha256Match"], false);
|
||||
}
|
||||
|
||||
@@ -700,7 +718,7 @@ mod tests {
|
||||
|
||||
fn sample_cir(
|
||||
objects: &[(&str, u8)],
|
||||
tals: &[&str],
|
||||
trust_anchors: &[&str],
|
||||
rejected_objects: &[(&str, Option<&str>)],
|
||||
) -> CanonicalInputRepresentation {
|
||||
let rejected_objects = rejected_objects
|
||||
@@ -711,7 +729,7 @@ mod tests {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
CanonicalInputRepresentation {
|
||||
version: CIR_VERSION_V2,
|
||||
version: CIR_VERSION_V3,
|
||||
hash_alg: CirHashAlgorithm::Sha256,
|
||||
validation_time: sample_time(),
|
||||
objects: objects
|
||||
@@ -721,12 +739,23 @@ mod tests {
|
||||
sha256: vec![*fill; 32],
|
||||
})
|
||||
.collect(),
|
||||
tals: tals
|
||||
trust_anchors: trust_anchors
|
||||
.iter()
|
||||
.map(|tal_uri| CirTal {
|
||||
tal_uri: (*tal_uri).to_string(),
|
||||
tal_bytes: format!("{tal_uri}\nrsync://example.net/repo/ta.cer\nMIIB")
|
||||
.into_bytes(),
|
||||
.map(|tal_uri| {
|
||||
let name = tal_uri
|
||||
.rsplit('/')
|
||||
.next()
|
||||
.unwrap_or("root.tal")
|
||||
.trim_end_matches(".tal");
|
||||
let ta_rsync_uri = format!("rsync://example.net/repo/{name}.cer");
|
||||
let ta_certificate_der = format!("ta-der-{name}").into_bytes();
|
||||
CirTrustAnchor {
|
||||
ta_rsync_uri: ta_rsync_uri.clone(),
|
||||
tal_uri: (*tal_uri).to_string(),
|
||||
tal_bytes: format!("{ta_rsync_uri}\n\nAQID\n").into_bytes(),
|
||||
ta_certificate_sha256: sha256(&ta_certificate_der),
|
||||
ta_certificate_der,
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
reject_list_sha256: compute_reject_list_sha256(
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use rpki::blob_store::ExternalRepoBytesDb;
|
||||
use rpki::cir::{
|
||||
CIR_VERSION_V2, CanonicalInputRepresentation, CirHashAlgorithm, CirObject, CirTal,
|
||||
compute_reject_list_sha256, encode_cir,
|
||||
CIR_VERSION_V3, CanonicalInputRepresentation, CirHashAlgorithm, CirTrustAnchor,
|
||||
compute_reject_list_sha256, encode_cir, sha256,
|
||||
};
|
||||
use sha2::Digest;
|
||||
|
||||
const USAGE: &str = "Usage: cir_ta_only_fixture --tal-path <path> --ta-path <path> --tal-uri <url> --validation-time <rfc3339> --cir-out <path> --repo-bytes-db <path>";
|
||||
|
||||
@@ -88,6 +86,7 @@ fn parse_args(
|
||||
fn main() -> Result<(), String> {
|
||||
let argv: Vec<String> = std::env::args().collect();
|
||||
let (tal_path, ta_path, tal_uri, validation_time, cir_out, repo_bytes_db) = parse_args(&argv)?;
|
||||
let _ = repo_bytes_db;
|
||||
|
||||
let tal_bytes = std::fs::read(&tal_path).map_err(|e| format!("read tal failed: {e}"))?;
|
||||
let ta_bytes = std::fs::read(&ta_path).map_err(|e| format!("read ta failed: {e}"))?;
|
||||
@@ -101,22 +100,20 @@ fn main() -> Result<(), String> {
|
||||
.as_str()
|
||||
.to_string();
|
||||
|
||||
let sha = sha2::Sha256::digest(&ta_bytes);
|
||||
let hash_hex = hex::encode(sha);
|
||||
ExternalRepoBytesDb::open(&repo_bytes_db)
|
||||
.map_err(|e| format!("open repo bytes db failed: {e}"))?
|
||||
.put_blob_bytes_batch(&[(hash_hex, ta_bytes.clone())])
|
||||
.map_err(|e| format!("write repo bytes db failed: {e}"))?;
|
||||
let ta_certificate_sha256 = sha256(&ta_bytes);
|
||||
|
||||
let cir = CanonicalInputRepresentation {
|
||||
version: CIR_VERSION_V2,
|
||||
version: CIR_VERSION_V3,
|
||||
hash_alg: CirHashAlgorithm::Sha256,
|
||||
validation_time,
|
||||
objects: vec![CirObject {
|
||||
rsync_uri: ta_rsync_uri,
|
||||
sha256: sha.to_vec(),
|
||||
objects: Vec::new(),
|
||||
trust_anchors: vec![CirTrustAnchor {
|
||||
ta_rsync_uri,
|
||||
tal_uri,
|
||||
tal_bytes,
|
||||
ta_certificate_der: ta_bytes,
|
||||
ta_certificate_sha256,
|
||||
}],
|
||||
tals: vec![CirTal { tal_uri, tal_bytes }],
|
||||
reject_list_sha256: compute_reject_list_sha256(std::iter::empty::<&str>()),
|
||||
rejected_objects: Vec::new(),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user