184 lines
6.3 KiB
Rust
184 lines
6.3 KiB
Rust
use der_parser::num_bigint::BigUint;
|
|
use rpki::data_model::oid::OID_CP_IPADDR_ASNUMBER;
|
|
use rpki::data_model::rc::{
|
|
Afi, AsIdOrRange, AsIdentifierChoice, AsResourceSet, IpAddressChoice, IpAddressFamily,
|
|
IpAddressOrRange, IpPrefix, RcExtensions, ResourceCertKind, ResourceCertificate,
|
|
RpkixTbsCertificate,
|
|
};
|
|
use rpki::data_model::ta::{TaCertificate, TaCertificateDecodeError, TaCertificateProfileError};
|
|
use time::OffsetDateTime;
|
|
|
|
fn dummy_rc_ca(ext: RcExtensions) -> ResourceCertificate {
|
|
let t = OffsetDateTime::from_unix_timestamp(0).unwrap();
|
|
ResourceCertificate {
|
|
raw_der: Vec::new(),
|
|
kind: ResourceCertKind::Ca,
|
|
tbs: RpkixTbsCertificate {
|
|
version: 2,
|
|
serial_number: BigUint::from(1u32),
|
|
signature_algorithm: "1.2.840.113549.1.1.11".into(),
|
|
issuer_dn: "CN=TA".into(),
|
|
subject_dn: "CN=TA".into(),
|
|
validity_not_before: t,
|
|
validity_not_after: t,
|
|
subject_public_key_info: Vec::new(),
|
|
extensions: ext,
|
|
},
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn ta_certificate_from_der_parses_downloaded_fixtures() {
|
|
let fixtures = [
|
|
"tests/fixtures/ta/afrinic-ta.cer",
|
|
"tests/fixtures/ta/apnic-ta.cer",
|
|
"tests/fixtures/ta/arin-ta.cer",
|
|
"tests/fixtures/ta/lacnic-ta.cer",
|
|
"tests/fixtures/ta/ripe-ncc-ta.cer",
|
|
];
|
|
for path in fixtures {
|
|
let der = std::fs::read(path).expect("read TA fixture");
|
|
let ta = TaCertificate::from_der(&der).expect("parse TA fixture");
|
|
assert_eq!(ta.rc_ca.kind, ResourceCertKind::Ca);
|
|
assert_eq!(
|
|
ta.rc_ca.tbs.extensions.certificate_policies_oid.as_deref(),
|
|
Some(OID_CP_IPADDR_ASNUMBER)
|
|
);
|
|
assert!(ta.rc_ca.tbs.extensions.subject_key_identifier.is_some());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn ta_certificate_rejects_non_self_signed_ca() {
|
|
// This is a CA cert fixture, but not self-signed (issuer != subject).
|
|
let der = std::fs::read(
|
|
"tests/fixtures/repository/rpki.apnic.net/repository/B527EF581D6611E2BB468F7C72FD1FF2/BfycW4hQb3wNP4YsiJW-1n6fjro.cer",
|
|
)
|
|
.expect("read CA cert fixture");
|
|
assert!(matches!(
|
|
TaCertificate::from_der(&der),
|
|
Err(TaCertificateDecodeError::Validate(
|
|
TaCertificateProfileError::NotSelfSignedIssuerSubject
|
|
))
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn ta_constraints_require_policies_and_ski() {
|
|
let rc = dummy_rc_ca(RcExtensions {
|
|
basic_constraints_ca: true,
|
|
subject_key_identifier: None,
|
|
authority_key_identifier: None,
|
|
crl_distribution_points_uris: None,
|
|
ca_issuers_uris: None,
|
|
subject_info_access: None,
|
|
certificate_policies_oid: None,
|
|
ip_resources: Some(rpki::data_model::rc::IpResourceSet { families: vec![] }),
|
|
as_resources: None,
|
|
});
|
|
assert!(matches!(
|
|
TaCertificate::validate_rc_constraints(&rc),
|
|
Err(TaCertificateProfileError::MissingOrInvalidCertificatePolicies)
|
|
));
|
|
|
|
let rc = dummy_rc_ca(RcExtensions {
|
|
certificate_policies_oid: Some(OID_CP_IPADDR_ASNUMBER.to_string()),
|
|
..rc.tbs.extensions.clone()
|
|
});
|
|
assert!(matches!(
|
|
TaCertificate::validate_rc_constraints(&rc),
|
|
Err(TaCertificateProfileError::MissingSubjectKeyIdentifier)
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn ta_constraints_require_non_empty_resources_and_no_inherit() {
|
|
// Missing both IP and AS resources.
|
|
let rc = dummy_rc_ca(RcExtensions {
|
|
basic_constraints_ca: true,
|
|
subject_key_identifier: Some(vec![1]),
|
|
authority_key_identifier: None,
|
|
crl_distribution_points_uris: None,
|
|
ca_issuers_uris: None,
|
|
subject_info_access: None,
|
|
certificate_policies_oid: Some(OID_CP_IPADDR_ASNUMBER.to_string()),
|
|
ip_resources: None,
|
|
as_resources: None,
|
|
});
|
|
assert!(matches!(
|
|
TaCertificate::validate_rc_constraints(&rc),
|
|
Err(TaCertificateProfileError::ResourcesMissing)
|
|
));
|
|
|
|
// IP resources present but empty => resources empty.
|
|
let rc = dummy_rc_ca(RcExtensions {
|
|
ip_resources: Some(rpki::data_model::rc::IpResourceSet { families: vec![] }),
|
|
..rc.tbs.extensions.clone()
|
|
});
|
|
assert!(matches!(
|
|
TaCertificate::validate_rc_constraints(&rc),
|
|
Err(TaCertificateProfileError::ResourcesEmpty)
|
|
));
|
|
|
|
// IP resources inherit is rejected.
|
|
let rc = dummy_rc_ca(RcExtensions {
|
|
ip_resources: Some(rpki::data_model::rc::IpResourceSet {
|
|
families: vec![IpAddressFamily {
|
|
afi: Afi::Ipv4,
|
|
choice: IpAddressChoice::Inherit,
|
|
}],
|
|
}),
|
|
..rc.tbs.extensions.clone()
|
|
});
|
|
assert!(matches!(
|
|
TaCertificate::validate_rc_constraints(&rc),
|
|
Err(TaCertificateProfileError::IpResourcesInherit)
|
|
));
|
|
|
|
// AS resources inherit is rejected.
|
|
let rc = dummy_rc_ca(RcExtensions {
|
|
ip_resources: None,
|
|
as_resources: Some(AsResourceSet {
|
|
asnum: Some(AsIdentifierChoice::Inherit),
|
|
rdi: None,
|
|
}),
|
|
..rc.tbs.extensions.clone()
|
|
});
|
|
assert!(matches!(
|
|
TaCertificate::validate_rc_constraints(&rc),
|
|
Err(TaCertificateProfileError::AsResourcesInherit)
|
|
));
|
|
|
|
// Valid non-empty explicit IP resources => OK.
|
|
let rc = dummy_rc_ca(RcExtensions {
|
|
ip_resources: Some(rpki::data_model::rc::IpResourceSet {
|
|
families: vec![IpAddressFamily {
|
|
afi: Afi::Ipv6,
|
|
choice: IpAddressChoice::AddressesOrRanges(vec![IpAddressOrRange::Prefix(
|
|
IpPrefix {
|
|
afi: Afi::Ipv6,
|
|
prefix_len: 32,
|
|
addr: vec![0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
},
|
|
)]),
|
|
}],
|
|
}),
|
|
as_resources: None,
|
|
..rc.tbs.extensions.clone()
|
|
});
|
|
TaCertificate::validate_rc_constraints(&rc).expect("valid explicit resources");
|
|
|
|
// Valid non-empty explicit AS resources => OK.
|
|
let rc = dummy_rc_ca(RcExtensions {
|
|
ip_resources: None,
|
|
as_resources: Some(AsResourceSet {
|
|
asnum: Some(AsIdentifierChoice::AsIdsOrRanges(vec![AsIdOrRange::Id(
|
|
64512,
|
|
)])),
|
|
rdi: None,
|
|
}),
|
|
..rc.tbs.extensions.clone()
|
|
});
|
|
TaCertificate::validate_rc_constraints(&rc).expect("valid explicit AS resources");
|
|
}
|