structured_xades/validation/
ref_fields.rs1use super::{ReferenceField, ReferenceProperty};
4use crate::{
5 binary::{BinaryXml, Location},
6 certificate::{self, Agreement},
7 properties::{DateTimeFact, DateTimeXml},
8 reference::LexicalSource,
9 scalar::{self, Datatype, ScalarXml},
10 xml::{Access, AccessError, Name, Xml},
11};
12use core::convert::Infallible;
13use structured_asn1::memory::{MemoryError, Work};
14
15#[derive(Debug)]
18pub enum ReferenceFieldError<E, N, D, G> {
19 Foreign {
21 node: N,
23 },
24 Access(AccessError<E, N>),
26 Scalar(scalar::Error<E, N>),
28 Time {
30 node: N,
32 fact: DateTimeFact,
34 },
35 Binary {
37 location: Location<N, D, G>,
39 cause: AccessError<E, N>,
41 },
42 Method {
44 node: N,
46 cause: Agreement,
48 },
49 Resource {
51 node: N,
53 cause: MemoryError,
55 },
56}
57
58pub type ReferenceFieldResult<X> = Result<
60 (),
61 ReferenceFieldError<
62 <X as Xml>::Error,
63 <X as Xml>::Id,
64 <X as Xml>::Document,
65 <X as Xml>::Generation,
66 >,
67>;
68
69pub fn check_reference_fields<X: ScalarXml + DateTimeXml + BinaryXml, W: Work>(
75 references: &ReferenceProperty<X::Id, X::Document, X::Generation>,
76 access: &Access<'_, X, W>,
77) -> ReferenceFieldResult<X> {
78 let node = references.node();
79 if references.snapshot() != access.snapshot() {
80 return Err(ReferenceFieldError::Foreign { node });
81 }
82 access
83 .query(node, |_, _, _| Ok(()))
84 .map_err(ReferenceFieldError::Access)?;
85 let mut ordinal = 0;
86 while ordinal < references.entries().len() {
87 access
88 .execution()
89 .charge_work(1)
90 .map_err(|cause| ReferenceFieldError::Resource { node, cause })?;
91 let entry = &references.entries()[ordinal];
92 if let Some((method, _)) = entry.digest()
93 && let Some(cause) = certificate::preflight_method(access, method)
94 .map_err(ReferenceFieldError::Access)?
95 {
96 return Err(ReferenceFieldError::Method {
97 node: method,
98 cause,
99 });
100 }
101 let fields = entry.fields();
102 for field in fields {
103 access
104 .execution()
105 .charge_work(1)
106 .map_err(|cause| ReferenceFieldError::Resource { node, cause })?;
107 if let Some(field) = field {
108 check_field(access, field)?;
109 }
110 }
111 ordinal += 1;
112 }
113 access
114 .query(node, |_, _, _| Ok(()))
115 .map_err(ReferenceFieldError::Access)
116}
117
118fn check_field<X: ScalarXml + DateTimeXml + BinaryXml, W: Work>(
119 access: &Access<'_, X, W>,
120 field: ReferenceField<X::Id>,
121) -> ReferenceFieldResult<X> {
122 match field {
123 ReferenceField::Uri(node) => {
124 let uri = Name {
125 namespace: "",
126 local: "URI",
127 };
128 if access
129 .attribute(node, uri, |value| value.is_some())
130 .map_err(ReferenceFieldError::Access)?
131 {
132 scalar::check(
133 access,
134 node,
135 LexicalSource::Attribute(uri),
136 Datatype::AnyUri,
137 )
138 .map_err(ReferenceFieldError::Scalar)?;
139 }
140 }
141 ReferenceField::Integer(node) => {
142 scalar::check(
143 access,
144 node,
145 LexicalSource::SimpleContent,
146 Datatype::Integer,
147 )
148 .map_err(ReferenceFieldError::Scalar)?;
149 }
150 ReferenceField::DateTime(node) => {
151 let fact = access
152 .query(node, |xml, snapshot, work| {
153 xml.date_time(snapshot, node, work)
154 })
155 .map_err(ReferenceFieldError::Access)?;
156 match fact {
161 DateTimeFact::Valid { .. } => (),
162 fact => return Err(ReferenceFieldError::Time { node, fact }),
163 }
164 }
165 ReferenceField::Binary(node) => {
166 let location = Location {
167 snapshot: access.snapshot(),
168 node,
169 };
170 let checked = access
171 .query(node, |xml, snapshot, work| {
172 xml.with_octets(snapshot, node, work, |_| Ok::<_, Infallible>(()))
173 })
174 .map_err(|cause| ReferenceFieldError::Binary { location, cause })?;
175 checked.unwrap_or_else(|never| match never {});
176 }
177 }
178 Ok(())
179}