Compare commits

..

1 Commits

Author SHA1 Message Date
xiuting.xu
767923cea7 增加RC数据结构和资源集合数据结构 2026-02-02 15:31:47 +08:00
5 changed files with 393 additions and 520 deletions

View File

@ -10,6 +10,3 @@ thiserror = "2.0.18"
time = "0.3.45" time = "0.3.45"
x509-parser = { version = "0.18.0", features = ["verify"] } x509-parser = { version = "0.18.0", features = ["verify"] }
url = "2.5.8" url = "2.5.8"
asn1-rs = "0.7.1"
asn1-rs-derive = "0.6.0"
asn1 = "0.23.0"

View File

@ -11,6 +11,3 @@ pub const OID_AD_OCSP: &str = "1.3.6.1.5.5.7.48.1";
pub const OID_SUBJECT_INFO_ACCESS: &str = "1.3.6.1.5.5.7.1.11"; pub const OID_SUBJECT_INFO_ACCESS: &str = "1.3.6.1.5.5.7.1.11";
pub const OID_CERTIFICATE_POLICIES: &str = "2.5.29.32"; pub const OID_CERTIFICATE_POLICIES: &str = "2.5.29.32";
pub const OID_SHA256_WITH_RSA_ENCRYPTION: &str = "1.2.840.113549.1.1.11"; pub const OID_SHA256_WITH_RSA_ENCRYPTION: &str = "1.2.840.113549.1.1.11";
pub const OID_IP_ADDRESS_BLOCKS: &str = "1.3.6.1.5.5.7.1.7";
pub const OID_AS_IDENTIFIERS: &str = "1.3.6.1.5.5.7.1.8";
pub const OID_RPKI_CP: &str = "1.3.6.1.5.5.7.14.2";

View File

@ -1,4 +1,3 @@
use asn1::{parse, BitString};
use der_parser::asn1_rs::Tag; use der_parser::asn1_rs::Tag;
use der_parser::num_bigint::BigUint; use der_parser::num_bigint::BigUint;
use url::Url; use url::Url;
@ -6,11 +5,9 @@ use time::OffsetDateTime;
use x509_parser::x509::AlgorithmIdentifier; use x509_parser::x509::AlgorithmIdentifier;
use x509_parser::prelude::{Validity, KeyUsage, X509Certificate, FromDer, use x509_parser::prelude::{Validity, KeyUsage, X509Certificate, FromDer,
X509Version, X509Extension, ParsedExtension, X509Version, X509Extension, ParsedExtension,
DistributionPointName, GeneralName}; CRLDistributionPoints, DistributionPointName, GeneralName};
use crate::data_model::crl::CrlDecodeError; use crate::data_model::crl::CrlDecodeError;
use crate::data_model::resources::ip_resources::{Afi, IPAddrBlocks, IPAddress, IPAddressChoice, use crate::data_model::resources::ip_resources::IPAddrBlocks;
IPAddressOrRange, IPAddressPrefix, IPAddressRange,
IPAddressFamily};
use crate::data_model::resources::as_resources::ASIdentifiers; use crate::data_model::resources::as_resources::ASIdentifiers;
use crate::data_model::oids; use crate::data_model::oids;
@ -130,510 +127,393 @@ pub enum ResourceCertError {
#[error("Empty AuthorityInfoAccess!")] #[error("Empty AuthorityInfoAccess!")]
EmptyAuthorityInfoAccess, EmptyAuthorityInfoAccess,
#[error("Certificate Policies must exists one policy")]
CertificatePoliciesTooMany,
#[error("Certificate Policies invalid")]
CertificatePoliciesInvalid,
} }
impl ResourceCert{ // impl ResourceCert{
pub fn from_der(cert_der: &[u8]) -> Result<Self, ResourceCertError> { // pub fn from_der(cert_der: &[u8]) -> Result<Self, ResourceCertError> {
let (rem, x509_rc) = X509Certificate::from_der(cert_der) // let (rem, x509_rc) = X509Certificate::from_der(cert_der)
.map_err(|e| ResourceCertError::ParseCert(e.to_string()))?; // .map_err(|e| ResourceCertError::ParseCert(e.to_string()))?;
//
if !rem.is_empty() { // if !rem.is_empty() {
return Err(ResourceCertError::TrailingBytes(rem.len())); // return Err(ResourceCertError::TrailingBytes(rem.len()));
} // }
//
// 校验 // // 校验
parse_and_validate_cert(x509_rc) // parse_and_validate_cert(x509_rc)
} // }
//
//
//
} // }
//
fn parse_and_validate_cert(x509_rc: X509Certificate) -> Result<ResourceCert, ResourceCertError> { // fn parse_and_validate_cert(x509_rc: X509Certificate) -> Result<ResourceCert, ResourceCertError> {
///逐个校验RC的内容, 如果有任何一个校验失败, 则返回错误 // ///逐个校验RC的内容, 如果有任何一个校验失败, 则返回错误
//
// 1. 版本号必须是V3 // // 1. 版本号必须是V3
let version = match x509_rc.version() { // let version = match x509_rc.version() {
X509Version::V3 => X509Version::V3, // X509Version::V3 => X509Version::V3,
v => { // v => {
return Err(ResourceCertError::InvalidVersion(v.0)); // return Err(ResourceCertError::InvalidVersion(v.0));
} // }
}; // };
//
// 2.校验签名算法 // // 2.校验签名算法
// 2.1. 校验外层的签名算法与里层的一致 // // 2.1. 校验外层的签名算法与里层的一致
let outer = &x509_rc.signature_algorithm; // let outer = &x509_rc.signature_algorithm;
let inner = &x509_rc.tbs_certificate.signature; // let inner = &x509_rc.tbs_certificate.signature;
//
if outer.algorithm != inner.algorithm || outer.parameters != inner.parameters { // if outer.algorithm != inner.algorithm || outer.parameters != inner.parameters {
return Err(ResourceCertError::SignatureAlgorithmMismatch); // return Err(ResourceCertError::SignatureAlgorithmMismatch);
} // }
//2.2 RPKI的签名算法必须是rsaWithSHA256 // //2.2 RPKI的签名算法必须是rsaWithSHA256
let signature_algorithm = &x509_rc.signature_algorithm; // let signature_algorithm = &x509_rc.signature_algorithm;
if signature_algorithm.algorithm.to_id_string() != oids::OID_SHA256_WITH_RSA_ENCRYPTION { // if signature_algorithm.algorithm.to_id_string() != oids::OID_SHA256_WITH_RSA_ENCRYPTION {
return Err(ResourceCertError::UnsupportedSignatureAlgorithm); // return Err(ResourceCertError::UnsupportedSignatureAlgorithm);
} // }
validate_sig_params(signature_algorithm)?; // validate_sig_params(signature_algorithm)?;
//
// 3. 校验Validity // // 3. 校验Validity
let validity = x509_rc.validity(); // let validity = x509_rc.validity();
validate_validity(validity, OffsetDateTime::now_utc())?; // validate_validity(validity, OffsetDateTime::now_utc())?;
//
// 4. SubjectPublicKeyInfo // // 4. SubjectPublicKeyInfo
let subject_public_key_info = x509_rc.tbs_certificate.subject_pki; // let subject_public_key_info = x509_rc.tbs_certificate.subject_pki;
//
let extensions = parse_and_validate_extensions(x509_rc.extensions())?; // let extensions = parse_and_validate_extensions(x509_rc.extensions())?;
//
// TODO // Ok(ResourceCert {
Ok(ResourceCert { // cert_der: x509_rc.to_der().to_vec(),
// version: version.0,
}) // serial_number: x509_rc.serial(),
// signature_algorithm_oid: signature_algorithm.algorithm.to_id_string(),
// issuer_dn: x509_rc.issuer().to_string(),
} // subject_dn: x509_rc.subject().to_string(),
// validity,
fn validate_sig_params(sig: &AlgorithmIdentifier<'_>) -> Result<(), CrlDecodeError> { // subject_public_key_info: SubjectPublicKeyInfo {
match sig.parameters.as_ref() { // // algorithm_oid: x509_rc.tbs_certificate.subject_pki.algorithm.algorithm.to_id_string(),
None => Ok(()), // // subject_public_key: x509_rc.tbs_certificate.subject_pki.subject_public_key.unused_bits,
Some(p) if p.tag() == Tag::Null => Ok(()), // },
Some(_p) => Err(CrlDecodeError::InvalidSignatureAlgorithmParameters), // extensions,
} // })
} //
//
fn validate_validity( // }
validity: &Validity, //
now: OffsetDateTime, // fn validate_sig_params(sig: &AlgorithmIdentifier<'_>) -> Result<(), CrlDecodeError> {
) -> Result<(), ResourceCertError> { // match sig.parameters.as_ref() {
let not_before = validity.not_before.to_datetime(); // None => Ok(()),
let not_after = validity.not_after.to_datetime(); // Some(p) if p.tag() == Tag::Null => Ok(()),
// Some(_p) => Err(CrlDecodeError::InvalidSignatureAlgorithmParameters),
if not_after < not_before { // }
return Err(ResourceCertError::InvalidValidityRange); // }
} //
// fn validate_validity(
if now < not_before { // validity: &Validity,
return Err(ResourceCertError::NotYetValid); // now: OffsetDateTime,
} // ) -> Result<(), ResourceCertError> {
// let not_before = validity.not_before.to_datetime();
if now > not_after { // let not_after = validity.not_after.to_datetime();
return Err(ResourceCertError::Expired); //
} // if not_after < not_before {
// return Err(ResourceCertError::InvalidValidityRange);
Ok(()) // }
} //
// if now < not_before {
// return Err(ResourceCertError::NotYetValid);
pub fn parse_and_validate_extensions( // }
exts: &[X509Extension<'_>], //
) -> Result<RcExtension, ResourceCertError> { // if now > not_after {
let mut basic_constraints = None; // return Err(ResourceCertError::Expired);
let mut ip_addr_blocks = None; // }
let mut as_identifiers = None; //
let mut ski = None; // Ok(())
let mut aki = None; // }
let mut crl_dp = None; //
let mut aia = None; //
let mut sia = None; // pub fn parse_and_validate_extensions(
let mut key_usage = None; // exts: &[X509Extension<'_>],
let mut extended_key_usage = None; // ) -> Result<RcExtension, ResourceCertError> {
let mut certificate_policies = None; // let mut basic_constraints = None;
// let mut ip_addr_blocks = None;
for ext in exts { // let mut as_identifiers = None;
let oid = ext.oid.to_id_string(); // let mut ski = None;
let critical = ext.critical; // let mut aki = None;
match oid.as_str() { // let mut crl_dp = None;
oids::OID_BASIC_CONSTRAINTS => { // let mut aia = None;
if basic_constraints.is_some() { // let mut sia = None;
return Err(ResourceCertError::DuplicateExtension("basicConstraints".into())); // let mut key_usage = None;
} // let mut extended_key_usage = None;
if !critical { // let mut certificate_policies = None;
return Err(ResourceCertError::CriticalError("basicConstraints".into(), "critical".into())); //
} // for ext in exts {
let bc = parse_basic_constraints(ext)?; // let oid = ext.oid.to_id_string();
basic_constraints = Some(bc); // let critical = ext.critical;
} // match oid.as_str() {
oids::OID_SUBJECT_KEY_IDENTIFIER => { // oids::OID_BASIC_CONSTRAINTS => {
if ski.is_some() { // if basic_constraints.is_some() {
return Err(ResourceCertError::DuplicateExtension("subjectKeyIdentifier".into())); // return Err(ResourceCertError::DuplicateExtension("basicConstraints".into()));
} // }
if critical { // if !critical {
return Err(ResourceCertError::CriticalError("subjectKeyIdentifier".into(), "non-critical".into())); // return Err(ResourceCertError::CriticalError("basicConstraints".into(), "critical".into()));
} // }
let s = parse_subject_key_identifier(ext)?; // let bc = parse_basic_constraints(ext)?;
ski = Some(s); // basic_constraints = Some(bc);
} // }
oids::OID_AUTHORITY_KEY_IDENTIFIER => { // oids::OID_SUBJECT_KEY_IDENTIFIER => {
if aki.is_some() { // if ski.is_some() {
return Err(ResourceCertError::DuplicateExtension("authorityKeyIdentifier".into())); // return Err(ResourceCertError::DuplicateExtension("subjectKeyIdentifier".into()));
} // }
if critical { // if critical {
return Err(ResourceCertError::CriticalError("authorityKeyIdentifier".into(), "non-critical".into())); // return Err(ResourceCertError::CriticalError("subjectKeyIdentifier".into(), "non-critical".into()));
} // }
let a = parse_authority_key_identifier(ext)?; // let s = parse_subject_key_identifier(ext)?;
aki = Some(a); // ski = Some(s);
} // }
oids::OID_KEY_USAGE => { // oids::OID_AUTHORITY_KEY_IDENTIFIER => {
if key_usage.is_some() { // if aki.is_some() {
return Err(ResourceCertError::DuplicateExtension("keyUsage".into())); // return Err(ResourceCertError::DuplicateExtension("authorityKeyIdentifier".into()));
} // }
if !critical { // if critical {
return Err(ResourceCertError::CriticalError("keyUsage".into(), "critical".into())); // return Err(ResourceCertError::CriticalError("authorityKeyIdentifier".into(), "non-critical".into()));
} // }
let ku = parse_key_usage(ext)?; // let a = parse_authority_key_identifier(ext)?;
key_usage = Some(ku); // aki = Some(a);
} // }
oids::OID_EXTENDED_KEY_USAGE => { // oids::OID_KEY_USAGE => {
if extended_key_usage.is_some() { // if key_usage.is_some() {
return Err(ResourceCertError::DuplicateExtension("extendedKeyUsage".into())); // return Err(ResourceCertError::DuplicateExtension("keyUsage".into()));
} // }
if critical { // if !critical {
return Err(ResourceCertError::CriticalError("extendedKeyUsage".into(), "non-critical".into())); // return Err(ResourceCertError::CriticalError("keyUsage".into(), "critical".into()));
} // }
let eku = oids::OID_EXTENDED_KEY_USAGE; // let ku = parse_key_usage(ext)?;
} // key_usage = Some(ku);
oids::OID_CRL_DISTRIBUTION_POINTS => { // }
if crl_dp.is_some() { // oids::OID_EXTENDED_KEY_USAGE => {
return Err(ResourceCertError::DuplicateExtension("crlDistributionPoints".into())); // if extended_key_usage.is_some() {
} // return Err(ResourceCertError::DuplicateExtension("extendedKeyUsage".into()));
if critical { // }
return Err(ResourceCertError::CriticalError("crlDistributionPoints".into(), "non-critical".into())); // if critical {
} // return Err(ResourceCertError::CriticalError("extendedKeyUsage".into(), "non-critical".into()));
let cdp = parse_crl_distribution_points(ext)?; // }
crl_dp = Some(cdp); // let eku = oids::OID_EXTENDED_KEY_USAGE;
} // }
oids::OID_AUTHORITY_INFO_ACCESS => { // oids::OID_CRL_DISTRIBUTION_POINTS => {
if aia.is_some() { // if crl_dp.is_some() {
return Err(ResourceCertError::DuplicateExtension("authorityInfoAccess".into())); // return Err(ResourceCertError::DuplicateExtension("crlDistributionPoints".into()));
} // }
if critical { // if critical {
return Err(ResourceCertError::CriticalError("authorityInfoAccess".into(), "non-critical".into())); // return Err(ResourceCertError::CriticalError("crlDistributionPoints".into(), "non-critical".into()));
} // }
let p_aia = parse_authority_info_access(ext)?; // let cdp = parse_crl_distribution_points(ext)?;
aia = Some(p_aia); // crl_dp = Some(cdp);
} // }
oids::OID_SUBJECT_INFO_ACCESS => { // oids::OID_AUTHORITY_INFO_ACCESS => {
if sia.is_some() { // if aia.is_some() {
return Err(ResourceCertError::DuplicateExtension("subjectInfoAccess".into())); // return Err(ResourceCertError::DuplicateExtension("authorityInfoAccess".into()));
} // }
if critical { // if critical {
return Err(ResourceCertError::CriticalError("subjectInfoAccess".into(), "non-critical".into())); // return Err(ResourceCertError::CriticalError("authorityInfoAccess".into(), "non-critical".into()));
} // }
let p_sia = parse_subject_info_access(ext)?; // let p_aia = parse_authority_info_access(ext)?;
sia = Some(p_sia); // aia = Some(p_aia);
} // }
oids::OID_CERTIFICATE_POLICIES => { // oids::OID_SUBJECT_INFO_ACCESS => {
if certificate_policies.is_some() { // if sia.is_some() {
return Err(ResourceCertError::DuplicateExtension("certificatePolicies".into())); // return Err(ResourceCertError::DuplicateExtension("subjectInfoAccess".into()));
} // }
if !critical { // if critical {
return Err(ResourceCertError::CriticalError("certificatePolicies".into(), "critical".into())); // return Err(ResourceCertError::CriticalError("subjectInfoAccess".into(), "non-critical".into()));
} // }
let p_cp = parse_certificate_policies(ext)?; // let p_sia = parse_subject_info_access(ext)?;
certificate_policies = Some(p_cp); // sia = Some(p_sia);
} // }
oids::OID_IP_ADDRESS_BLOCKS => { // oids::OID_CERTIFICATE_POLICIES => {
if ip_addr_blocks.is_some() { // if certificate_policies.is_some() {
return Err(ResourceCertError::DuplicateExtension("ipAddressBlocks".into())); // return Err(ResourceCertError::DuplicateExtension("certificatePolicies".into()));
} // }
if !critical { // if !critical {
return Err(ResourceCertError::CriticalError("ipAddressBlocks".into(), "critical".into())); // return Err(ResourceCertError::CriticalError("certificatePolicies".into(), "critical".into()));
} // }
let p_ip = parse_ip_address_blocks(ext)?; // let p_cp = parse_certificate_policies(ext)?;
ip_addr_blocks = Some(p_ip); // certificate_policies = Some(p_cp);
} // }
oids::OID_AS_IDENTIFIERS => { // }
if as_identifiers.is_some() { //
return Err(ResourceCertError::DuplicateExtension("asIdentifiers".into())); //
} // }
if !critical { // Ok(RcExtension {
return Err(ResourceCertError::CriticalError("asIdentifiers".into(), "critical".into())); // basic_constraints,
} // ip_addr_blocks,
let p_as = parse_as_identifiers(ext)?; // as_identifiers,
as_identifiers = Some(p_as); // subject_key_id: ski,
} // authority_key_id: aki,
} // crl_distribution_points: crl_dp,
} // authority_info_access: aia,
// })
// TODO: // }
Ok(RcExtension { //
// fn parse_basic_constraints(ext: &X509Extension<'_>) -> Result<bool, ResourceCertError> {
} // let ParsedExtension::BasicConstraints(bc) = ext.parsed_extension() else {
} // return Err(ResourceCertError::ParseCert("basicConstraints parse failed".into()));
// };
fn parse_basic_constraints(ext: &X509Extension<'_>) -> Result<bool, ResourceCertError> { // Ok(bc.ca)
let ParsedExtension::BasicConstraints(bc) = ext.parsed_extension() else { // }
return Err(ResourceCertError::ParseCert("basicConstraints parse failed".into())); //
}; // fn parse_subject_key_identifier(ext: &X509Extension<'_>) -> Result<Vec<u8>, ResourceCertError> {
Ok(bc.ca) // let ParsedExtension::SubjectKeyIdentifier(s) = ext.parsed_extension() else {
} // return Err(ResourceCertError::ParseCert("subjectKeyIdentifier parse failed".into()));
// };
fn parse_subject_key_identifier(ext: &X509Extension<'_>) -> Result<Vec<u8>, ResourceCertError> { // Ok(s.0.to_vec())
let ParsedExtension::SubjectKeyIdentifier(s) = ext.parsed_extension() else { // }
return Err(ResourceCertError::ParseCert("subjectKeyIdentifier parse failed".into())); //
}; // fn parse_authority_key_identifier(ext: &X509Extension<'_>) -> Result<Vec<u8>, ResourceCertError> {
Ok(s.0.to_vec()) // let ParsedExtension::AuthorityKeyIdentifier(aki) = ext.parsed_extension() else {
} // return Err(ResourceCertError::ParseCert("authorityKeyIdentifier parse failed".into()));
// };
fn parse_authority_key_identifier(ext: &X509Extension<'_>) -> Result<Vec<u8>, ResourceCertError> { // let key_id = aki
let ParsedExtension::AuthorityKeyIdentifier(aki) = ext.parsed_extension() else { // .key_identifier
return Err(ResourceCertError::ParseCert("authorityKeyIdentifier parse failed".into())); // .as_ref()
}; // .ok_or(ResourceCertError::MissingParameter("key_identifier".into()))?;
let key_id = aki //
.key_identifier // if aki.authority_cert_issuer.is_some() {
.as_ref() // return Err(ResourceCertError::UnexceptedParameter("authority_cert_issuer".into()));
.ok_or(ResourceCertError::MissingParameter("key_identifier".into()))?; // }
// if aki.authority_cert_serial.is_some() {
if aki.authority_cert_issuer.is_some() { // return Err(ResourceCertError::UnexceptedParameter("authority_cert_serial".into()));
return Err(ResourceCertError::UnexceptedParameter("authority_cert_issuer".into())); // }
} //
if aki.authority_cert_serial.is_some() { //
return Err(ResourceCertError::UnexceptedParameter("authority_cert_serial".into())); // Ok(key_id.0.to_vec())
} // }
//
// fn parse_key_usage(ext: &X509Extension<'_>) -> Result<KeyUsage, ResourceCertError> {
Ok(key_id.0.to_vec()) // let ParsedExtension::KeyUsage(ku) = ext.parsed_extension() else {
} // return Err(ResourceCertError::ParseCert("keyUsage parse failed".into()));
// };
fn parse_key_usage(ext: &X509Extension<'_>) -> Result<KeyUsage, ResourceCertError> { // Ok(ku.clone())
let ParsedExtension::KeyUsage(ku) = ext.parsed_extension() else { // }
return Err(ResourceCertError::ParseCert("keyUsage parse failed".into())); //
}; // fn parse_crl_distribution_points(ext: &X509Extension<'_>) -> Result<Vec<Url>, ResourceCertError> {
Ok(ku.clone()) // let ParsedExtension::CRLDistributionPoints(cdp) = ext.parsed_extension() else {
} // return Err(ResourceCertError::ParseCert("crlDistributionPoints parse failed".into()));
// };
fn parse_crl_distribution_points(ext: &X509Extension<'_>) -> Result<Vec<Url>, ResourceCertError> { // let mut urls = Vec::new();
let ParsedExtension::CRLDistributionPoints(cdp) = ext.parsed_extension() else { // for point in cdp.points.iter() {
return Err(ResourceCertError::ParseCert("crlDistributionPoints parse failed".into())); // if point.reasons.is_some() {
}; // return Err(ResourceCertError::UnexceptedParameter("reasons".into()));
let mut urls = Vec::new(); // }
for point in cdp.points.iter() { // if point.crl_issuer.is_some() {
if point.reasons.is_some() { // return Err(ResourceCertError::UnexceptedParameter("crl_issuer".into()));
return Err(ResourceCertError::UnexceptedParameter("reasons".into())); // }
} //
if point.crl_issuer.is_some() { // let dp_name = point.distribution_point.as_ref()
return Err(ResourceCertError::UnexceptedParameter("crl_issuer".into())); // .ok_or(ResourceCertError::MissingParameter("distribution_point".into()))?;
} // match dp_name {
// DistributionPointName::FullName(names) => {
let dp_name = point.distribution_point.as_ref() // for name in names {
.ok_or(ResourceCertError::MissingParameter("distribution_point".into()))?; // match name {
match dp_name { // GeneralName::URI(uri) => {
DistributionPointName::FullName(names) => { // let url = Url::parse(uri)
for name in names { // .map_err(|_| ResourceCertError::InvalidUri(uri.to_string()))?;
match name { // urls.push(url);
GeneralName::URI(uri) => { // }
let url = Url::parse(uri) // _ => {
.map_err(|_| ResourceCertError::InvalidUri(uri.to_string()))?; // return Err(ResourceCertError::UnsupportedGeneralName("distribution_point".into()));
urls.push(url); // }
} // }
_ => { // }
return Err(ResourceCertError::UnsupportedGeneralName("distribution_point".into())); //
} // }
} // DistributionPointName::NameRelativeToCRLIssuer(_) => {
} // return Err(ResourceCertError::UnsupportedCrlDistributionPoint);
// }
} // }
DistributionPointName::NameRelativeToCRLIssuer(_) => { // }
return Err(ResourceCertError::UnsupportedCrlDistributionPoint); // if urls.is_empty() {
} // return Err(ResourceCertError::MissingParameter("distribution_point".into()));
} // }
} // Ok(urls)
if urls.is_empty() { // }
return Err(ResourceCertError::MissingParameter("distribution_point".into())); //
} // fn parse_authority_info_access(
Ok(urls) // ext: &X509Extension<'_>,
} // ) -> Result<Vec<AccessDescription>, ResourceCertError> {
// let ParsedExtension::AuthorityInfoAccess(aia) = ext.parsed_extension() else {
fn parse_authority_info_access( // return Err(ResourceCertError::ParseCert(
ext: &X509Extension<'_>, // "authorityInfoAccess parse failed".into(),
) -> Result<Vec<AccessDescription>, ResourceCertError> { // ));
let ParsedExtension::AuthorityInfoAccess(aia) = ext.parsed_extension() else { // };
return Err(ResourceCertError::ParseCert( //
"authorityInfoAccess parse failed".into(), // let mut access_descriptions = Vec::new();
)); //
}; // for access in &aia.accessdescs {
// let access_method_oid = access.access_method.to_id_string();
let mut access_descriptions = Vec::new(); //
// let uri = match &access.access_location {
for access in &aia.accessdescs { // GeneralName::URI(uri) => uri,
let access_method_oid = access.access_method.to_id_string(); // _ => {
// return Err(ResourceCertError::InvalidAccessLocationType);
let uri = match &access.access_location { // }
GeneralName::URI(uri) => uri, // };
_ => { //
return Err(ResourceCertError::InvalidAccessLocationType); // let url = Url::parse(uri)
} // .map_err(|_| ResourceCertError::InvalidUri(uri.to_string()))?;
}; //
// access_descriptions.push(AccessDescription {
let url = Url::parse(uri) // access_method_oid,
.map_err(|_| ResourceCertError::InvalidUri(uri.to_string()))?; // access_location: url,
// });
access_descriptions.push(AccessDescription { // }
access_method_oid, //
access_location: url, // if access_descriptions.is_empty() {
}); // return Err(ResourceCertError::EmptyAuthorityInfoAccess);
} // }
//
if access_descriptions.is_empty() { // Ok(access_descriptions)
return Err(ResourceCertError::EmptyAuthorityInfoAccess); // }
} //
// fn parse_subject_info_access(ext: &X509Extension<'_>) -> Result<Vec<AccessDescription>, ResourceCertError> {
Ok(access_descriptions) // let ParsedExtension::SubjectInfoAccess(sia) = ext.parsed_extension() else {
} // return Err(ResourceCertError::ParseCert(
// "subjectInfoAccess parse failed".into(),
fn parse_subject_info_access(ext: &X509Extension<'_>) -> Result<Vec<AccessDescription>, ResourceCertError> { // ));
let ParsedExtension::SubjectInfoAccess(sia) = ext.parsed_extension() else { // };
return Err(ResourceCertError::ParseCert( // let mut access_descriptions = Vec::new();
"subjectInfoAccess parse failed".into(), //
)); // for access in &sia.accessdescs {
}; // let access_method_oid = access.access_method.to_id_string();
let mut access_descriptions = Vec::new(); //
// // accessLocation: MUST be URI in RPKI
for access in &sia.accessdescs { // let uri = match &access.access_location {
let access_method_oid = access.access_method.to_id_string(); // GeneralName::URI(uri) => uri,
// _ => {
// accessLocation: MUST be URI in RPKI // return Err(ResourceCertError::InvalidAccessLocationType);
let uri = match &access.access_location { // }
GeneralName::URI(uri) => uri, // };
_ => { //
return Err(ResourceCertError::InvalidAccessLocationType); // let url = Url::parse(uri)
} // .map_err(|_| ResourceCertError::InvalidUri(uri.to_string()))?;
}; //
// access_descriptions.push(AccessDescription {
let url = Url::parse(uri) // access_method_oid,
.map_err(|_| ResourceCertError::InvalidUri(uri.to_string()))?; // access_location: url,
// });
access_descriptions.push(AccessDescription { // }
access_method_oid, //
access_location: url, // if access_descriptions.is_empty() {
}); // return Err(ResourceCertError::EmptyAuthorityInfoAccess);
} // }
//
if access_descriptions.is_empty() { // Ok(access_descriptions)
return Err(ResourceCertError::EmptyAuthorityInfoAccess); // }
} //
// fn parse_certificate_policies(ext: &X509Extension<'_>) -> Result<Vec<PolicyInformation>, ResourceCertError> {
Ok(access_descriptions) // let ParsedExtension::CertificatePolicies(cp) = ext.parsed_extension() else {
} // return Err(ResourceCertError::ParseCert(
// "certificatePolicies parse failed".into(),
fn parse_certificate_policies(ext: &X509Extension<'_>) -> Result<Vec<PolicyInformation>, ResourceCertError> { // ));
let ParsedExtension::CertificatePolicies(cp) = ext.parsed_extension() else { // };
return Err(ResourceCertError::ParseCert( // let mut policies = Vec::new();
"certificatePolicies parse failed".into(), //
)); // }
};
let mut policies = Vec::new();
if cp.len() > 1 {
return Err(ResourceCertError::CertificatePoliciesTooMany);
}
let policy_info = cp.first().unwrap();
let policy_id = policy_info.policy_id.to_id_string();
if policy_id != oids::OID_RPKI_CP {
return Err(ResourceCertError::CertificatePoliciesInvalid);
}
let policy_info = PolicyInformation{
policy_oid: policy_id,
};
policies.push(policy_info);
Ok(policies)
}
fn bitstring_to_ip(b: &BitString, afi: &Afi) -> Result<IPAddress, ResourceCertError> {
let bytes = b.as_bytes();
let ip = match afi {
Afi::Ipv4 => {
if bytes.len() != 4 { return Err(ResourceCertError::ParseCert("IPv4 length mismatch".into())); }
u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as u128
},
Afi::Ipv6 => {
if bytes.len() != 16 { return Err(ResourceCertError::ParseCert("IPv6 length mismatch".into())); }
u128::from_be_bytes([
bytes[0], bytes[1], bytes[2], bytes[3],
bytes[4], bytes[5], bytes[6], bytes[7],
bytes[8], bytes[9], bytes[10], bytes[11],
bytes[12], bytes[13], bytes[14], bytes[15],
])
},
};
Ok(IPAddress(ip))
}
fn parse_ip_address_blocks(ext: &X509Extension<'_>) -> Result<IPAddrBlocks, ResourceCertError> {
let ip_blocks_der = ext.value;
let ips = parse(ip_blocks_der, |p| {
// 顶层 SEQUENCE OF IPAddressFamily
let mut ip_families = Vec::new();
p.read_sequence_of(|p2| {
// 每个 IPAddressFamily 是 SEQUENCE { addressFamily OCTET STRING, ipAddressChoice }
p2.read_sequence(|p3| {
let address_family_bytes = p3.read_element::<&[u8]>()?;
let afi = match address_family_bytes {
[0,1] => Afi::Ipv4,
[0,2] => Afi::Ipv6,
_ => return Err(asn1::ParseError::new(asn1::ParseErrorKind::InvalidValue)),
};
// 解析 IPAddressChoice
let ip_address_choice = {
let peek_tag = p3.peek_tag()?;
match peek_tag.tag_number() {
5 => IPAddressChoice::Inherit, // NULL
16 => { // SEQUENCE OF IPAddressOrRange
let ranges = p3.read_sequence_of(|p4| {
// 解析 IPAddressOrRange CHOICE
let peek = p4.peek_tag()?.tag_number();
if peek == 16 { // SEQUENCE -> AddressPrefix
let (addr_bytes, prefix_len): (&[u8], u8) = p4.read_sequence(|p5| {
let addr = p5.read_element::<BitString>()?.as_bytes();
let prefix_len = addr.len() as u8 * 8; // 简化:用字节长度推前缀
Ok((addr, prefix_len))
})?;
Ok(IPAddressOrRange::AddressPrefix(IPAddressPrefix{
address: bitstring_to_ip(addr_bytes, &afi)?,
prefix_length: prefix_len,
}))
} else {
// AddressRange
let (min_bytes, max_bytes) = p4.read_sequence(|p5| {
let min = p5.read_element::<BitString>()?.as_bytes();
let max = p5.read_element::<BitString>()?.as_bytes();
Ok((min, max))
})?;
Ok(IPAddressOrRange::AddressRange(IPAddressRange{
min: bitstring_to_ip(min_bytes, &afi)?,
max: bitstring_to_ip(max_bytes, &afi)?,
}))
}
})?;
IPAddressChoice::AddressOrRange(ranges)
}
_ => return Err(asn1::ParseError::new(asn1::ParseErrorKind::InvalidValue)),
}
};
ip_families.push(IPAddressFamily {
address_family: afi,
ip_address_choice,
});
Ok(())
})
})?;
Ok(IPAddrBlocks { ips: ip_families })
}).map_err(|_| ResourceCertError::ParseCert("Failed to parse IPAddrBlocks DER".into()))?;
Ok(ips)
}
fn parse_as_identifiers(ext: &X509Extension<'_>) -> Result<Vec<AsIdentifier>, ResourceCertError> {
let as_identifiers_der = ext.value;
// TODO: 解析 ASIdentifiers DER
}

View File

@ -1,7 +1,7 @@
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct IPAddrBlocks { pub struct IPAddrBlocks {
pub ips: Vec<IPAddressFamily> ips: Vec<IPAddressFamily>
} }
@ -44,4 +44,3 @@ pub struct IPAddressRange {
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct IPAddress(u128); pub struct IPAddress(u128);