Skip to main content

structured_xades/validation/
ref_name.rs

1//! Original RFC4514 issuer/responder names against actual retained PKIX names.
2
3use super::{ReferenceIdentifier, ReferenceProperty, ResponderIdentifier};
4use crate::{
5    reference::{LexicalSource, VisitError},
6    scalar::{TextValue, TextXml},
7    xml::{Access, AccessError},
8};
9use structured_asn1::ScopedReader;
10use structured_pkix::name::{Name, Selector};
11
12/// A failed name interpretation is never a completed negative comparison.
13#[derive(Debug)]
14pub enum ReferenceNameError<E, N> {
15    /// Current original-source/access admission failed.
16    Access(AccessError<E, N>),
17    /// Original XML text could not be acquired, preserving resource cause.
18    Xml(E),
19    /// Caller selected no reference at this catalogue ordinal.
20    Index {
21        /// Requested ordinal, not an XML byte location.
22        index: usize,
23    },
24    /// The original required name has no readable simple content.
25    Content {
26        /// Original issuer or `ByName` element.
27        node: N,
28    },
29    /// Shared RFC4514/Name syntax, semantic preparation or resource failure.
30    Name {
31        /// Original XML name enclosure. Inner offsets refer to DN text, NOT
32        /// physical XML bytes; no copied-buffer offset is fabricated.
33        node: N,
34        /// Exact original shared cause.
35        cause: structured_pkix::Error,
36    },
37}
38
39/// Compare an original CRL issuer or OCSP `ByName` hint with an actual PKIX Name.
40/// Annex A.1.2 refers to `XMLDSig` ยง4.5.4.1 DN strings; RFC4514 parsing and
41/// RFC5280 name preparation remain with the existing PKIX owner.
42/// <https://www.etsi.org/deliver/etsi_en/319100_319199/31913201/01.03.01_60/en_31913201v010301p.pdf>
43///
44/// None denotes a different identifier branch, never successful agreement.
45/// Query decoding, normalization and comparison use the current reader even
46/// for independently retained material. Source storage remains on its account.
47/// This does not establish digest agreement, authority, freshness or path use.
48pub fn matches_reference_name<X: TextXml>(
49    xml: &X,
50    references: &ReferenceProperty<X::Id, X::Document, X::Generation>,
51    index: usize,
52    actual: &Name<'_>,
53    operation: &ScopedReader<'_, '_>,
54) -> Result<Option<bool>, ReferenceNameError<X::Error, X::Id>> {
55    let work = operation.execution();
56    let access = Access::new(xml, references.snapshot(), &work);
57    access
58        .query(references.node(), |_, _, _| Ok(()))
59        .map_err(ReferenceNameError::Access)?;
60    let Some(entry) = references.entries().get(index) else {
61        return Err(ReferenceNameError::Index { index });
62    };
63    let node = match entry.identifier() {
64        ReferenceIdentifier::Crl { issuer, .. } => issuer,
65        ReferenceIdentifier::Ocsp {
66            responder: ResponderIdentifier::Name(node),
67            ..
68        } => node,
69        _ => return Ok(None),
70    };
71    let compared = access
72        .query(node, |xml, snapshot, work| {
73            Ok(xml.with_text(
74                snapshot,
75                node,
76                LexicalSource::SimpleContent,
77                work,
78                |value| {
79                    let TextValue::Present(text) = value else {
80                        return Err(ReferenceNameError::Content { node });
81                    };
82                    let selector = Selector::parse_in(text, operation)
83                        .map_err(|cause| ReferenceNameError::Name { node, cause })?;
84                    selector
85                        .matches_name_in(actual, operation)
86                        .map(Some)
87                        .map_err(|cause| ReferenceNameError::Name { node, cause })
88                },
89            ))
90        })
91        .map_err(ReferenceNameError::Access)?;
92    compared.map_err(|cause| match cause {
93        VisitError::Processing(cause) => ReferenceNameError::Xml(cause),
94        VisitError::Visitor(cause) => cause,
95    })
96}