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}