1
0
mirror of https://github.com/NLnetLabs/routinator.git synced 2024-05-19 06:50:04 +00:00

Consider manifest cert for chain validity and note when points go stale. (#945)

This PR changes the code that calculates the validity of the full validation
chain to also consider the validity of the EE certificates of the
publication points along the chain. It also adds a new field in the jsonext
output format that provides the time when any of the publication points
along the validation chain become stale.
This commit is contained in:
Martin Hoffmann
2024-03-25 17:49:32 +01:00
committed by GitHub
parent 493eef84b5
commit daed4d4d86
7 changed files with 114 additions and 59 deletions

View File

@ -54,8 +54,9 @@ in the :term:`json` and :term:`jsonext` output formats, e.g.:
},
"chainValidity": {
"notBefore": "2023-04-18T14:32:13Z",
"notAfter": "2024-07-01T00:00:00Z"
}
"notAfter": "2023-04-20T00:00:00Z"
},
"stale": "2023-04-20T00:00:00Z"
}]
}],
"routerKeys": [],
@ -73,8 +74,9 @@ in the :term:`json` and :term:`jsonext` output formats, e.g.:
},
"chainValidity": {
"notBefore": "2023-04-18T14:32:13Z",
"notAfter": "2024-04-11T07:26:24Z"
}
"notAfter": "2023-04-20T00:00:00Z"
},
"stale": "2023-04-20T00:00:00Z"
}]
}]
}
@ -125,8 +127,9 @@ in the :term:`SLURM`, :term:`json` and :term:`jsonext` output formats, e.g.:
},
"chainValidity": {
"notBefore": "2021-05-06T12:51:30Z",
"notAfter": "2022-07-01T00:00:00Z"
}
"notAfter": "2021-05-08T00:00:00Z"
},
"stale": "2021-05-08T00:00:00Z"
}]
}],
"routerKeys": [{
@ -142,8 +145,9 @@ in the :term:`SLURM`, :term:`json` and :term:`jsonext` output formats, e.g.:
},
"chainValidity": {
"notBefore": "2022-01-16T14:45:51Z",
"notAfter": "2022-08-06T00:00:00Z"
}
"notAfter": "2021-01-18T00:00:00Z"
},
"stale": "2021-01-18T00:00:00Z"
}]
}],
"aspas": []
@ -205,4 +209,4 @@ Routinator will report the resources used to sign the object:
- `A proof-of-concept for constructing and validating RTAs
<https://github.com/APNIC-net/rpki-rta-demo>`_
.. versionadded:: 0.8.0
.. versionadded:: 0.8.0

View File

@ -542,9 +542,11 @@ These can be requested by providing different commands on the command line.
For RPKI objects, *tal* provides the name of the trust
anchor locator the object was published under, *uri*
provides the rsync URI of the ROA or router certificate,
*validity* provides the validity of the ROA itself, and
*validity* provides the validity of the ROA itself,
*chainValidity* the validity considering the validity of
the certificates along the validation chain.
the certificates along the validation chain, and
*stale* the time when any of the publication points along
the validation chain becomes stale.
For assertions from local exceptions, *path* will provide
the path of the local exceptions file and, optionally,

View File

@ -206,9 +206,10 @@ generated in a wide range of output formats for various use cases.
For RPKI objects, *tal* provides the name of the trust anchor
locator the object was published under, *uri* provides the rsync
URI of the ROA or router certificate, *validity* provides the
validity of the ROA itself, and *chainValidity* the validity
validity of the ROA itself, *chainValidity* the validity
considering the validity of the certificates along the validation
chain.
chain, and *stale* the time when any of the publication points along
the validation chain becomes stale.
For assertions from local exceptions, *path* will provide the path
of the local exceptions file and, optionally, *comment* will
@ -244,8 +245,9 @@ generated in a wide range of output formats for various use cases.
},
"chainValidity": {
"notBefore": "2022-07-25T20:47:37Z",
"notAfter": "2023-02-24T12:31:01Z"
}
"notAfter": "2022-07-26T00:00:00Z"
},
"stale": "2022-07-26T00:00:00Z"
}]
}
],
@ -263,8 +265,9 @@ generated in a wide range of output formats for various use cases.
},
"chainValidity": {
"notBefore": "2022-07-25T20:47:37Z",
"notAfter": "2023-02-24T12:31:01Z"
}
"notAfter": "2022-07-26T00:00:00Z"
},
"stale": "2022-07-26T00:00:00Z"
}]
}],
"aspas": [{
@ -281,8 +284,9 @@ generated in a wide range of output formats for various use cases.
},
"chainValidity": {
"notBefore": "2023-04-18T14:32:13Z",
"notAfter": "2024-04-11T07:26:24Z"
}
"notAfter": "2023-04-20T00:00:00Z"
},
"stale": "2022-07-26T00:00:00Z"
}]
}]
}

View File

@ -18,7 +18,7 @@
/// the accompanying trait [`ProcessPubPoint`] dealing with individual
/// publication points.
use std::{fmt, fs, thread};
use std::{cmp, fmt, fs, thread};
use std::borrow::Cow;
use std::collections::HashMap;
use std::fs::File;
@ -705,7 +705,12 @@ impl<'a, P: ProcessRun> PubPoint<'a, P> {
}
};
// The manifest is fine, so we can now look at the objects. The
// The manifest is fine, so we can continue.
//
// First, report its validity to the processor.
collected.point_validity(&mut self.processor);
// We can look at the objects now. The
// objects are fine if they are present and match the hash. If they
// dont we have to cancel the update. We also validate them while we
// are at it. This also collects all the child CAs that need
@ -713,7 +718,7 @@ impl<'a, P: ProcessRun> PubPoint<'a, P> {
//
// However, the processor can decide it doesnt like the publication
// point at all. This is not an error -- the publication point is
// correct from a store perspective --, but we must not process te
// correct from a store perspective --, but we must not process the
// collected `ca_tasks`. We keep track of this through `point_ok` and,
// if that happens to end up being `false` return an empty list to
// signal that the publication point was processed successfully but
@ -1029,6 +1034,8 @@ impl<'a, P: ProcessRun> PubPoint<'a, P> {
}
};
manifest.point_validity(&mut self.processor);
let mut ca_tasks = Vec::new();
for object in &mut store {
let object = match object {
@ -1332,13 +1339,12 @@ impl<'a, P: ProcessRun> PubPoint<'a, P> {
manifest.metrics.valid_ca_certs += 1;
let mut processor = match self.processor.process_ca(
let processor = match self.processor.process_ca(
uri, &cert
)? {
Some(processor) => processor,
None => return Ok(())
};
processor.update_refresh(cert.cert().validity().not_after());
// Defer operation if we need to update the repository part where
// the CA lives.
@ -1543,6 +1549,17 @@ impl ValidPointManifest {
Ok(())
}
/// Reports the validity to the given processor.
fn point_validity(&self, processor: &mut impl ProcessPubPoint) {
processor.point_validity(
self.ee_cert.validity(),
cmp::min(
self.content.next_update(),
self.crl.next_update(),
)
)
}
}
@ -1610,6 +1627,9 @@ struct CaTask<P> {
//------------ CaCert --------------------------------------------------------
/// A CA certificate plus references to all its parents.
///
/// Note that this does not represent the full publication point, only the
/// certificate itself.
#[derive(Clone, Debug)]
pub struct CaCert {
/// The CA certificate of this CA.
@ -1640,12 +1660,6 @@ pub struct CaCert {
/// The index of the TAL in the metrics.
pub(crate) // XXX
tal: usize,
/// The combined validity of the certificate.
///
/// This is derived from the validity of all the parents and the
/// certificate itself.
combined_validity: Validity,
}
impl CaCert {
@ -1695,10 +1709,6 @@ impl CaCert {
chain_len: usize,
tal: usize,
) -> Result<Arc<Self>, Failed> {
let combined_validity = match parent.as_ref() {
Some(ca) => cert.validity().trim(ca.combined_validity()),
None => cert.validity()
};
let ca_repository = match cert.ca_repository() {
Some(uri) => uri.clone(),
None => {
@ -1727,8 +1737,7 @@ impl CaCert {
}
};
Ok(Arc::new(CaCert {
cert, uri, ca_repository, rpki_manifest, parent, chain_len, tal,
combined_validity,
cert, uri, ca_repository, rpki_manifest, parent, chain_len, tal
}))
}
@ -1783,11 +1792,6 @@ impl CaCert {
self.cert.rpki_notify()
}
/// Returns the combined validaty of the whole CA.
pub fn combined_validity(&self) -> Validity {
self.combined_validity
}
/// Returns whether the CA is in a different repository from its parent.
///
/// This is just a quick check and may report a switch when in fact there
@ -1947,9 +1951,17 @@ pub trait ProcessPubPoint: Sized + Send + Sync {
let _ = repository_index;
}
/// Updates the refresh time for this publication poont.
fn update_refresh(&mut self, not_after: Time) {
let _ = not_after;
/// Process the publication pointss validity.
///
/// The validity of the manifests EE certificate is provided in
/// `manifest_ee`. The smaller of the manifests and CRLs next update
/// time is given in `stale`.
fn point_validity(
&mut self,
manifest_ee: Validity,
stale: Time,
) {
let _ = (manifest_ee, stale);
}
/// Determines whether an object with the given URI should be processed.

View File

@ -1020,13 +1020,15 @@ impl ExtendedJson {
\"validity\": {{ \"notBefore\": \"{}\", \
\"notAfter\": \"{}\" }}, \
\"chainValidity\": {{ \"notBefore\": \"{}\", \
\"notAfter\": \"{}\" }} \
\"notAfter\": \"{}\" }}, \
\"stale\": \"{}\" \
}}",
json_str(roa.tal.name()),
format_iso_date(roa.roa_validity.not_before().into()),
format_iso_date(roa.roa_validity.not_after().into()),
format_iso_date(roa.chain_validity.not_before().into()),
format_iso_date(roa.chain_validity.not_after().into()),
format_iso_date(roa.point_stale.into()),
)?;
}
if let Some(exc) = item.exception_info() {

View File

@ -6,8 +6,7 @@ use std::sync::Arc;
use rpki::uri;
use rpki::repository::cert::{Cert, ResourceCert};
use rpki::repository::tal::TalInfo;
use rpki::repository::x509::Validity;
use crate::engine::CaCert;
use rpki::repository::x509::{Validity, Time};
use crate::slurm::ExceptionInfo;
//------------ PayloadInfo ---------------------------------------------------
@ -144,11 +143,18 @@ pub struct PublishInfo {
/// The validity of the validation chain.
pub chain_validity: Validity,
/// When will the objects publication point become stale?
pub point_stale: Time,
}
impl PublishInfo {
/// Creates a new origin info from the EE certificate of a ROA.
pub fn signed_object(cert: &ResourceCert, ca_validity: Validity) -> Self {
pub fn signed_object(
cert: &ResourceCert,
ca_validity: Validity,
point_stale: Time,
) -> Self {
PublishInfo {
tal: cert.tal().clone(),
uri: cert.signed_object().cloned().map(|mut uri| {
@ -156,17 +162,23 @@ impl PublishInfo {
}),
roa_validity: cert.validity(),
chain_validity: cert.validity().trim(ca_validity),
point_stale,
}
}
pub fn router_cert(
cert: &Cert, uri: &uri::Rsync, ca_cert: &CaCert
cert: &Cert,
uri: &uri::Rsync,
tal: Arc<TalInfo>,
ca_validity: Validity,
point_stale: Time,
) -> Self {
PublishInfo {
tal: ca_cert.cert().tal().clone(),
tal,
uri: Some(uri.clone()),
roa_validity: cert.validity(),
chain_validity: cert.validity().trim(ca_cert.combined_validity())
chain_validity: cert.validity().trim(ca_validity),
point_stale,
}
}

View File

@ -133,7 +133,8 @@ impl<'a> ProcessRun for &'a ValidationReport {
PubPointProcessor {
report: self,
pub_point: PubPoint::new_ta(cert, tal_index),
validity: cert.combined_validity(),
validity: cert.cert().validity(),
point_stale: cert.cert().validity().not_after(),
}
))
}
@ -155,8 +156,11 @@ pub struct PubPointProcessor<'a> {
/// The data being collected.
pub_point: PubPoint,
/// The (combined) validity of the CA certificate.
/// The (combined) validity of the publication point.
validity: Validity,
/// When will this publication point become stale.
point_stale: Time,
}
impl<'a> ProcessPubPoint for PubPointProcessor<'a> {
@ -164,10 +168,13 @@ impl<'a> ProcessPubPoint for PubPointProcessor<'a> {
self.pub_point.repository_index = Some(repository_index)
}
fn update_refresh(&mut self, not_after: Time) {
fn point_validity(&mut self, manifest: Validity, stale: Time) {
self.pub_point.refresh = cmp::min(
self.pub_point.refresh, not_after
self.pub_point.refresh,
cmp::min(manifest.not_after(), stale)
);
self.validity = self.validity.trim(manifest);
self.point_stale = cmp::min(self.point_stale, stale);
}
fn want(&self, _uri: &uri::Rsync) -> Result<bool, Failed> {
@ -183,7 +190,10 @@ impl<'a> ProcessPubPoint for PubPointProcessor<'a> {
PubPointProcessor {
report: self.report,
pub_point: PubPoint::new_ca(&self.pub_point, cert),
validity: cert.combined_validity(),
validity: self.validity.trim(cert.cert().validity()),
point_stale: cmp::min(
self.point_stale, cert.cert().validity().not_after()
),
}
))
}
@ -233,7 +243,10 @@ impl<'a> ProcessPubPoint for PubPointProcessor<'a> {
self.pub_point.update_refresh(cert.validity().not_after());
self.pub_point.add_router_key(
asns, id, key,
Arc::new(PublishInfo::router_cert(&cert, uri, ca_cert)),
Arc::new(PublishInfo::router_cert(
&cert, uri, ca_cert.cert().tal().clone(),
self.validity, self.point_stale,
)),
);
Ok(())
}
@ -245,7 +258,10 @@ impl<'a> ProcessPubPoint for PubPointProcessor<'a> {
route: RouteOriginAttestation
) -> Result<(), Failed> {
if self.pub_point.add_roa(
route, Arc::new(PublishInfo::signed_object(&cert, self.validity)),
route,
Arc::new(PublishInfo::signed_object(
&cert, self.validity, self.point_stale
)),
self.report.limit_v4_len, self.report.limit_v6_len,
) {
self.pub_point.update_refresh(cert.validity().not_after());
@ -264,7 +280,10 @@ impl<'a> ProcessPubPoint for PubPointProcessor<'a> {
}
self.pub_point.update_refresh(cert.validity().not_after());
self.pub_point.add_aspa(
aspa, Arc::new(PublishInfo::signed_object(&cert, self.validity))
aspa,
Arc::new(PublishInfo::signed_object(
&cert, self.validity, self.point_stale
))
);
Ok(())
}