1use crate::binding::Bound;
4use crate::container::{DS, XADES};
5use crate::xml::{Access, AccessError, ChildError, Name, Node, Snapshot, Xml};
6use structured_asn1::memory::{MemoryError, OwnedVec, Work};
7
8mod claimed_time;
9pub use claimed_time::{
10 CalendarFact, CalendarValue, CalendarXml, ClaimedTime, ClaimedTimeBinding, ClaimedTimeError,
11 ClaimedTimeFailure, ClaimedTimeResult, DateTimeFact, DateTimeXml, check_time,
12};
13
14const SIGNATURE_PROPERTIES: &[&str] = &[
15 "SigningTime",
16 "SigningCertificateV2",
17 "SignaturePolicyIdentifier",
18 "SignatureProductionPlaceV2",
19 "SignerRoleV2",
20];
21const LEGACY_PROPERTIES: &[&str] = &[
22 "SigningCertificate",
23 "SignatureProductionPlace",
24 "SignerRole",
25];
26const OBJECT_PROPERTIES: &[&str] = &[
27 "DataObjectFormat",
28 "CommitmentTypeIndication",
29 "AllDataObjectsTimeStamp",
30 "IndividualDataObjectsTimeStamp",
31];
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum DataObjectRole {
37 Format,
39 Commitment,
41 AllTimestamp,
43 IndividualTimestamp,
45 Extension,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub struct DataObject<N> {
52 pub node: N,
54 pub role: DataObjectRole,
56}
57
58#[derive(Debug)]
60pub struct DataObjects<N> {
61 parent: N,
62 entries: OwnedVec<DataObject<N>>,
63}
64
65impl<N: Copy> DataObjects<N> {
66 #[must_use]
68 pub fn parent(&self) -> N {
69 self.parent
70 }
71
72 #[must_use]
75 pub fn entries(&self) -> &[DataObject<N>] {
76 &self.entries
77 }
78}
79
80#[derive(Debug)]
82pub enum Error<E, N> {
83 Selection {
85 parent: N,
87 index: usize,
89 },
90 Lexical {
92 node: N,
94 local: &'static str,
96 },
97 Access(AccessError<E, N>),
99 Child(ChildError<E, N>),
101 Missing {
103 parent: N,
105 local: &'static str,
107 },
108 Duplicate {
110 node: N,
112 },
113 Order {
115 node: N,
117 },
118 Forbidden {
120 node: N,
122 },
123 Unexpected {
125 node: N,
127 },
128 Resource {
130 node: N,
132 cause: MemoryError,
134 },
135}
136
137pub struct Signed<N, D, G> {
144 snapshot: Snapshot<D, G>,
145 signature: N,
146 parent: N,
147 time: N,
148 certificate: N,
149 policy: Option<N>,
150 place: Option<N>,
151 role: Option<N>,
152 extensions: OwnedVec<N>,
153 objects: Option<DataObjects<N>>,
154}
155
156impl<N: Copy, D: Copy, G: Copy> Signed<N, D, G> {
157 #[must_use]
159 pub fn snapshot(&self) -> Snapshot<D, G> {
160 self.snapshot
161 }
162 #[must_use]
164 pub fn signature(&self) -> N {
165 self.signature
166 }
167 #[must_use]
169 pub fn parent(&self) -> N {
170 self.parent
171 }
172 #[must_use]
174 pub fn signing_time(&self) -> N {
175 self.time
176 }
177 #[must_use]
179 pub fn signing_certificate(&self) -> N {
180 self.certificate
181 }
182 #[must_use]
184 pub fn policy(&self) -> Option<N> {
185 self.policy
186 }
187 #[must_use]
189 pub fn place(&self) -> Option<N> {
190 self.place
191 }
192 #[must_use]
194 pub fn role(&self) -> Option<N> {
195 self.role
196 }
197 #[must_use]
199 pub fn extensions(&self) -> &[N] {
200 &self.extensions
201 }
202
203 #[must_use]
206 pub fn data_objects(&self) -> Option<&DataObjects<N>> {
207 self.objects.as_ref()
208 }
209}
210
211pub type Reading<X> = Signed<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>;
213pub type PropertyResult<T, X> = Result<T, Error<<X as Xml>::Error, <X as Xml>::Id>>;
215
216pub(crate) fn simple_content<X: Xml, W: Work>(
221 access: &Access<'_, X, W>,
222 parent: X::Id,
223) -> PropertyResult<(), X> {
224 let mut child = access.first_child(parent).map_err(Error::Access)?;
225 while let Some(node) = child {
226 if access
227 .inspect(node, |value| matches!(value, Node::Element(_)))
228 .map_err(Error::Access)?
229 {
230 return Err(Error::Unexpected { node });
231 }
232 child = access.next_sibling(parent, node).map_err(Error::Access)?;
233 }
234 Ok(())
235}
236
237pub(crate) fn digest_value<X: Xml, W: Work>(
241 access: &Access<'_, X, W>,
242 parent: X::Id,
243) -> PropertyResult<(X::Id, X::Id), X> {
244 let mut children = access.children(parent);
245 let method = children
246 .next()
247 .transpose()
248 .map_err(Error::Child)?
249 .ok_or(Error::Missing {
250 parent,
251 local: "DigestMethod",
252 })?;
253 if !access
254 .has_name(
255 method,
256 Name {
257 namespace: DS,
258 local: "DigestMethod",
259 },
260 )
261 .map_err(Error::Access)?
262 {
263 return Err(Error::Unexpected { node: method });
264 }
265 let value = children
266 .next()
267 .transpose()
268 .map_err(Error::Child)?
269 .ok_or(Error::Missing {
270 parent,
271 local: "DigestValue",
272 })?;
273 if !access
274 .has_name(
275 value,
276 Name {
277 namespace: DS,
278 local: "DigestValue",
279 },
280 )
281 .map_err(Error::Access)?
282 {
283 return Err(Error::Unexpected { node: value });
284 }
285 if let Some(extra) = children.next() {
286 return Err(Error::Unexpected {
287 node: extra.map_err(Error::Child)?,
288 });
289 }
290 simple_content(access, value)?;
291 Ok((method, value))
292}
293
294pub(crate) type Sections<X> = (Option<<X as Xml>::Id>, Option<<X as Xml>::Id>);
295
296pub(crate) fn sections<X: Xml, W: Work>(
299 access: &Access<'_, X, W>,
300 layout: &crate::container::Layout<X>,
301) -> PropertyResult<Sections<X>, X> {
302 if layout.snapshot() != access.snapshot() {
303 return Err(Error::Access(AccessError::Changed {
304 node: layout.signed(),
305 }));
306 }
307 let mut parent = None;
308 let mut objects = None;
309 for child in access.children(layout.signed()) {
310 let node = child.map_err(Error::Child)?;
311 if named(access, node, "SignedSignatureProperties")? {
312 if parent.is_some() {
313 return Err(Error::Duplicate { node });
314 }
315 if objects.is_some() {
316 return Err(Error::Order { node });
317 }
318 parent = Some(node);
319 } else if named(access, node, "SignedDataObjectProperties")? {
320 if objects.is_some() {
321 return Err(Error::Duplicate { node });
322 }
323 objects = Some(node);
324 } else {
325 return Err(Error::Unexpected { node });
326 }
327 }
328 Ok((parent, objects))
329}
330
331pub fn read<X: Xml, W: Work>(
338 access: &Access<'_, X, W>,
339 bound: &Bound<X::Id, X::Document, X::Generation>,
340) -> PropertyResult<Reading<X>, X> {
341 let layout = bound.containers();
342 let (parent, objects) = sections(access, layout)?;
343 let parent = parent.ok_or(Error::Missing {
344 parent: layout.signed(),
345 local: "SignedSignatureProperties",
346 })?;
347 let mut fields = [None; 5];
348 let mut previous = 0;
349 let mut extensions = access
350 .query(parent, |_, _, work| Ok(work.vector()))
351 .map_err(Error::Access)?;
352 for child in access.children(parent) {
353 let node = child.map_err(Error::Child)?;
354 let kind = classify(access, node, SIGNATURE_PROPERTIES, LEGACY_PROPERTIES)?;
355 let rank = match kind {
356 Kind::Known(rank) => {
357 if fields[rank].is_some() {
358 return Err(Error::Duplicate { node });
359 }
360 fields[rank] = Some(node);
361 rank
362 }
363 Kind::Extension => {
364 extensions
365 .try_push(node)
366 .map_err(|cause| Error::Resource { node, cause })?;
367 SIGNATURE_PROPERTIES.len()
368 }
369 Kind::Forbidden => return Err(Error::Forbidden { node }),
370 Kind::Unexpected => return Err(Error::Unexpected { node }),
371 };
372 if rank < previous {
373 return Err(Error::Order { node });
374 }
375 previous = rank;
376 }
377 let time = fields[0].ok_or(Error::Missing {
378 parent,
379 local: "SigningTime",
380 })?;
381 let certificate = fields[1].ok_or(Error::Missing {
382 parent,
383 local: "SigningCertificateV2",
384 })?;
385 simple_content(access, time)?;
386 if let Some(place) = fields[3] {
387 production_place(access, place)?;
388 }
389 let objects = objects
390 .map(|parent| read_objects(access, parent))
391 .transpose()?;
392 Ok(Signed {
393 snapshot: layout.snapshot(),
394 signature: layout.signature(),
395 parent,
396 time,
397 certificate,
398 policy: fields[2],
399 place: fields[3],
400 role: fields[4],
401 extensions: extensions.into_owned(),
402 objects,
403 })
404}
405
406fn production_place<X: Xml, W: Work>(
407 access: &Access<'_, X, W>,
408 parent: X::Id,
409) -> PropertyResult<(), X> {
410 const FIELDS: &[&str] = &[
414 "City",
415 "StreetAddress",
416 "StateOrProvince",
417 "PostalCode",
418 "CountryName",
419 ];
420 let mut seen = [false; 5];
421 let mut previous = None;
422 for child in access.children(parent) {
423 let node = child.map_err(Error::Child)?;
424 let rank = match classify(access, node, FIELDS, &[])? {
425 Kind::Known(rank) => rank,
426 Kind::Forbidden | Kind::Unexpected | Kind::Extension => {
427 return Err(Error::Unexpected { node });
428 }
429 };
430 if seen[rank] {
431 return Err(Error::Duplicate { node });
432 }
433 if let Some(previous) = previous
434 && rank < previous
435 {
436 return Err(Error::Order { node });
437 }
438 seen[rank] = true;
439 previous = Some(rank);
440 simple_content(access, node)?;
441 }
442 if previous.is_none() {
443 return Err(Error::Missing {
444 parent,
445 local: "production-place field",
446 });
447 }
448 Ok(())
449}
450
451enum Kind {
452 Known(usize),
453 Extension,
454 Forbidden,
455 Unexpected,
456}
457
458fn classify<X: Xml, W: Work>(
459 access: &Access<'_, X, W>,
460 node: X::Id,
461 known: &[&str],
462 forbidden: &[&str],
463) -> PropertyResult<Kind, X> {
464 access
465 .inspect(node, |value| {
466 let Node::Element(actual) = value else {
467 return Ok(Kind::Unexpected);
468 };
469 if actual.namespace.is_empty() {
473 return Ok(Kind::Unexpected);
474 }
475 if !access.equal(actual.namespace, XADES)? {
476 return Ok(Kind::Extension);
477 }
478 for (rank, local) in known.iter().enumerate() {
479 if access.equal(actual.local, local)? {
480 return Ok(Kind::Known(rank));
481 }
482 }
483 for local in forbidden {
484 if access.equal(actual.local, local)? {
485 return Ok(Kind::Forbidden);
486 }
487 }
488 Ok(Kind::Unexpected)
489 })
490 .map_err(Error::Access)?
491 .map_err(|cause| Error::Resource { node, cause })
492}
493
494pub(crate) fn read_objects<X: Xml, W: Work>(
495 access: &Access<'_, X, W>,
496 parent: X::Id,
497) -> PropertyResult<DataObjects<X::Id>, X> {
498 let mut entries = access
502 .query(parent, |_, _, work| Ok(work.vector()))
503 .map_err(Error::Access)?;
504 let mut previous = 0;
505 for child in access.children(parent) {
506 let node = child.map_err(Error::Child)?;
507 let (rank, role) = match classify(access, node, OBJECT_PROPERTIES, &[])? {
508 Kind::Known(rank) => {
509 let roles = [
510 DataObjectRole::Format,
511 DataObjectRole::Commitment,
512 DataObjectRole::AllTimestamp,
513 DataObjectRole::IndividualTimestamp,
514 ];
515 debug_assert!(rank < roles.len());
516 (rank, roles[rank])
517 }
518 Kind::Extension => (OBJECT_PROPERTIES.len(), DataObjectRole::Extension),
519 Kind::Forbidden | Kind::Unexpected => return Err(Error::Unexpected { node }),
520 };
521 if rank < previous {
522 return Err(Error::Order { node });
523 }
524 entries
525 .try_push(DataObject { node, role })
526 .map_err(|cause| Error::Resource { node, cause })?;
527 previous = rank;
528 }
529 Ok(DataObjects {
530 parent,
531 entries: entries.into_owned(),
532 })
533}
534
535fn named<X: Xml, W: Work>(
536 access: &Access<'_, X, W>,
537 node: X::Id,
538 local: &str,
539) -> PropertyResult<bool, X> {
540 access
541 .has_name(
542 node,
543 Name {
544 namespace: XADES,
545 local,
546 },
547 )
548 .map_err(Error::Access)
549}