1use crate::binding::Bound;
4use crate::container::XADES;
5use crate::material::{self, Catalogue};
6use crate::properties;
7use crate::timestamp::{self, InputError, XADES_141};
8use crate::xml::{Access, Name, Snapshot, Xml};
9use structured_asn1::memory::Work;
10
11mod refs;
12pub(crate) use refs::read as read_references;
13mod ref_catalogue;
14mod ref_digest;
15pub use ref_catalogue::{
16 MaterialDigest, ReferenceCatalogueResult, ReferenceDigests, ReferenceRow, ReferenceSearch,
17 compare_reference_catalogues, compare_reference_catalogues_with_tokens,
18};
19mod ref_issuer;
20mod ref_time;
21pub use ref_time::{ReferenceTime, ReferenceTimeError, matches_reference_time};
22mod ref_envelope;
23mod ref_key;
24mod ref_name;
25mod ref_ocsp;
26pub use ref_envelope::{
27 OcspEnvelopeError, OcspEnvelopeReference, OcspEnvelopeResult, OcspReferenceInput,
28 check_ocsp_envelope_reference,
29};
30pub use ref_issuer::with_reference_issuer_serial;
31pub use ref_key::{
32 ReferenceKeyResult, ResponderKeyError, matches_reference_key, with_responder_key,
33};
34pub use ref_name::{ReferenceNameError, matches_reference_name};
35pub use ref_ocsp::{
36 OcspReferenceError, OcspReferenceIdentity, OcspReferenceResult, check_ocsp_reference,
37};
38mod ref_credential_certificates;
39mod ref_crl;
40mod ref_crl_value;
41mod ref_path;
42mod ref_presence;
43mod ref_roles;
44mod ref_status_required;
45pub use ref_credential_certificates::{
46 CredentialCertificate, CredentialCertificateReferences, CredentialCertificateResult,
47 CredentialCertificateRow, CredentialReferencePlace, check_credential_certificate_references,
48};
49mod ref_status_roles;
50pub use ref_path::{
51 RootPathReferenceResult, RootPathReferences, RootReferenceRow,
52 check_root_certificate_references,
53};
54pub use ref_presence::{
55 ReferencePresence, ReferencePresenceError, ReferencePresenceFailure, ReferencePresenceResult,
56 ReferencePresenceRow, reference_presence,
57};
58pub use ref_roles::{
59 CertificateRoleComparison, CertificateRoleError, CertificateRoleResult, CertificateRoleRow,
60 CertificateRoles, check_certificate_reference_roles,
61};
62pub use ref_status_required::{CredentialStatusSource, PathStatusSource};
63pub use ref_status_roles::{
64 RevocationRoleResult, RevocationRoles, StatusRoleAgreement, StatusRoleComparison,
65 StatusRoleRow, StatusSourceComparison, check_revocation_reference_roles,
66};
67mod ref_fields;
68pub use ref_crl::{
69 CrlReferenceError, CrlReferenceIdentity, CrlReferenceResult, check_crl_reference,
70};
71pub use ref_crl_value::{
72 CrlValueError, CrlValueReference, CrlValueResult, check_crl_value_reference,
73};
74pub use ref_digest::{
75 ReferenceDigest, ReferenceDigestError, ReferenceTarget, compare_reference_digest,
76 compare_reference_target,
77};
78pub use ref_fields::{ReferenceFieldError, ReferenceFieldResult, check_reference_fields};
79pub use refs::{
80 ReferenceEntry, ReferenceField, ReferenceIdentifier, ReferenceKind, ReferenceProperty,
81 ResponderIdentifier,
82};
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86pub enum Role {
87 Any,
89 Timestamp,
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95pub enum Hint<N> {
96 Adjacent(N),
99 Unresolved {
102 uri_present: bool,
104 },
105}
106
107#[derive(Debug)]
109pub enum Error<E, N> {
110 Input(InputError<E, N>),
112 Property(properties::Error<E, N>),
115 ForbiddenUri {
117 node: N,
119 },
120 Empty {
122 node: N,
124 },
125}
126
127#[derive(Debug)]
129pub struct Data<N, D, G> {
130 snapshot: Snapshot<D, G>,
131 signature: N,
132 node: N,
133 role: Role,
134 hint: Option<Hint<N>>,
135 certificates: Option<Catalogue<N, D, G>>,
136 revocations: Option<Catalogue<N, D, G>>,
137}
138
139impl<N: Copy, D: Copy, G: Copy> Data<N, D, G> {
140 #[must_use]
142 pub fn snapshot(&self) -> Snapshot<D, G> {
143 self.snapshot
144 }
145 #[must_use]
147 pub fn signature(&self) -> N {
148 self.signature
149 }
150 #[must_use]
152 pub fn node(&self) -> N {
153 self.node
154 }
155 #[must_use]
157 pub fn role(&self) -> Role {
158 self.role
159 }
160 #[must_use]
162 pub fn hint(&self) -> Option<Hint<N>> {
163 self.hint
164 }
165 #[must_use]
167 pub fn certificates(&self) -> Option<&Catalogue<N, D, G>> {
168 self.certificates.as_ref()
169 }
170 #[must_use]
172 pub fn revocations(&self) -> Option<&Catalogue<N, D, G>> {
173 self.revocations.as_ref()
174 }
175}
176
177pub type Reading<X> = Data<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>;
179pub type ValidationResult<T, X> = Result<T, Error<<X as Xml>::Error, <X as Xml>::Id>>;
181
182pub fn read<X: Xml, W: Work>(
190 access: &Access<'_, X, W>,
191 bound: &Bound<X::Id, X::Document, X::Generation>,
192 node: X::Id,
193) -> ValidationResult<Reading<X>, X> {
194 let parent = timestamp::unsigned_parent(access, bound, node).map_err(Error::Input)?;
195 let mut previous = None;
196 let mut found = false;
197 for child in access.children(parent) {
198 let child = child.map_err(|cause| Error::Input(InputError::Child(cause)))?;
199 if access
200 .equal_id(child, node)
201 .map_err(|cause| Error::Input(InputError::Resource { node: child, cause }))?
202 {
203 found = true;
204 break;
205 }
206 previous = Some(child);
207 }
208 if !found {
209 return Err(Error::Input(InputError::Foreign { node }));
210 }
211 read_at(access, bound.containers().signature(), node, previous)
212}
213
214pub(crate) fn read_at<X: Xml, W: Work>(
218 access: &Access<'_, X, W>,
219 signature: X::Id,
220 node: X::Id,
221 previous: Option<X::Id>,
222) -> ValidationResult<Reading<X>, X> {
223 let role = if named(access, node, XADES_141, "AnyValidationData")? {
224 Role::Any
225 } else if named(access, node, XADES_141, "TimeStampValidationData")? {
226 Role::Timestamp
227 } else {
228 return Err(Error::Input(InputError::Unexpected { node }));
229 };
230 let uri_present = access
231 .attribute(
232 node,
233 Name {
234 namespace: "",
235 local: "URI",
236 },
237 |value| value.is_some(),
238 )
239 .map_err(|cause| Error::Input(InputError::Access(cause)))?;
240 if role == Role::Any && uri_present {
241 return Err(Error::ForbiddenUri { node });
242 }
243 let mut hint = None;
244 if role == Role::Timestamp {
245 hint = Some(Hint::Unresolved { uri_present });
246 if let Some(prior) = previous
247 && (named(access, prior, XADES, "SignatureTimeStamp")?
248 || named(access, prior, XADES_141, "ArchiveTimeStamp")?
249 || named(access, prior, XADES_141, "SigAndRefsTimeStampV2")?
250 || named(access, prior, XADES_141, "RefsOnlyTimeStampV2")?)
251 {
252 hint = Some(Hint::Adjacent(prior));
253 }
254 }
255 let mut certificates = None;
256 let mut revocations = None;
257 for child in access.children(node) {
258 let child = child.map_err(|cause| Error::Input(InputError::Child(cause)))?;
259 if named(access, child, XADES, "CertificateValues")? {
260 if certificates.is_some() {
261 return Err(Error::Property(properties::Error::Duplicate {
262 node: child,
263 }));
264 }
265 if revocations.is_some() {
266 return Err(Error::Property(properties::Error::Order { node: child }));
267 }
268 certificates = Some(material::read(access, child).map_err(Error::Property)?);
269 } else if named(access, child, XADES, "RevocationValues")? {
270 if revocations.is_some() {
271 return Err(Error::Property(properties::Error::Duplicate {
272 node: child,
273 }));
274 }
275 revocations = Some(material::read(access, child).map_err(Error::Property)?);
276 } else {
277 return Err(Error::Input(InputError::Unexpected { node: child }));
278 }
279 }
280 if role == Role::Any
281 && certificates.as_ref().is_none_or(|c| c.entries().is_empty())
282 && revocations.as_ref().is_none_or(|c| c.entries().is_empty())
283 {
284 return Err(Error::Empty { node });
285 }
286 Ok(Data {
287 snapshot: access.snapshot(),
288 signature,
289 node,
290 role,
291 hint,
292 certificates,
293 revocations,
294 })
295}
296
297fn named<X: Xml, W: Work>(
298 access: &Access<'_, X, W>,
299 node: X::Id,
300 namespace: &str,
301 local: &str,
302) -> ValidationResult<bool, X> {
303 access
304 .has_name(node, Name { namespace, local })
305 .map_err(|cause| Error::Input(InputError::Access(cause)))
306}