1use structured_asn1::memory::{MemoryError, OwnedVec, Work};
7use structured_xades::{
8 attributes::{self, AttributeXml},
9 reference::VisitError,
10 xml::{Access, AccessError, Name, Node, Snapshot, Xml},
11};
12
13pub mod producer;
14
15pub const ODF: &str = "urn:oasis:names:tc:opendocument:xmlns:digitalsignature:1.0";
17pub const OCF: &str = "urn:oasis:names:tc:opendocument:xmlns:container";
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum Wrapper {
23 Bare,
25 Asic,
27 Odf,
29 Ocf,
31 Other,
33 NotElement,
35}
36
37#[derive(Debug, Clone, Copy)]
39pub struct Signature<N> {
40 pub node: N,
42 pub parent: Option<N>,
44 pub enclosing: Option<N>,
46 pub direct: bool,
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52pub enum FaultKind {
53 Root,
55 Missing,
57 Child,
59 Text,
61 Attribute,
63 InstanceUnassessed,
65 OdfVersion,
67 Misplaced,
69}
70
71#[derive(Debug, Clone, Copy)]
73pub struct Fault<N> {
74 pub node: N,
76 pub kind: FaultKind,
78}
79
80#[derive(Debug)]
82pub enum Error<E, N> {
83 Access(AccessError<E, N>),
85 Attributes(AccessError<VisitError<E, MemoryError>, N>),
87 Resource {
89 node: N,
91 cause: MemoryError,
93 },
94}
95
96pub struct Reading<N, D, G> {
98 snapshot: Snapshot<D, G>,
99 root: N,
100 wrapper: Wrapper,
101 signatures: OwnedVec<Signature<N>>,
102 faults: OwnedVec<Fault<N>>,
103}
104impl<N: Copy, D: Copy, G: Copy> Reading<N, D, G> {
105 #[must_use]
107 pub fn snapshot(&self) -> Snapshot<D, G> {
108 self.snapshot
109 }
110 #[must_use]
112 pub fn root(&self) -> N {
113 self.root
114 }
115 #[must_use]
117 pub fn wrapper(&self) -> Wrapper {
118 self.wrapper
119 }
120 #[must_use]
122 pub fn signatures(&self) -> &[Signature<N>] {
123 &self.signatures
124 }
125 #[must_use]
127 pub fn faults(&self) -> &[Fault<N>] {
128 &self.faults
129 }
130}
131
132struct Frame<N> {
133 parent: N,
134 next: Option<N>,
135 enclosing: Option<N>,
136}
137enum Kind {
138 Element { signature: bool, wrapper: Wrapper },
139 Text,
140 Other,
141}
142
143fn classify<X: Xml, W: Work>(
144 access: &Access<'_, X, W>,
145 node: X::Id,
146) -> Result<Kind, Error<X::Error, X::Id>> {
147 access
148 .inspect(node, |value| match value {
149 Node::Element(name) => {
150 let cost = name
151 .namespace
152 .len()
153 .checked_add(name.local.len())
154 .and_then(|count| count.checked_mul(4))
155 .ok_or(MemoryError::WorkExceeded)?;
156 access.execution().charge_work(cost as u64)?;
157 let signature = name.namespace == crate::manifest::DS && name.local == "Signature";
158 let wrapper = if signature {
159 Wrapper::Bare
160 } else if name.namespace == crate::manifest::NAMESPACE
161 && name.local == "XAdESSignatures"
162 {
163 Wrapper::Asic
164 } else if name.namespace == ODF && name.local == "document-signatures" {
165 Wrapper::Odf
166 } else if name.namespace == OCF && name.local == "signatures" {
167 Wrapper::Ocf
168 } else {
169 Wrapper::Other
170 };
171 Ok(Kind::Element { signature, wrapper })
172 }
173 Node::Text(text) => {
174 access.execution().charge_work(text.len() as u64)?;
175 for byte in text.bytes() {
176 if !matches!(byte, b' ' | b'\r' | b'\n' | b'\t') {
177 return Ok(Kind::Text);
178 }
179 }
180 Ok(Kind::Other)
181 }
182 Node::Other => Ok(Kind::Other),
183 })
184 .map_err(Error::Access)?
185 .map_err(|cause| Error::Resource { node, cause })
186}
187
188fn fault<N, W: Work, E>(
189 output: &mut OwnedVec<Fault<N>, W>,
190 node: N,
191 kind: FaultKind,
192) -> Result<(), Error<E, N>>
193where
194 N: Copy,
195{
196 output
197 .try_push(Fault { node, kind })
198 .map_err(|cause| Error::Resource { node, cause })
199}
200
201pub fn inspect<X: AttributeXml, W: Work>(xml: &X, root: X::Id, work: &W) -> InspectionResult<X> {
207 let snapshot = xml.snapshot();
208 let access = Access::new(xml, snapshot, work);
209 let mut signatures = work.vector();
210 let mut faults = work.vector();
211 let root_kind = classify(&access, root)?;
212 let wrapper = match root_kind {
213 Kind::Element { signature, wrapper } => {
214 if signature {
215 signatures
216 .try_push(Signature {
217 node: root,
218 parent: None,
219 enclosing: None,
220 direct: true,
221 })
222 .map_err(|cause| Error::Resource { node: root, cause })?;
223 }
224 wrapper
225 }
226 Kind::Text | Kind::Other => {
227 fault(&mut faults, root, FaultKind::Root)?;
228 Wrapper::NotElement
229 }
230 };
231 inspect_wrapper(&access, root, wrapper, &mut faults)?;
232 inspect_descendants(&access, root, wrapper, &mut signatures, &mut faults)?;
233 access.inspect(root, |_| ()).map_err(Error::Access)?;
234 Ok(Reading {
235 snapshot,
236 root,
237 wrapper,
238 signatures: signatures.into_owned(),
239 faults: faults.into_owned(),
240 })
241}
242
243pub type InspectionResult<X> = Result<
245 Reading<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>,
246 Error<<X as Xml>::Error, <X as Xml>::Id>,
247>;
248
249fn inspect_wrapper<X: AttributeXml, W: Work, O: Work>(
250 access: &Access<'_, X, W>,
251 root: X::Id,
252 wrapper: Wrapper,
253 faults: &mut OwnedVec<Fault<X::Id>, O>,
254) -> Result<(), Error<X::Error, X::Id>> {
255 let work = access.execution();
256 if matches!(wrapper, Wrapper::Asic | Wrapper::Odf | Wrapper::Ocf) {
257 attributes::visit(access, root, |name| {
258 work.charge_work(name.namespace.len() as u64 + name.local.len() as u64 + 1)?;
259 if wrapper == Wrapper::Odf && name.namespace == ODF && name.local == "version" {
260 return Ok(());
261 }
262 let kind = if name.namespace == "http://www.w3.org/2001/XMLSchema-instance" {
263 FaultKind::InstanceUnassessed
264 } else {
265 FaultKind::Attribute
266 };
267 faults.try_push(Fault { node: root, kind })
268 })
269 .map_err(Error::Attributes)?;
270 }
271 if wrapper == Wrapper::Odf {
272 let valid = access
276 .attribute(
277 root,
278 Name {
279 namespace: ODF,
280 local: "version",
281 },
282 |value| {
283 let Some(value) = value else {
284 return Ok(false);
285 };
286 work.charge_work(value.len() as u64)?;
287 Ok(value.trim_matches([' ', '\t', '\r', '\n']) == "1.2")
288 },
289 )
290 .map_err(Error::Access)?
291 .map_err(|cause| Error::Resource { node: root, cause })?;
292 if !valid {
293 fault(faults, root, FaultKind::OdfVersion)?;
294 }
295 }
296 Ok(())
297}
298
299fn inspect_descendants<X: AttributeXml, W: Work, O: Work>(
300 access: &Access<'_, X, W>,
301 root: X::Id,
302 wrapper: Wrapper,
303 signatures: &mut OwnedVec<Signature<X::Id>, O>,
304 faults: &mut OwnedVec<Fault<X::Id>, O>,
305) -> Result<(), Error<X::Error, X::Id>> {
306 let work = access.execution();
307 let mut stack = work.vector();
308 if wrapper != Wrapper::NotElement {
309 let next = access.first_child(root).map_err(Error::Access)?;
310 stack
311 .try_push(Frame {
312 parent: root,
313 next,
314 enclosing: if wrapper == Wrapper::Bare {
315 Some(root)
316 } else {
317 None
318 },
319 })
320 .map_err(|cause| Error::Resource { node: root, cause })?;
321 }
322 let mut direct = usize::from(wrapper == Wrapper::Bare);
323 while let Some(frame) = stack.last_mut() {
324 let Some(node) = frame.next else {
325 stack.pop();
326 continue;
327 };
328 let parent = frame.parent;
329 let outer = frame.enclosing;
330 frame.next = access.next_sibling(parent, node).map_err(Error::Access)?;
331 let kind = classify(access, node)?;
332 let is_direct = parent == root && wrapper != Wrapper::Bare;
333 let (is_element, enclosing) = match kind {
334 Kind::Element { signature, .. } => {
335 if signature {
336 signatures
337 .try_push(Signature {
338 node,
339 parent: Some(parent),
340 enclosing: outer,
341 direct: is_direct,
342 })
343 .map_err(|cause| Error::Resource { node, cause })?;
344 if is_direct {
345 direct += 1;
346 } else if outer.is_none() {
347 fault(faults, node, FaultKind::Misplaced)?;
348 }
349 } else if is_direct {
350 fault(faults, node, FaultKind::Child)?;
351 }
352 (true, if signature { Some(node) } else { outer })
353 }
354 Kind::Text => {
355 if is_direct {
356 fault(faults, node, FaultKind::Text)?;
357 }
358 (false, outer)
359 }
360 Kind::Other => (false, outer),
361 };
362 if is_element {
363 let next = access.first_child(node).map_err(Error::Access)?;
364 stack
365 .try_push(Frame {
366 parent: node,
367 next,
368 enclosing,
369 })
370 .map_err(|cause| Error::Resource { node, cause })?;
371 }
372 }
373 if direct == 0 {
374 fault(faults, root, FaultKind::Missing)?;
375 }
376 Ok(())
377}