rpki/tests/test_model_print_real_fixtures.rs

499 lines
16 KiB
Rust

use rpki::data_model::aspa::{AspaEContent, AspaObject};
use rpki::data_model::crl::{CrlExtensions, RevokedCert, RpkixCrl};
use rpki::data_model::manifest::{FileAndHash, ManifestEContent, ManifestObject};
use rpki::data_model::rc::{
AsResourceSet, IpResourceSet, RcExtensions, ResourceCertKind, ResourceCertificate, RpkixTbsCertificate,
SubjectInfoAccess,
};
use rpki::data_model::roa::{RoaEContent, RoaIpAddressFamily, RoaObject};
use rpki::data_model::signed_object::{
EncapsulatedContentInfo, ResourceEeCertificate, RpkiSignedObject, SignedAttrsProfiled, SignedDataProfiled,
SignerInfoProfiled,
};
use rpki::data_model::ta::{TaCertificate, TrustAnchor};
use rpki::data_model::tal::Tal;
use sha2::{Digest, Sha256};
#[derive(Clone, Debug, PartialEq, Eq)]
struct BytesFmt {
len: usize,
sha256_hex: String,
head_hex: String,
tail_hex: String,
}
fn bytes_fmt(bytes: &[u8]) -> BytesFmt {
let len = bytes.len();
let sha = Sha256::digest(bytes);
let head_len = len.min(16);
let tail_len = len.min(16);
let head = &bytes[..head_len];
let tail = &bytes[len.saturating_sub(tail_len)..];
BytesFmt {
len,
sha256_hex: hex::encode(sha),
head_hex: hex::encode(head),
tail_hex: hex::encode(tail),
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct TalPretty {
raw: BytesFmt,
comments: Vec<String>,
ta_uris: Vec<String>,
subject_public_key_info_der: BytesFmt,
}
impl From<&Tal> for TalPretty {
fn from(v: &Tal) -> Self {
Self {
raw: bytes_fmt(&v.raw),
comments: v.comments.clone(),
ta_uris: v.ta_uris.iter().map(|u| u.to_string()).collect(),
subject_public_key_info_der: bytes_fmt(&v.subject_public_key_info_der),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct TaCertificatePretty {
raw_der: BytesFmt,
rc_ca: ResourceCertificatePretty,
}
impl From<&TaCertificate> for TaCertificatePretty {
fn from(v: &TaCertificate) -> Self {
Self {
raw_der: bytes_fmt(&v.raw_der),
rc_ca: ResourceCertificatePretty::from(&v.rc_ca),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct TrustAnchorPretty {
tal: TalPretty,
ta_certificate: TaCertificatePretty,
resolved_ta_uri: Option<String>,
}
impl From<&TrustAnchor> for TrustAnchorPretty {
fn from(v: &TrustAnchor) -> Self {
Self {
tal: TalPretty::from(&v.tal),
ta_certificate: TaCertificatePretty::from(&v.ta_certificate),
resolved_ta_uri: v.resolved_ta_uri.as_ref().map(|u| u.to_string()),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct ResourceCertificatePretty {
raw_der: BytesFmt,
tbs: RpkixTbsCertificatePretty,
kind: ResourceCertKind,
}
impl From<&ResourceCertificate> for ResourceCertificatePretty {
fn from(v: &ResourceCertificate) -> Self {
Self {
raw_der: bytes_fmt(&v.raw_der),
tbs: RpkixTbsCertificatePretty::from(&v.tbs),
kind: v.kind,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct RpkixTbsCertificatePretty {
version: u32,
serial_number: String,
signature_algorithm: String,
issuer_dn: String,
subject_dn: String,
validity_not_before: time::OffsetDateTime,
validity_not_after: time::OffsetDateTime,
subject_public_key_info: BytesFmt,
extensions: RcExtensionsPretty,
}
impl From<&RpkixTbsCertificate> for RpkixTbsCertificatePretty {
fn from(v: &RpkixTbsCertificate) -> Self {
Self {
version: v.version,
serial_number: hex::encode(v.serial_number.to_bytes_be()),
signature_algorithm: v.signature_algorithm.clone(),
issuer_dn: v.issuer_dn.clone(),
subject_dn: v.subject_dn.clone(),
validity_not_before: v.validity_not_before,
validity_not_after: v.validity_not_after,
subject_public_key_info: bytes_fmt(&v.subject_public_key_info),
extensions: RcExtensionsPretty::from(&v.extensions),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct RcExtensionsPretty {
basic_constraints_ca: bool,
subject_key_identifier: Option<BytesFmt>,
subject_info_access: Option<SubjectInfoAccess>,
certificate_policies_oid: Option<String>,
ip_resources: Option<IpResourceSet>,
as_resources: Option<AsResourceSet>,
}
impl From<&RcExtensions> for RcExtensionsPretty {
fn from(v: &RcExtensions) -> Self {
Self {
basic_constraints_ca: v.basic_constraints_ca,
subject_key_identifier: v.subject_key_identifier.as_ref().map(|b| bytes_fmt(b)),
subject_info_access: v.subject_info_access.clone(),
certificate_policies_oid: v.certificate_policies_oid.clone(),
ip_resources: v.ip_resources.clone(),
as_resources: v.as_resources.clone(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct RpkiSignedObjectPretty {
raw_der: BytesFmt,
content_info_content_type: String,
signed_data: SignedDataProfiledPretty,
}
impl From<&RpkiSignedObject> for RpkiSignedObjectPretty {
fn from(v: &RpkiSignedObject) -> Self {
Self {
raw_der: bytes_fmt(&v.raw_der),
content_info_content_type: v.content_info_content_type.clone(),
signed_data: SignedDataProfiledPretty::from(&v.signed_data),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct SignedDataProfiledPretty {
version: u32,
digest_algorithms: Vec<String>,
encap_content_info: EncapsulatedContentInfoPretty,
certificates: Vec<ResourceEeCertificatePretty>,
crls_present: bool,
signer_infos: Vec<SignerInfoProfiledPretty>,
}
impl From<&SignedDataProfiled> for SignedDataProfiledPretty {
fn from(v: &SignedDataProfiled) -> Self {
Self {
version: v.version,
digest_algorithms: v.digest_algorithms.clone(),
encap_content_info: EncapsulatedContentInfoPretty::from(&v.encap_content_info),
certificates: v
.certificates
.iter()
.map(ResourceEeCertificatePretty::from)
.collect(),
crls_present: v.crls_present,
signer_infos: v.signer_infos.iter().map(SignerInfoProfiledPretty::from).collect(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct EncapsulatedContentInfoPretty {
econtent_type: String,
econtent: BytesFmt,
}
impl From<&EncapsulatedContentInfo> for EncapsulatedContentInfoPretty {
fn from(v: &EncapsulatedContentInfo) -> Self {
Self {
econtent_type: v.econtent_type.clone(),
econtent: bytes_fmt(&v.econtent),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct ResourceEeCertificatePretty {
raw_der: BytesFmt,
subject_key_identifier: BytesFmt,
spki_der: BytesFmt,
sia_signed_object_uris: Vec<String>,
resource_cert: ResourceCertificatePretty,
}
impl From<&ResourceEeCertificate> for ResourceEeCertificatePretty {
fn from(v: &ResourceEeCertificate) -> Self {
Self {
raw_der: bytes_fmt(&v.raw_der),
subject_key_identifier: bytes_fmt(&v.subject_key_identifier),
spki_der: bytes_fmt(&v.spki_der),
sia_signed_object_uris: v.sia_signed_object_uris.clone(),
resource_cert: ResourceCertificatePretty::from(&v.resource_cert),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct SignerInfoProfiledPretty {
version: u32,
sid_ski: BytesFmt,
digest_algorithm: String,
signature_algorithm: String,
signed_attrs: SignedAttrsProfiledPretty,
unsigned_attrs_present: bool,
signature: BytesFmt,
signed_attrs_der_for_signature: BytesFmt,
}
impl From<&SignerInfoProfiled> for SignerInfoProfiledPretty {
fn from(v: &SignerInfoProfiled) -> Self {
Self {
version: v.version,
sid_ski: bytes_fmt(&v.sid_ski),
digest_algorithm: v.digest_algorithm.clone(),
signature_algorithm: v.signature_algorithm.clone(),
signed_attrs: SignedAttrsProfiledPretty::from(&v.signed_attrs),
unsigned_attrs_present: v.unsigned_attrs_present,
signature: bytes_fmt(&v.signature),
signed_attrs_der_for_signature: bytes_fmt(&v.signed_attrs_der_for_signature),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct SignedAttrsProfiledPretty {
content_type: String,
message_digest: BytesFmt,
signing_time: rpki::data_model::common::Asn1TimeUtc,
other_attrs_present: bool,
}
impl From<&SignedAttrsProfiled> for SignedAttrsProfiledPretty {
fn from(v: &SignedAttrsProfiled) -> Self {
Self {
content_type: v.content_type.clone(),
message_digest: bytes_fmt(&v.message_digest),
signing_time: v.signing_time,
other_attrs_present: v.other_attrs_present,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct ManifestObjectPretty {
signed_object: RpkiSignedObjectPretty,
econtent_type: String,
manifest: ManifestEContentPretty,
}
impl From<&ManifestObject> for ManifestObjectPretty {
fn from(v: &ManifestObject) -> Self {
Self {
signed_object: RpkiSignedObjectPretty::from(&v.signed_object),
econtent_type: v.econtent_type.clone(),
manifest: ManifestEContentPretty::from(&v.manifest),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct ManifestEContentPretty {
version: u32,
manifest_number: String,
this_update: time::OffsetDateTime,
next_update: time::OffsetDateTime,
file_hash_alg: String,
files: Vec<FileAndHashPretty>,
}
impl From<&ManifestEContent> for ManifestEContentPretty {
fn from(v: &ManifestEContent) -> Self {
Self {
version: v.version,
manifest_number: v.manifest_number.to_hex_upper(),
this_update: v.this_update,
next_update: v.next_update,
file_hash_alg: v.file_hash_alg.clone(),
files: v.files.iter().map(FileAndHashPretty::from).collect(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct FileAndHashPretty {
file_name: String,
hash_hex: String,
}
impl From<&FileAndHash> for FileAndHashPretty {
fn from(v: &FileAndHash) -> Self {
Self {
file_name: v.file_name.clone(),
hash_hex: hex::encode(&v.hash_bytes),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct RoaObjectPretty {
signed_object: RpkiSignedObjectPretty,
econtent_type: String,
roa: RoaEContentPretty,
}
impl From<&RoaObject> for RoaObjectPretty {
fn from(v: &RoaObject) -> Self {
Self {
signed_object: RpkiSignedObjectPretty::from(&v.signed_object),
econtent_type: v.econtent_type.clone(),
roa: RoaEContentPretty::from(&v.roa),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct RoaEContentPretty {
version: u32,
as_id: u32,
ip_addr_blocks: Vec<RoaIpAddressFamily>,
}
impl From<&RoaEContent> for RoaEContentPretty {
fn from(v: &RoaEContent) -> Self {
Self {
version: v.version,
as_id: v.as_id,
ip_addr_blocks: v.ip_addr_blocks.clone(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct AspaObjectPretty {
signed_object: RpkiSignedObjectPretty,
econtent_type: String,
aspa: AspaEContent,
}
impl From<&AspaObject> for AspaObjectPretty {
fn from(v: &AspaObject) -> Self {
Self {
signed_object: RpkiSignedObjectPretty::from(&v.signed_object),
econtent_type: v.econtent_type.clone(),
aspa: v.aspa.clone(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct RpkixCrlPretty {
raw_der: BytesFmt,
version: u32,
issuer_dn: String,
signature_algorithm_oid: String,
this_update: rpki::data_model::common::Asn1TimeUtc,
next_update: rpki::data_model::common::Asn1TimeUtc,
revoked_certs: Vec<RevokedCert>,
extensions: CrlExtensions,
}
impl From<&RpkixCrl> for RpkixCrlPretty {
fn from(v: &RpkixCrl) -> Self {
Self {
raw_der: bytes_fmt(&v.raw_der),
version: v.version,
issuer_dn: v.issuer_dn.clone(),
signature_algorithm_oid: v.signature_algorithm_oid.clone(),
this_update: v.this_update,
next_update: v.next_update,
revoked_certs: v.revoked_certs.clone(),
extensions: v.extensions.clone(),
}
}
}
#[test]
fn print_all_models_from_real_fixtures() {
// Note: run this test with `cargo test --test test_model_print_real_fixtures -- --nocapture`
// to see the output.
let tal_path = "tests/fixtures/tal/ripe-ncc.tal";
println!("== TAL / TA / TrustAnchor ==");
println!("Fixture (TAL): {tal_path}");
let tal_raw = std::fs::read(tal_path).expect("read TAL fixture");
let tal = Tal::decode_bytes(&tal_raw).expect("decode TAL");
let ta_path = "tests/fixtures/ta/ripe-ncc-ta.cer";
println!("Fixture (TA): {ta_path}");
let ta_der = std::fs::read(ta_path).expect("read TA fixture");
let ta = TaCertificate::from_der(&ta_der).expect("parse TA cert");
let resolved = tal
.ta_uris
.iter()
.find(|u| u.scheme() == "https")
.or_else(|| tal.ta_uris.first())
.cloned()
.expect("tal has at least one uri");
let trust_anchor = TrustAnchor::bind(tal, &ta_der, Some(&resolved)).expect("bind trust anchor");
println!("{:#?}", TalPretty::from(&trust_anchor.tal));
println!("{:#?}", TaCertificatePretty::from(&ta));
println!("{:#?}", TrustAnchorPretty::from(&trust_anchor));
println!();
println!("== ResourceCertificate (example non-TA CA cert) ==");
let ca_path =
"tests/fixtures/repository/rpki.apnic.net/repository/B527EF581D6611E2BB468F7C72FD1FF2/BfycW4hQb3wNP4YsiJW-1n6fjro.cer";
println!("Fixture (CA cert): {ca_path}");
let ca_der = std::fs::read(ca_path).expect("read CA cert fixture");
let ca_rc = ResourceCertificate::from_der(&ca_der).expect("parse CA resource certificate");
println!("{:#?}", ResourceCertificatePretty::from(&ca_rc));
println!();
println!("== Signed Object / Manifest ==");
let mft_path =
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft";
println!("Fixture (MFT): {mft_path}");
let mft_der = std::fs::read(mft_path).expect("read MFT fixture");
let mft_obj = ManifestObject::decode_der(&mft_der).expect("decode manifest object");
println!("{:#?}", ManifestObjectPretty::from(&mft_obj));
println!("Manifest.validate_embedded_ee_cert={:?}", mft_obj.validate_embedded_ee_cert());
println!("Manifest.verify_signature={:?}", mft_obj.signed_object.verify_signature());
println!();
println!("== Signed Object / ROA ==");
let roa_path = "tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/AS4538.roa";
println!("Fixture (ROA): {roa_path}");
let roa_der = std::fs::read(roa_path).expect("read ROA fixture");
let roa_obj = RoaObject::decode_der(&roa_der).expect("decode ROA object");
println!("{:#?}", RoaObjectPretty::from(&roa_obj));
println!("ROA.validate_embedded_ee_cert={:?}", roa_obj.validate_embedded_ee_cert());
println!("ROA.verify_signature={:?}", roa_obj.signed_object.verify_signature());
println!();
println!("== Signed Object / ASPA ==");
let aspa_path =
"tests/fixtures/repository/chloe.sobornost.net/rpki/RIPE-nljobsnijders/5m80fwYws_3FiFD7JiQjAqZ1RYQ.asa";
println!("Fixture (ASPA): {aspa_path}");
let aspa_der = std::fs::read(aspa_path).expect("read ASPA fixture");
let aspa_obj = AspaObject::decode_der(&aspa_der).expect("decode ASPA object");
println!("{:#?}", AspaObjectPretty::from(&aspa_obj));
println!("ASPA.validate_embedded_ee_cert={:?}", aspa_obj.validate_embedded_ee_cert());
println!("ASPA.verify_signature={:?}", aspa_obj.signed_object.verify_signature());
println!();
println!("== CRL ==");
let crl_path = "tests/fixtures/0099DEAB073EFD74C250C0A382B25012B5082AEE.crl";
println!("Fixture (CRL): {crl_path}");
let crl_der = std::fs::read(crl_path).expect("read CRL fixture");
let crl = RpkixCrl::decode_der(&crl_der).expect("decode CRL");
println!("{:#?}", RpkixCrlPretty::from(&crl));
}