Skip to main content

structured_xades/validation/
ref_crl.rs

1//! Original CRL identifier facts over the shared name/time kernels.
2
3use super::{
4    ReferenceIdentifier, ReferenceNameError, ReferenceProperty, ReferenceTime, ReferenceTimeError,
5    matches_reference_name, matches_reference_time,
6};
7use crate::{
8    binary::{self, Location},
9    properties::CalendarXml,
10    scalar::TextXml,
11    xml::{Access, AccessError, Xml},
12};
13use structured_asn1::ScopedReader;
14use structured_pkix::crl::CertificateList;
15
16/// Completed mandatory fields. Optional original Number is only an acquisition
17/// hint; it is never narrowed to u64 or used as a digest identity.
18pub struct CrlReferenceIdentity<N> {
19    issuer: bool,
20    issued_at: ReferenceTime,
21    number_hint: Option<N>,
22}
23
24impl<N: Copy> CrlReferenceIdentity<N> {
25    /// Shared issuer equality, not CRL signature authentication.
26    #[must_use]
27    pub fn issuer_matches(&self) -> bool {
28        self.issuer
29    }
30    /// Full issue-time fact without defaulting an absent timezone to UTC.
31    #[must_use]
32    pub fn issued_at(&self) -> ReferenceTime {
33        self.issued_at
34    }
35    /// Original optional Number element; its integer lexical check belongs to
36    /// field preflight and remains independent of artifact agreement.
37    #[must_use]
38    pub fn number_hint(&self) -> Option<N> {
39        self.number_hint
40    }
41}
42
43/// Terminal causes never become missing identity or completed disagreement.
44#[derive(Debug)]
45pub enum CrlReferenceError<E, N> {
46    /// Original source/generation/current-operation refusal.
47    Access(AccessError<E, N>),
48    /// No original reference exists at this ordinal.
49    Index {
50        /// Requested ordinal, not an XML byte offset.
51        index: usize,
52    },
53    /// Original name syntax/source/shared comparison refusal.
54    Name(ReferenceNameError<E, N>),
55    /// Original time-source/current comparison refusal.
56    Time(ReferenceTimeError<E, N>),
57}
58
59/// Original XML enclosure and both fields, or the exact terminal cause.
60pub type CrlReferenceResult<X> = Result<
61    Option<binary::LocatedValue<CrlReferenceIdentity<<X as Xml>::Id>, X>>,
62    CrlReferenceError<<X as Xml>::Error, <X as Xml>::Id>,
63>;
64
65/// Compare every mandatory field of a written `CRLIdentifier` with the actual
66/// list through original name/XSD1.0 time semantics under the current query.
67/// EN319132-1 Annex A.1.2 requires issuer and issue time; Note3 expressly makes
68/// Number an optional retrieval hint. It cannot replace the whole-list digest
69/// or impose a finite-width requirement. None means no written CRL identifier,
70/// including another reference kind, never successful agreement.
71/// Signature/issuer authorization, complete/delta applicability, freshness,
72/// actual use and incorporation remain independent. No CRL parse is repeated.
73/// <https://www.etsi.org/deliver/etsi_en/319100_319199/31913201/01.03.01_60/en_31913201v010301p.pdf>
74///
75/// # Panics
76/// Only if an immutable privately constructed reference changes its selector
77/// kind between original field selection and the same field kernel.
78pub fn check_crl_reference<X: TextXml + CalendarXml>(
79    xml: &X,
80    references: &ReferenceProperty<X::Id, X::Document, X::Generation>,
81    index: usize,
82    actual: &CertificateList<'_>,
83    operation: &ScopedReader<'_, '_>,
84) -> CrlReferenceResult<X> {
85    let work = operation.execution();
86    let access = Access::new(xml, references.snapshot(), &work);
87    access
88        .query(references.node(), |_, _, _| Ok(()))
89        .map_err(CrlReferenceError::Access)?;
90    let Some(entry) = references.entries().get(index) else {
91        return Err(CrlReferenceError::Index { index });
92    };
93    let ReferenceIdentifier::Crl { node, number, .. } = entry.identifier() else {
94        return Ok(None);
95    };
96    let issuer = matches_reference_name(xml, references, index, actual.tbs().issuer(), operation)
97        .map_err(CrlReferenceError::Name)?
98        .expect("original CRL issuer entry");
99    let issued_at = matches_reference_time(
100        xml,
101        references,
102        index,
103        actual.tbs().this_update(),
104        operation,
105    )
106    .map_err(CrlReferenceError::Time)?
107    .expect("original CRL time entry");
108    access
109        .query(node, |_, _, _| Ok(()))
110        .map_err(CrlReferenceError::Access)?;
111    Ok(Some(binary::Located {
112        location: Location {
113            snapshot: references.snapshot(),
114            node,
115        },
116        value: CrlReferenceIdentity {
117            issuer,
118            issued_at,
119            number_hint: number,
120        },
121    }))
122}