20260720 规范化 CCR Manifest location 导出
This commit is contained in:
@@ -6,6 +6,7 @@ use crate::ccr::build::{
|
||||
};
|
||||
use crate::ccr::encode::encode_manifest_state_payload_der;
|
||||
use crate::ccr::hash::compute_state_hash;
|
||||
use crate::ccr::manifest_location::select_manifest_signed_object_location_from_der;
|
||||
use crate::ccr::model::{
|
||||
CcrDigestAlgorithm, ManifestInstance, ManifestState, RpkiCanonicalCacheRepresentation,
|
||||
};
|
||||
@@ -54,7 +55,10 @@ impl CcrManifestContribution {
|
||||
aki: projection.manifest_ee_aki.clone(),
|
||||
manifest_number_be: projection.manifest_number_be.clone(),
|
||||
this_update,
|
||||
locations_der: projection.manifest_sia_locations_der.clone(),
|
||||
locations_der: vec![select_manifest_signed_object_location_from_der(
|
||||
&projection.manifest_rsync_uri,
|
||||
&projection.manifest_sia_locations_der,
|
||||
)?],
|
||||
subordinate_skis: projection.subordinate_skis.clone(),
|
||||
})
|
||||
}
|
||||
@@ -246,7 +250,8 @@ mod tests {
|
||||
use crate::ccr::export::build_ccr_from_run;
|
||||
use crate::ccr::verify::verify_content_info;
|
||||
use crate::data_model::manifest::ManifestObject;
|
||||
use crate::data_model::rc::SubjectInfoAccess;
|
||||
use crate::data_model::oid::{OID_AD_RPKI_NOTIFY, OID_AD_SIGNED_OBJECT};
|
||||
use crate::data_model::rc::{AccessDescription, SubjectInfoAccess};
|
||||
use crate::data_model::roa::{IpPrefix, RoaAfi};
|
||||
use crate::data_model::ta::TrustAnchor;
|
||||
use crate::data_model::tal::Tal;
|
||||
@@ -283,16 +288,35 @@ mod tests {
|
||||
)
|
||||
.expect("read manifest");
|
||||
let manifest = ManifestObject::decode_der(&manifest_der).expect("decode manifest");
|
||||
let manifest_uri = match manifest.signed_object.signed_data.certificates[0]
|
||||
.resource_cert
|
||||
.tbs
|
||||
.extensions
|
||||
.subject_info_access
|
||||
.as_ref()
|
||||
.expect("manifest sia")
|
||||
{
|
||||
SubjectInfoAccess::Ee(ee_sia) => ee_sia
|
||||
.access_descriptions
|
||||
.iter()
|
||||
.find(|ad| {
|
||||
ad.access_method_oid == OID_AD_SIGNED_OBJECT
|
||||
&& ad.access_location.starts_with("rsync://")
|
||||
})
|
||||
.expect("manifest rsync signedObject")
|
||||
.access_location
|
||||
.clone(),
|
||||
SubjectInfoAccess::Ca(_) => panic!("manifest ee sia should not be CA variant"),
|
||||
};
|
||||
let manifest_hash = hex::encode(sha2::Sha256::digest(&manifest_der));
|
||||
let mut raw = RawByHashEntry::from_bytes(manifest_hash.clone(), manifest_der.clone());
|
||||
raw.origin_uris
|
||||
.push("rsync://example.test/repo/current.mft".to_string());
|
||||
raw.origin_uris.push(manifest_uri.clone());
|
||||
raw.object_type = Some("mft".to_string());
|
||||
raw.encoding = Some("der".to_string());
|
||||
store.put_raw_by_hash_entry(&raw).expect("put raw");
|
||||
|
||||
let projection = VcirCcrManifestProjection {
|
||||
manifest_rsync_uri: "rsync://example.test/repo/current.mft".to_string(),
|
||||
manifest_rsync_uri: manifest_uri.clone(),
|
||||
manifest_sha256: sha2::Sha256::digest(&manifest_der).to_vec(),
|
||||
manifest_size: manifest_der.len() as u64,
|
||||
manifest_ee_aki: manifest.signed_object.signed_data.certificates[0]
|
||||
@@ -312,23 +336,20 @@ mod tests {
|
||||
.as_ref()
|
||||
.expect("manifest sia")
|
||||
{
|
||||
SubjectInfoAccess::Ee(ee_sia) => ee_sia
|
||||
.access_descriptions
|
||||
.iter()
|
||||
.map(|ad| {
|
||||
let oid = encode_oid_for_test(&ad.access_method_oid)
|
||||
.expect("encode access method oid");
|
||||
let uri = encode_tlv_for_test(0x86, ad.access_location.as_bytes().to_vec());
|
||||
encode_sequence_for_test(&[oid, uri])
|
||||
})
|
||||
.collect(),
|
||||
SubjectInfoAccess::Ee(ee_sia) => vec![
|
||||
crate::ccr::manifest_location::select_manifest_signed_object_location(
|
||||
&manifest_uri,
|
||||
&ee_sia.access_descriptions,
|
||||
)
|
||||
.expect("select manifest signedObject"),
|
||||
],
|
||||
SubjectInfoAccess::Ca(_) => panic!("manifest ee sia should not be CA variant"),
|
||||
},
|
||||
subordinate_skis: vec![vec![0x33; 20]],
|
||||
};
|
||||
|
||||
let vcir = ValidatedCaInstanceResult {
|
||||
manifest_rsync_uri: "rsync://example.test/repo/current.mft".to_string(),
|
||||
manifest_rsync_uri: manifest_uri.clone(),
|
||||
parent_manifest_rsync_uri: None,
|
||||
tal_id: "apnic".to_string(),
|
||||
ca_subject_name: "CN=test".to_string(),
|
||||
@@ -337,8 +358,8 @@ mod tests {
|
||||
last_successful_validation_time: PackTime::from_utc_offset_datetime(
|
||||
manifest.manifest.this_update,
|
||||
),
|
||||
current_manifest_rsync_uri: "rsync://example.test/repo/current.mft".to_string(),
|
||||
current_crl_rsync_uri: "rsync://example.test/repo/current.crl".to_string(),
|
||||
current_manifest_rsync_uri: manifest_uri.clone(),
|
||||
current_crl_rsync_uri: format!("{manifest_uri}.crl"),
|
||||
validated_manifest_meta: ValidatedManifestMeta {
|
||||
validated_manifest_number: manifest.manifest.manifest_number.bytes_be.clone(),
|
||||
validated_manifest_this_update: PackTime::from_utc_offset_datetime(
|
||||
@@ -381,7 +402,7 @@ mod tests {
|
||||
related_artifacts: vec![VcirRelatedArtifact {
|
||||
artifact_role: VcirArtifactRole::Manifest,
|
||||
artifact_kind: VcirArtifactKind::Mft,
|
||||
uri: Some("rsync://example.test/repo/current.mft".to_string()),
|
||||
uri: Some(manifest_uri.clone()),
|
||||
sha256: manifest_hash,
|
||||
object_type: Some("mft".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
@@ -429,55 +450,6 @@ mod tests {
|
||||
(vcir, vrps, aspas, router_keys)
|
||||
}
|
||||
|
||||
fn encode_oid_for_test(oid: &str) -> Result<Vec<u8>, String> {
|
||||
let arcs = oid
|
||||
.split('.')
|
||||
.map(|part| part.parse::<u64>().map_err(|_| format!("bad oid: {oid}")))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
if arcs.len() < 2 {
|
||||
return Err(format!("bad oid: {oid}"));
|
||||
}
|
||||
let mut body = Vec::new();
|
||||
body.push((arcs[0] * 40 + arcs[1]) as u8);
|
||||
for arc in &arcs[2..] {
|
||||
encode_base128_for_test(*arc, &mut body);
|
||||
}
|
||||
Ok(encode_tlv_for_test(0x06, body))
|
||||
}
|
||||
|
||||
fn encode_base128_for_test(mut value: u64, out: &mut Vec<u8>) {
|
||||
let mut tmp = vec![(value & 0x7F) as u8];
|
||||
value >>= 7;
|
||||
while value > 0 {
|
||||
tmp.push(((value & 0x7F) as u8) | 0x80);
|
||||
value >>= 7;
|
||||
}
|
||||
tmp.reverse();
|
||||
out.extend_from_slice(&tmp);
|
||||
}
|
||||
|
||||
fn encode_sequence_for_test(elements: &[Vec<u8>]) -> Vec<u8> {
|
||||
let total_len: usize = elements.iter().map(Vec::len).sum();
|
||||
let mut buf = Vec::with_capacity(total_len);
|
||||
for element in elements {
|
||||
buf.extend_from_slice(element);
|
||||
}
|
||||
encode_tlv_for_test(0x30, buf)
|
||||
}
|
||||
|
||||
fn encode_tlv_for_test(tag: u8, value: Vec<u8>) -> Vec<u8> {
|
||||
let mut out = Vec::with_capacity(1 + 9 + value.len());
|
||||
out.push(tag);
|
||||
if value.len() < 0x80 {
|
||||
out.push(value.len() as u8);
|
||||
} else {
|
||||
out.push(0x81);
|
||||
out.push(value.len() as u8);
|
||||
}
|
||||
out.extend_from_slice(&value);
|
||||
out
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accumulator_finish_matches_builder_on_fresh_vcir_inputs() {
|
||||
let td = tempfile::tempdir().expect("tempdir");
|
||||
@@ -512,4 +484,32 @@ mod tests {
|
||||
let ci = crate::ccr::model::CcrContentInfo::new(accumulated_ccr);
|
||||
verify_content_info(&ci).expect("verify accumulated ccr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accumulator_sanitizes_historical_projection_with_rpki_notify() {
|
||||
let td = tempfile::tempdir().expect("tempdir");
|
||||
let store = RocksStore::open(td.path()).expect("open rocksdb");
|
||||
let (mut vcir, _, _, _) = sample_vcir_and_manifest(&store);
|
||||
let notify_der =
|
||||
crate::ccr::manifest_location::encode_access_description_der(&AccessDescription {
|
||||
access_method_oid: OID_AD_RPKI_NOTIFY.to_string(),
|
||||
access_location: "https://rrdp.example.test/notification.xml".to_string(),
|
||||
})
|
||||
.expect("encode rpkiNotify");
|
||||
let expected_location = vcir.ccr_manifest_projection.manifest_sia_locations_der[0].clone();
|
||||
vcir.ccr_manifest_projection
|
||||
.manifest_sia_locations_der
|
||||
.push(notify_der);
|
||||
|
||||
let mut accumulator = CcrAccumulator::new(Vec::new());
|
||||
accumulator
|
||||
.append_manifest_projection(&vcir.ccr_manifest_projection)
|
||||
.expect("sanitize historical projection");
|
||||
let contribution = accumulator
|
||||
.manifests_by_hash
|
||||
.values()
|
||||
.next()
|
||||
.expect("manifest contribution");
|
||||
assert_eq!(contribution.locations_der, vec![expected_location]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user