Skip to main content

structured_xades/
reference.rs

1//! Authenticated reference resolution shared by signed property mechanisms.
2
3use crate::binding::{Reference, SignatureXml};
4use crate::xml::{Name, Snapshot};
5use structured_asn1::memory::Work;
6use structured_cms::stream::Receiver;
7
8/// Exact authenticated parent of an original reference instruction.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum Parent<N> {
11    /// Direct child of the selected signature's original `SignedInfo`.
12    SignedInfo(N),
13    /// Child of a Manifest authenticated by this selected signature.
14    Manifest(N),
15}
16
17/// Final conversion after the original reference transform chain. Explicit
18/// final canonicalization already in that chain keeps its actual method;
19/// octet output is never canonicalized a second time.
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum Replay<N> {
22    /// Ordinary `XMLDSig` reference output before hashing, including its implicit
23    /// C14N1.0 conversion of a remaining node-set. EN319132-1 ยง5.5.3 uses this
24    /// output for `NewSDODigestValue`.
25    ReferenceOutput,
26    /// Convert a remaining node-set with this original timestamp method and
27    /// parameters, as required for timestamp/archive imprint input.
28    Timestamp(N),
29}
30
31/// Origin of the resource actually observed by the original operation. It is
32/// never inferred from a URI string or absence of an element target identity.
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum ObjectLocation {
35    /// Original document node, including a whole-document reference.
36    SameDocument,
37    /// Original resolver selected/admitted the external resource route. This
38    /// includes typed Missing explicit bytes as well as Present bytes with
39    /// original resource identity; URI spelling or target=None cannot prove it.
40    Detached,
41    /// Generated, unprocessed or otherwise unclassified resource.
42    Unknown,
43}
44
45/// Complete replay is distinct from missing explicit detached source bytes.
46/// Only the owner's original resource lookup may produce Unavailable; stale
47/// identities, malformed URI/transform, policy and resource refusals remain Err.
48#[derive(Debug)]
49pub enum ReplayOutcome<E> {
50    /// Every required byte was delivered successfully through complete EOF.
51    Complete,
52    /// Detached bytes are absent from the original immutable explicit request.
53    /// No implicit reacquisition, re-verification or default resource is allowed.
54    Unavailable(E),
55}
56
57/// Callback-local instruction metadata; target validation remains independent.
58#[derive(Debug, Clone, Copy)]
59pub struct Descriptor<'a, N> {
60    /// Original reference and its actual target digest/coverage results.
61    pub reference: Reference<'a, N>,
62    /// Original authenticated instruction container.
63    pub parent: Parent<N>,
64    /// Original observed source kind, separately from digest/parent validity.
65    pub object_location: ObjectLocation,
66}
67
68/// Original XML location supplying a reference URI to the same owner resolver.
69/// The property node always supplies XML Base and source provenance; callers
70/// never replace this location with a separately collected or normalized URI.
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub enum LexicalSource<'a> {
73    /// Original attribute selected by its expanded XML name.
74    Attribute(Name<'a>),
75    /// Direct simple content: text/CDATA in order, excluding comments/PI.
76    /// Element children are malformed, not recursively flattened string values.
77    /// Empty text remains present and follows the URI rules, never Missing.
78    SimpleContent,
79}
80
81/// URI lookup outcome without confusing processing refusal with absence.
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83pub enum Resolution<R> {
84    /// An authenticated original reference was passed to the scoped visitor.
85    Resolved(R),
86    /// Original attribute is absent.
87    Missing,
88    /// URI does not resolve to a reference in the supplied source context.
89    Unresolved,
90    /// Reference is foreign or its instruction is not authenticated.
91    Unauthenticated,
92    /// The XML owner's configured mechanism cannot process this URI form.
93    Unsupported,
94}
95
96impl<R> Resolution<R> {
97    /// Maps only a successfully resolved value, preserving every lookup class.
98    pub fn map<T>(self, visitor: impl FnOnce(R) -> T) -> Resolution<T> {
99        match self {
100            Self::Resolved(value) => Resolution::Resolved(visitor(value)),
101            Self::Missing => Resolution::Missing,
102            Self::Unresolved => Resolution::Unresolved,
103            Self::Unauthenticated => Resolution::Unauthenticated,
104            Self::Unsupported => Resolution::Unsupported,
105        }
106    }
107}
108
109/// Original optional XML Schema boolean, validated by the XML lexical owner.
110#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111pub enum Boolean {
112    /// Attribute was not written; this is distinct from explicit false.
113    Absent,
114    /// Valid lexical boolean after XML Schema whitespace handling.
115    Value(bool),
116    /// Present text has no XML Schema boolean value.
117    Malformed,
118}
119
120/// Whether all relevant original reference instructions were processed.
121#[derive(Debug, Clone, Copy, PartialEq, Eq)]
122pub enum Completeness<N> {
123    /// All selected direct and authenticated Manifest instructions were visited.
124    /// Target digest outcomes/availability remain separate: Complete may include
125    /// an authenticated instruction whose explicit detached bytes are missing.
126    Complete,
127    /// Original request did not complete required instruction discovery/auth
128    /// traversal. This is not a missing-byte result for a discovered target.
129    Unchecked(N),
130    /// Processing stopped before a complete catalogue could be established.
131    Incomplete(N),
132}
133
134/// Traversal preserves XML processing and consumer callback causes separately.
135#[derive(Debug)]
136pub enum VisitError<E, VE> {
137    /// Original XML policy/resource/source-processing refusal.
138    Processing(E),
139    /// Exact visitor refusal; no later descriptor is visited.
140    Visitor(VE),
141}
142
143/// XML-owned URI resolution and streaming from one selected verification session.
144///
145/// The owner retains the original request, compiled policy and remaining budgets.
146/// No operation here performs a second signature verification, changes the
147/// document, resets admission, or acquires an implicit resource. Processing and
148/// resource refusals are returned as errors, never as a semantic lookup outcome.
149pub trait ReferenceXml: SignatureXml {
150    /// Visits the paid original authenticated instruction catalogue once.
151    /// Direct and signed-Manifest references retain exact parent identities.
152    /// Detached result arrays, fail-fast partial lists and an empty unprocessed
153    /// Manifest list must never be relabelled Complete. No implicit verification
154    /// or policy change is performed to complete the catalogue. The visitor's
155    /// short descriptor borrow cannot escape; its refusal terminates traversal.
156    fn visit_authenticated_references<VE, W: Work>(
157        &self,
158        snapshot: Snapshot<Self::Document, Self::Generation>,
159        signature: Self::Id,
160        execution: &W,
161        visitor: impl for<'view> FnMut(Descriptor<'view, Self::Id>) -> Result<(), VE>,
162    ) -> Result<Completeness<Self::Id>, VisitError<Self::Error, VE>>;
163
164    /// Resolves original lexical data on the property in its XML context.
165    /// Only selected `SignedInfo` or authenticated Manifest instructions may reach
166    /// the visitor. Its borrowed Type and view cannot escape the callback.
167    /// Multiple simple-content fragments may require fallible current-operation
168    /// scratch for the existing URI kernel; it cannot reset the operation or
169    /// return a reader into temporary storage. Malformed simple content retains
170    /// the owner's typed source cause instead of becoming absent or unresolved.
171    fn resolve_reference<R, W: Work>(
172        &self,
173        snapshot: Snapshot<Self::Document, Self::Generation>,
174        signature: Self::Id,
175        property: Self::Id,
176        source: LexicalSource<'_>,
177        execution: &W,
178        visitor: impl for<'view> FnOnce(Descriptor<'view, Self::Id>) -> R,
179    ) -> Result<Resolution<R>, Self::Error>;
180
181    /// Reads an unqualified attribute through the existing XML Schema boolean
182    /// kernel. Presence and malformed text must not be defaulted to false.
183    fn boolean_attribute<W: Work>(
184        &self,
185        snapshot: Snapshot<Self::Document, Self::Generation>,
186        node: Self::Id,
187        attribute: Name<'_>,
188        execution: &W,
189    ) -> Result<Boolean, Self::Error>;
190
191    /// Replays the original reference through the one transform/C14N kernel.
192    /// The owner checks selected membership, generation and method before sink
193    /// work. Final octets stay unchanged; remaining node-sets use the explicit
194    /// replay mode. Receiver refusal is sticky and terminal.
195    /// Direct ordinal queries and Manifest resolution feed this same kernel;
196    /// retained implicit C14N 1.0 bytes are not universally equivalent output.
197    fn replay_reference<W: Work>(
198        &self,
199        snapshot: Snapshot<Self::Document, Self::Generation>,
200        signature: Self::Id,
201        reference: Self::Id,
202        mode: Replay<Self::Id>,
203        receiver: &mut impl Receiver,
204        execution: &W,
205    ) -> Result<ReplayOutcome<Self::Error>, Self::Error>;
206}