structured_xades/prepare/fields.rs
1//! Original root field preflight before certificate/provider side effects.
2
3use super::{Prepared, UriError, check_uris};
4use crate::attributes::{self, AttributeXml};
5use crate::binary::BinaryXml;
6use crate::properties::{self, ClaimedTime, ClaimedTimeBinding, DateTimeXml};
7use crate::scalar::{ScalarXml, UriXml};
8use crate::xml::{Access, Xml};
9use structured_asn1::memory::Work;
10
11/// Completed root declared-attribute, URI/OID, optional validation-reference
12/// syntax and claimed-time checks against exactly this prepared source.
13/// The borrow prevents substituting another
14/// preparation when composing subsequent certificate/provider checks.
15///
16/// This is deliberately not whole-schema validity or a baseline level. Open
17/// property semantics, binary values, counters, certificate/path/status binding,
18/// policy acceptance and timestamp/material completeness remain obligations.
19pub struct Fields<'prepared, N, D, G> {
20 prepared: &'prepared super::Preparation<N, D, G>,
21 claimed_time: ClaimedTime<N, D, G>,
22}
23
24impl<N, D, G> Fields<'_, N, D, G> {
25 /// Same preparation whose original fields were checked, without reparsing.
26 #[must_use]
27 pub fn prepared(&self) -> &super::Preparation<N, D, G> {
28 self.prepared
29 }
30
31 /// Actual schema-qualified zoned claim, not a verified generation instant.
32 #[must_use]
33 pub fn claimed_time(&self) -> &ClaimedTime<N, D, G> {
34 &self.claimed_time
35 }
36}
37
38/// A failed/incomplete field never creates a successful preflight receipt.
39#[derive(Debug)]
40pub enum FieldError<E, N, D, G> {
41 /// Original root attribute declaration/scalar/source refusal.
42 Attributes(attributes::Error<E, N>),
43 /// Original URI/OID/policy-qualifier refusal.
44 Uri(UriError<E, N>),
45 /// Original optional validation-reference scalar/base64/method refusal.
46 ValidationReference(crate::validation::ReferenceFieldError<E, N, D, G>),
47 /// Original claimed-time source/current-operation refusal.
48 Time(properties::ClaimedTimeError<E, N>),
49 /// Completed claimed-time interpretation did not establish a zoned claim.
50 UnprovenTime {
51 /// Original protected `SigningTime`.
52 node: N,
53 /// Unsupported, malformed and genuinely absent timezone stay distinct.
54 cause: properties::ClaimedTimeFailure,
55 },
56}
57
58/// Root preflight in the XML owner's original identity/error domain.
59pub type FieldResult<'prepared, X> = Result<
60 Fields<'prepared, <X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>,
61 FieldError<<X as Xml>::Error, <X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>,
62>;
63
64/// Execute root field preflight in one ordered path, BEFORE certificate hashes,
65/// key association, path building or timestamp/provider work. Optional original
66/// reference fields use their retained structural model and XML-owned scalar/
67/// base64 kernels; this does not compare references against actual artifacts.
68/// It invokes the
69/// existing field kernels once; no successful caller-supplied flags or copied
70/// normalized values can stand in for the original protected source.
71///
72/// All operations use this current Access/Work, even when preparation survives
73/// its earlier parsing operation. Refusal drops temporary OID/attribute scratch;
74/// the prepared source and its retained storage account remain unchanged.
75pub fn check_fields<'prepared, X, W>(
76 prepared: &'prepared Prepared<X>,
77 access: &Access<'_, X, W>,
78) -> FieldResult<'prepared, X>
79where
80 X: AttributeXml + ScalarXml + UriXml + DateTimeXml + BinaryXml,
81 W: Work,
82{
83 attributes::check_prepared(prepared, access).map_err(FieldError::Attributes)?;
84 check_uris(prepared, access).map_err(FieldError::Uri)?;
85 for index in 0..prepared.validation_references().len() {
86 access.execution().charge_work(1).map_err(|cause| {
87 FieldError::ValidationReference(crate::validation::ReferenceFieldError::Resource {
88 node: prepared.bound().containers().signature(),
89 cause,
90 })
91 })?;
92 crate::validation::check_reference_fields(&prepared.validation_references()[index], access)
93 .map_err(FieldError::ValidationReference)?;
94 }
95 let claimed_time =
96 match properties::check_time(prepared.signed(), access).map_err(FieldError::Time)? {
97 ClaimedTimeBinding::Bound(claimed_time) => claimed_time,
98 ClaimedTimeBinding::Unproven { node, cause } => {
99 return Err(FieldError::UnprovenTime { node, cause });
100 }
101 };
102 Ok(Fields {
103 prepared,
104 claimed_time,
105 })
106}