串行验证通过
This commit is contained in:
123
src/validation/ca_instance.rs
Normal file
123
src/validation/ca_instance.rs
Normal file
@@ -0,0 +1,123 @@
|
||||
use crate::data_model::oid::{OID_AD_CA_REPOSITORY, OID_AD_RPKI_MANIFEST, OID_AD_RPKI_NOTIFY};
|
||||
use crate::data_model::rc::{ResourceCertKind, ResourceCertificate, SubjectInfoAccess};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct CaInstanceUris {
|
||||
/// CA repository base rsync URI (must end with `/`).
|
||||
pub rsync_base_uri: String,
|
||||
/// rsync URI for the manifest object (`.mft`).
|
||||
pub manifest_rsync_uri: String,
|
||||
/// Publication point rsync URI (RFC 9286 terminology). In v1 this equals `rsync_base_uri`.
|
||||
pub publication_point_rsync_uri: String,
|
||||
/// Optional RRDP notification URI (https).
|
||||
pub rrdp_notification_uri: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum CaInstanceUrisError {
|
||||
#[error("certificate must be a CA certificate (RFC 6487 §4.8.1)")]
|
||||
NotCa,
|
||||
|
||||
#[error(
|
||||
"CA certificate must contain Subject Information Access extension (RFC 6487 §4.8.8; RFC 5280 §4.2.2.2)"
|
||||
)]
|
||||
MissingSia,
|
||||
|
||||
#[error("CA certificate SIA must contain id-ad-caRepository rsync URI (RFC 6487 §4.8.8.1)")]
|
||||
MissingCaRepository,
|
||||
|
||||
#[error("CA certificate SIA must contain id-ad-rpkiManifest rsync URI (RFC 6487 §4.8.8.2)")]
|
||||
MissingRpkiManifest,
|
||||
|
||||
#[error(
|
||||
"SIA id-ad-caRepository accessLocation must be rsync:// URI, got {0} (RFC 6487 §4.8.8.1)"
|
||||
)]
|
||||
CaRepositoryNotRsync(String),
|
||||
|
||||
#[error(
|
||||
"SIA id-ad-rpkiManifest accessLocation must be rsync:// URI, got {0} (RFC 6487 §4.8.8.2)"
|
||||
)]
|
||||
RpkiManifestNotRsync(String),
|
||||
|
||||
#[error(
|
||||
"SIA id-ad-rpkiNotify accessLocation must be https:// URI, got {0} (RFC 8182 §3.4.1; RFC 6487 §4.8.8.3)"
|
||||
)]
|
||||
RpkiNotifyNotHttps(String),
|
||||
|
||||
#[error(
|
||||
"manifest rsync URI must be under CA publication point: manifest={manifest_rsync_uri} publication_point={publication_point_rsync_uri} (RFC 9286 §6.1)"
|
||||
)]
|
||||
ManifestNotUnderPublicationPoint {
|
||||
manifest_rsync_uri: String,
|
||||
publication_point_rsync_uri: String,
|
||||
},
|
||||
}
|
||||
|
||||
pub fn ca_instance_uris_from_ca_certificate(
|
||||
cert: &ResourceCertificate,
|
||||
) -> Result<CaInstanceUris, CaInstanceUrisError> {
|
||||
if cert.kind != ResourceCertKind::Ca {
|
||||
return Err(CaInstanceUrisError::NotCa);
|
||||
}
|
||||
|
||||
let sia = cert
|
||||
.tbs
|
||||
.extensions
|
||||
.subject_info_access
|
||||
.as_ref()
|
||||
.ok_or(CaInstanceUrisError::MissingSia)?;
|
||||
|
||||
let access_descriptions = match sia {
|
||||
SubjectInfoAccess::Ca(ca) => &ca.access_descriptions,
|
||||
SubjectInfoAccess::Ee(_ee) => return Err(CaInstanceUrisError::MissingSia),
|
||||
};
|
||||
|
||||
let mut ca_repo: Option<String> = None;
|
||||
let mut manifest: Option<String> = None;
|
||||
let mut notify: Option<String> = None;
|
||||
|
||||
for ad in access_descriptions {
|
||||
if ad.access_method_oid == OID_AD_CA_REPOSITORY {
|
||||
let u = ad.access_location.to_string();
|
||||
if ad.access_location.scheme() != "rsync" {
|
||||
return Err(CaInstanceUrisError::CaRepositoryNotRsync(u));
|
||||
}
|
||||
ca_repo.get_or_insert(u);
|
||||
} else if ad.access_method_oid == OID_AD_RPKI_MANIFEST {
|
||||
let u = ad.access_location.to_string();
|
||||
if ad.access_location.scheme() != "rsync" {
|
||||
return Err(CaInstanceUrisError::RpkiManifestNotRsync(u));
|
||||
}
|
||||
manifest.get_or_insert(u);
|
||||
} else if ad.access_method_oid == OID_AD_RPKI_NOTIFY {
|
||||
let u = ad.access_location.to_string();
|
||||
if ad.access_location.scheme() != "https" {
|
||||
return Err(CaInstanceUrisError::RpkiNotifyNotHttps(u));
|
||||
}
|
||||
notify.get_or_insert(u);
|
||||
}
|
||||
}
|
||||
|
||||
let mut publication_point_rsync_uri = ca_repo.ok_or(CaInstanceUrisError::MissingCaRepository)?;
|
||||
if !publication_point_rsync_uri.ends_with('/') {
|
||||
publication_point_rsync_uri.push('/');
|
||||
}
|
||||
|
||||
let rsync_base_uri = publication_point_rsync_uri.clone();
|
||||
|
||||
let manifest_rsync_uri = manifest.ok_or(CaInstanceUrisError::MissingRpkiManifest)?;
|
||||
if !manifest_rsync_uri.starts_with(&publication_point_rsync_uri) {
|
||||
return Err(CaInstanceUrisError::ManifestNotUnderPublicationPoint {
|
||||
manifest_rsync_uri,
|
||||
publication_point_rsync_uri,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(CaInstanceUris {
|
||||
rsync_base_uri,
|
||||
manifest_rsync_uri,
|
||||
publication_point_rsync_uri,
|
||||
rrdp_notification_uri: notify,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user