20260511 CIR V3 trust anchors self-contained

This commit is contained in:
2026-05-11 18:12:41 +08:00
parent 51e483d924
commit f2fbb20a29
25 changed files with 742 additions and 522 deletions

View File

@@ -6,8 +6,8 @@ use rpki::ccr::{
encode_content_info,
};
use rpki::cir::{
CIR_VERSION_V2, CanonicalInputRepresentation, CirHashAlgorithm, CirObject, CirTal,
compute_reject_list_sha256, encode_cir,
CIR_VERSION_V3, CanonicalInputRepresentation, CirHashAlgorithm, CirObject, CirTrustAnchor,
compute_reject_list_sha256, encode_cir, sha256,
};
fn skip_heavy_blackbox_test() -> bool {
@@ -42,9 +42,10 @@ fn cir_full_and_delta_pair_reuses_shared_repo_bytes_db() {
use sha2::{Digest, Sha256};
hex::encode(Sha256::digest(b"delta-object"))
};
let trust_anchors = vec![test_trust_anchor()];
let full_cir = CanonicalInputRepresentation {
version: CIR_VERSION_V2,
version: CIR_VERSION_V3,
hash_alg: CirHashAlgorithm::Sha256,
validation_time: time::OffsetDateTime::parse(
"2026-03-16T11:49:15Z",
@@ -55,15 +56,12 @@ fn cir_full_and_delta_pair_reuses_shared_repo_bytes_db() {
rsync_uri: "rsync://example.net/repo/full.roa".to_string(),
sha256: hex::decode(&full_obj_hash).unwrap(),
}],
tals: vec![CirTal {
tal_uri: "https://rpki.apnic.net/tal/apnic-rfc7730-https.tal".to_string(),
tal_bytes: b"rsync://example.net/repo/root.cer\nMIIB".to_vec(),
}],
trust_anchors: trust_anchors.clone(),
reject_list_sha256: compute_reject_list_sha256(std::iter::empty::<&str>()),
rejected_objects: Vec::new(),
};
let delta_cir = CanonicalInputRepresentation {
version: CIR_VERSION_V2,
version: CIR_VERSION_V3,
hash_alg: CirHashAlgorithm::Sha256,
validation_time: time::OffsetDateTime::parse(
"2026-03-16T11:50:15Z",
@@ -84,7 +82,7 @@ fn cir_full_and_delta_pair_reuses_shared_repo_bytes_db() {
objects.sort_by(|a, b| a.rsync_uri.cmp(&b.rsync_uri));
objects
},
tals: full_cir.tals.clone(),
trust_anchors,
reject_list_sha256: compute_reject_list_sha256(std::iter::empty::<&str>()),
rejected_objects: Vec::new(),
};
@@ -226,3 +224,15 @@ fi
assert!(out.join("full").join("result.ccr").is_file());
assert!(out.join("delta-001").join("result.ccr").is_file());
}
fn test_trust_anchor() -> CirTrustAnchor {
let ta_rsync_uri = "rsync://example.net/repo/root.cer";
let ta_certificate_der = b"ta-der".to_vec();
CirTrustAnchor {
ta_rsync_uri: ta_rsync_uri.to_string(),
tal_uri: "https://rpki.apnic.net/tal/apnic-rfc7730-https.tal".to_string(),
tal_bytes: format!("{ta_rsync_uri}\n\nAQID\n").into_bytes(),
ta_certificate_sha256: sha256(&ta_certificate_der),
ta_certificate_der,
}
}

View File

@@ -7,8 +7,8 @@ use rpki::ccr::{
encode_content_info,
};
use rpki::cir::{
CIR_VERSION_V2, CanonicalInputRepresentation, CirHashAlgorithm, CirObject, CirTal,
compute_reject_list_sha256, encode_cir,
CIR_VERSION_V3, CanonicalInputRepresentation, CirHashAlgorithm, CirObject, CirTrustAnchor,
compute_reject_list_sha256, encode_cir, sha256,
};
#[test]
@@ -34,7 +34,7 @@ fn cir_drop_report_counts_dropped_roa_objects_and_vrps() {
.expect("write repo bytes");
let cir = CanonicalInputRepresentation {
version: CIR_VERSION_V2,
version: CIR_VERSION_V3,
hash_alg: CirHashAlgorithm::Sha256,
validation_time: time::OffsetDateTime::parse(
"2026-04-09T00:00:00Z",
@@ -45,10 +45,7 @@ fn cir_drop_report_counts_dropped_roa_objects_and_vrps() {
rsync_uri: "rsync://example.net/repo/AS4538.roa".to_string(),
sha256: hex::decode(&hash).unwrap(),
}],
tals: vec![CirTal {
tal_uri: "https://example.test/root.tal".to_string(),
tal_bytes: b"rsync://example.net/repo/root.cer\nMIIB".to_vec(),
}],
trust_anchors: vec![test_trust_anchor()],
reject_list_sha256: compute_reject_list_sha256(std::iter::empty::<&str>()),
rejected_objects: Vec::new(),
};
@@ -124,3 +121,15 @@ fn cir_drop_report_counts_dropped_roa_objects_and_vrps() {
.contains("Dropped By Reason")
);
}
fn test_trust_anchor() -> CirTrustAnchor {
let ta_rsync_uri = "rsync://example.net/repo/root.cer";
let ta_certificate_der = b"ta-der".to_vec();
CirTrustAnchor {
ta_rsync_uri: ta_rsync_uri.to_string(),
tal_uri: "https://example.test/root.tal".to_string(),
tal_bytes: format!("{ta_rsync_uri}\n\nAQID\n").into_bytes(),
ta_certificate_sha256: sha256(&ta_certificate_der),
ta_certificate_der,
}
}

View File

@@ -3,8 +3,8 @@ use std::process::Command;
use rpki::blob_store::ExternalRepoBytesDb;
use rpki::cir::{
CIR_VERSION_V2, CanonicalInputRepresentation, CirHashAlgorithm, CirObject, CirTal,
compute_reject_list_sha256, encode_cir, materialize_cir_from_repo_bytes,
CIR_VERSION_V3, CanonicalInputRepresentation, CirHashAlgorithm, CirTrustAnchor,
compute_reject_list_sha256, encode_cir, materialize_cir_from_repo_bytes, sha256,
};
fn skip_heavy_script_replay_test() -> bool {
@@ -30,26 +30,22 @@ fn build_ta_only_cir() -> (CanonicalInputRepresentation, Vec<u8>) {
.expect("tal has rsync uri")
.as_str()
.to_string();
let ta_hash = {
use sha2::{Digest, Sha256};
Sha256::digest(&ta_bytes).to_vec()
};
(
CanonicalInputRepresentation {
version: CIR_VERSION_V2,
version: CIR_VERSION_V3,
hash_alg: CirHashAlgorithm::Sha256,
validation_time: time::OffsetDateTime::parse(
"2026-04-07T00:00:00Z",
&time::format_description::well_known::Rfc3339,
)
.unwrap(),
objects: vec![CirObject {
rsync_uri: ta_rsync_uri,
sha256: ta_hash,
}],
tals: vec![CirTal {
objects: Vec::new(),
trust_anchors: vec![CirTrustAnchor {
ta_rsync_uri,
tal_uri: "https://example.test/root.tal".to_string(),
tal_bytes,
ta_certificate_sha256: sha256(&ta_bytes),
ta_certificate_der: ta_bytes.clone(),
}],
reject_list_sha256: compute_reject_list_sha256(std::iter::empty::<&str>()),
rejected_objects: Vec::new(),

View File

@@ -3,8 +3,8 @@ use std::process::Command;
use rpki::blob_store::ExternalRepoBytesDb;
use rpki::cir::{
CIR_VERSION_V2, CanonicalInputRepresentation, CirHashAlgorithm, CirObject, CirTal,
compute_reject_list_sha256, encode_cir, materialize_cir_from_repo_bytes,
CIR_VERSION_V3, CanonicalInputRepresentation, CirHashAlgorithm, CirTrustAnchor,
compute_reject_list_sha256, encode_cir, materialize_cir_from_repo_bytes, sha256,
};
fn skip_heavy_script_replay_test() -> bool {
@@ -30,26 +30,22 @@ fn build_ta_only_cir() -> (CanonicalInputRepresentation, Vec<u8>) {
.expect("tal has rsync uri")
.as_str()
.to_string();
let ta_hash = {
use sha2::{Digest, Sha256};
Sha256::digest(&ta_bytes).to_vec()
};
(
CanonicalInputRepresentation {
version: CIR_VERSION_V2,
version: CIR_VERSION_V3,
hash_alg: CirHashAlgorithm::Sha256,
validation_time: time::OffsetDateTime::parse(
"2026-04-07T00:00:00Z",
&time::format_description::well_known::Rfc3339,
)
.unwrap(),
objects: vec![CirObject {
rsync_uri: ta_rsync_uri,
sha256: ta_hash,
}],
tals: vec![CirTal {
objects: Vec::new(),
trust_anchors: vec![CirTrustAnchor {
ta_rsync_uri,
tal_uri: "https://example.test/root.tal".to_string(),
tal_bytes,
ta_certificate_sha256: sha256(&ta_bytes),
ta_certificate_der: ta_bytes.clone(),
}],
reject_list_sha256: compute_reject_list_sha256(std::iter::empty::<&str>()),
rejected_objects: Vec::new(),

View File

@@ -6,8 +6,8 @@ use rpki::ccr::{
encode_content_info,
};
use rpki::cir::{
CIR_VERSION_V2, CanonicalInputRepresentation, CirHashAlgorithm, CirObject, CirTal,
compute_reject_list_sha256, encode_cir,
CIR_VERSION_V3, CanonicalInputRepresentation, CirHashAlgorithm, CirObject, CirTrustAnchor,
compute_reject_list_sha256, encode_cir, sha256,
};
fn skip_heavy_blackbox_test() -> bool {
@@ -36,7 +36,7 @@ fn cir_offline_sequence_writes_parseable_sequence_json_and_steps() {
.unwrap();
let mk_cir = |uri: &str, hash_hex: &str, vt: &str| CanonicalInputRepresentation {
version: CIR_VERSION_V2,
version: CIR_VERSION_V3,
hash_alg: CirHashAlgorithm::Sha256,
validation_time: time::OffsetDateTime::parse(
vt,
@@ -47,10 +47,7 @@ fn cir_offline_sequence_writes_parseable_sequence_json_and_steps() {
rsync_uri: uri.to_string(),
sha256: hex::decode(hash_hex).unwrap(),
}],
tals: vec![CirTal {
tal_uri: "https://rpki.apnic.net/tal/apnic-rfc7730-https.tal".to_string(),
tal_bytes: b"rsync://example.net/repo/root.cer\nMIIB".to_vec(),
}],
trust_anchors: vec![test_trust_anchor()],
reject_list_sha256: compute_reject_list_sha256(std::iter::empty::<&str>()),
rejected_objects: Vec::new(),
};
@@ -68,7 +65,7 @@ fn cir_offline_sequence_writes_parseable_sequence_json_and_steps() {
"2026-03-16T11:49:15Z",
);
let delta_cir = CanonicalInputRepresentation {
version: CIR_VERSION_V2,
version: CIR_VERSION_V3,
hash_alg: CirHashAlgorithm::Sha256,
validation_time: time::OffsetDateTime::parse(
"2026-03-16T11:50:15Z",
@@ -86,7 +83,7 @@ fn cir_offline_sequence_writes_parseable_sequence_json_and_steps() {
objects.sort_by(|a, b| a.rsync_uri.cmp(&b.rsync_uri));
objects
},
tals: full_cir.tals.clone(),
trust_anchors: full_cir.trust_anchors.clone(),
reject_list_sha256: compute_reject_list_sha256(std::iter::empty::<&str>()),
rejected_objects: Vec::new(),
};
@@ -244,3 +241,15 @@ fi
assert!(out.join(rel).is_file(), "missing {}", rel);
}
}
fn test_trust_anchor() -> CirTrustAnchor {
let ta_rsync_uri = "rsync://example.net/repo/root.cer";
let ta_certificate_der = b"ta-der".to_vec();
CirTrustAnchor {
ta_rsync_uri: ta_rsync_uri.to_string(),
tal_uri: "https://rpki.apnic.net/tal/apnic-rfc7730-https.tal".to_string(),
tal_bytes: format!("{ta_rsync_uri}\n\nAQID\n").into_bytes(),
ta_certificate_sha256: sha256(&ta_certificate_der),
ta_certificate_der,
}
}

View File

@@ -3,8 +3,8 @@ use std::process::Command;
use rpki::blob_store::ExternalRepoBytesDb;
use rpki::cir::{
CIR_VERSION_V2, CanonicalInputRepresentation, CirHashAlgorithm, CirObject, CirTal,
compute_reject_list_sha256, encode_cir, materialize_cir_from_repo_bytes,
CIR_VERSION_V3, CanonicalInputRepresentation, CirHashAlgorithm, CirTrustAnchor,
compute_reject_list_sha256, encode_cir, materialize_cir_from_repo_bytes, sha256,
};
fn skip_heavy_script_replay_test() -> bool {
@@ -30,26 +30,22 @@ fn build_ta_only_cir() -> (CanonicalInputRepresentation, Vec<u8>) {
.expect("tal has rsync uri")
.as_str()
.to_string();
let ta_hash = {
use sha2::{Digest, Sha256};
Sha256::digest(&ta_bytes).to_vec()
};
(
CanonicalInputRepresentation {
version: CIR_VERSION_V2,
version: CIR_VERSION_V3,
hash_alg: CirHashAlgorithm::Sha256,
validation_time: time::OffsetDateTime::parse(
"2026-04-07T00:00:00Z",
&time::format_description::well_known::Rfc3339,
)
.unwrap(),
objects: vec![CirObject {
rsync_uri: ta_rsync_uri,
sha256: ta_hash,
}],
tals: vec![CirTal {
objects: Vec::new(),
trust_anchors: vec![CirTrustAnchor {
ta_rsync_uri,
tal_uri: "https://example.test/root.tal".to_string(),
tal_bytes,
ta_certificate_sha256: sha256(&ta_bytes),
ta_certificate_der: ta_bytes.clone(),
}],
reject_list_sha256: compute_reject_list_sha256(std::iter::empty::<&str>()),
rejected_objects: Vec::new(),

View File

@@ -3,8 +3,8 @@ use std::process::Command;
use rpki::blob_store::ExternalRepoBytesDb;
use rpki::cir::{
CIR_VERSION_V2, CanonicalInputRepresentation, CirHashAlgorithm, CirObject, CirTal,
compute_reject_list_sha256, encode_cir, materialize_cir_from_repo_bytes,
CIR_VERSION_V3, CanonicalInputRepresentation, CirHashAlgorithm, CirTrustAnchor,
compute_reject_list_sha256, encode_cir, materialize_cir_from_repo_bytes, sha256,
};
fn skip_heavy_script_replay_test() -> bool {
@@ -30,26 +30,22 @@ fn build_ta_only_cir() -> (CanonicalInputRepresentation, Vec<u8>) {
.expect("tal has rsync uri")
.as_str()
.to_string();
let ta_hash = {
use sha2::{Digest, Sha256};
Sha256::digest(&ta_bytes).to_vec()
};
(
CanonicalInputRepresentation {
version: CIR_VERSION_V2,
version: CIR_VERSION_V3,
hash_alg: CirHashAlgorithm::Sha256,
validation_time: time::OffsetDateTime::parse(
"2026-04-07T00:00:00Z",
&time::format_description::well_known::Rfc3339,
)
.unwrap(),
objects: vec![CirObject {
rsync_uri: ta_rsync_uri,
sha256: ta_hash,
}],
tals: vec![CirTal {
objects: Vec::new(),
trust_anchors: vec![CirTrustAnchor {
ta_rsync_uri,
tal_uri: "https://example.test/root.tal".to_string(),
tal_bytes,
ta_certificate_sha256: sha256(&ta_bytes),
ta_certificate_der: ta_bytes.clone(),
}],
reject_list_sha256: compute_reject_list_sha256(std::iter::empty::<&str>()),
rejected_objects: Vec::new(),

View File

@@ -127,12 +127,16 @@ fn cli_run_offline_mode_writes_cir_and_static_pool() {
let bytes = std::fs::read(&cir_path).expect("read cir");
let cir = rpki::cir::decode_cir(&bytes).expect("decode cir");
assert_eq!(cir.tals.len(), 1);
assert_eq!(cir.tals[0].tal_uri, "https://example.test/root.tal");
assert_eq!(cir.trust_anchors.len(), 1);
assert_eq!(
cir.trust_anchors[0].tal_uri,
"https://example.test/root.tal"
);
assert!(!cir.trust_anchors[0].ta_certificate_der.is_empty());
assert!(
cir.objects
!cir.objects
.iter()
.any(|item| item.rsync_uri.contains("apnic-rpki-root-iana-origin.cer"))
.any(|item| item.rsync_uri == cir.trust_anchors[0].ta_rsync_uri)
);
}