串行验证通过

This commit is contained in:
2026-02-09 19:35:54 +08:00
parent 7be865d7f1
commit afc31c02ab
66 changed files with 12049 additions and 4 deletions

146
src/validation/from_tal.rs Normal file
View File

@@ -0,0 +1,146 @@
use url::Url;
use crate::data_model::ta::{TrustAnchor, TrustAnchorError};
use crate::data_model::tal::{Tal, TalDecodeError};
use crate::sync::rrdp::Fetcher;
use crate::validation::ca_instance::{CaInstanceUris, CaInstanceUrisError, ca_instance_uris_from_ca_certificate};
use crate::validation::objects::IssuerCaCertificateResolver;
use crate::validation::run::{RunError, RunOutput, run_publication_point_once};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DiscoveredRootCaInstance {
pub tal_url: Option<String>,
pub trust_anchor: TrustAnchor,
pub ca_instance: CaInstanceUris,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RunFromTalOutput {
pub discovery: DiscoveredRootCaInstance,
pub run: RunOutput,
}
#[derive(Debug, thiserror::Error)]
pub enum FromTalError {
#[error("TAL fetch failed: {0} (RFC 8630 §2.2)")]
TalFetch(String),
#[error("TAL decode failed: {0} (RFC 8630 §2.2)")]
TalDecode(#[from] TalDecodeError),
#[error("failed to fetch TA certificate from TAL: {0} (RFC 8630 §2.3)")]
TaFetch(String),
#[error("failed to bind TAL and TA certificate: {0} (RFC 8630 §2.3)")]
Bind(#[from] TrustAnchorError),
#[error("failed to discover CA instance URIs from TA certificate: {0}")]
CaInstanceUris(#[from] CaInstanceUrisError),
#[error("run failed: {0}")]
Run(#[from] RunError),
#[error("TAL contains no TA URIs (RFC 8630 §2.2)")]
NoTaUris,
}
pub fn discover_root_ca_instance_from_tal_url(
http_fetcher: &dyn Fetcher,
tal_url: &str,
) -> Result<DiscoveredRootCaInstance, FromTalError> {
let tal_bytes = http_fetcher
.fetch(tal_url)
.map_err(FromTalError::TalFetch)?;
let tal = Tal::decode_bytes(&tal_bytes)?;
discover_root_ca_instance_from_tal(http_fetcher, tal, Some(tal_url.to_string()))
}
pub fn discover_root_ca_instance_from_tal(
http_fetcher: &dyn Fetcher,
tal: Tal,
tal_url: Option<String>,
) -> Result<DiscoveredRootCaInstance, FromTalError> {
if tal.ta_uris.is_empty() {
return Err(FromTalError::NoTaUris);
}
let mut last_err: Option<String> = None;
for ta_uri in tal.ta_uris.iter() {
let ta_der = match http_fetcher.fetch(ta_uri.as_str()) {
Ok(b) => b,
Err(e) => {
last_err = Some(format!("fetch {ta_uri} failed: {e}"));
continue;
}
};
let trust_anchor = match TrustAnchor::bind_der(tal.clone(), &ta_der, Some(ta_uri)) {
Ok(ta) => ta,
Err(e) => {
last_err = Some(format!("bind {ta_uri} failed: {e}"));
continue;
}
};
let ca_instance = match ca_instance_uris_from_ca_certificate(&trust_anchor.ta_certificate.rc_ca)
{
Ok(v) => v,
Err(e) => {
last_err = Some(format!("CA instance discovery failed: {e}"));
continue;
}
};
return Ok(DiscoveredRootCaInstance {
tal_url,
trust_anchor,
ca_instance,
});
}
Err(FromTalError::TaFetch(
last_err.unwrap_or_else(|| "unknown TA candidate error".to_string()),
))
}
pub fn discover_root_ca_instance_from_tal_and_ta_der(
tal_bytes: &[u8],
ta_der: &[u8],
resolved_ta_uri: Option<&Url>,
) -> Result<DiscoveredRootCaInstance, FromTalError> {
let tal = Tal::decode_bytes(tal_bytes)?;
let trust_anchor = TrustAnchor::bind_der(tal, ta_der, resolved_ta_uri)?;
let ca_instance = ca_instance_uris_from_ca_certificate(&trust_anchor.ta_certificate.rc_ca)?;
Ok(DiscoveredRootCaInstance {
tal_url: None,
trust_anchor,
ca_instance,
})
}
pub fn run_root_from_tal_url_once(
store: &crate::storage::RocksStore,
policy: &crate::policy::Policy,
tal_url: &str,
http_fetcher: &dyn Fetcher,
rsync_fetcher: &dyn crate::fetch::rsync::RsyncFetcher,
issuer_resolver: &dyn IssuerCaCertificateResolver,
validation_time: time::OffsetDateTime,
) -> Result<RunFromTalOutput, FromTalError> {
let discovery = discover_root_ca_instance_from_tal_url(http_fetcher, tal_url)?;
let run = run_publication_point_once(
store,
policy,
discovery.ca_instance.rrdp_notification_uri.as_deref(),
&discovery.ca_instance.rsync_base_uri,
&discovery.ca_instance.manifest_rsync_uri,
&discovery.ca_instance.publication_point_rsync_uri,
http_fetcher,
rsync_fetcher,
issuer_resolver,
validation_time,
)?;
Ok(RunFromTalOutput { discovery, run })
}