structured_xades/timestamp/
counters.rs1use super::{Input, InputError, InputResult, Role, Stamp, TimestampXml};
4use crate::xml::{Access, Snapshot, Xml};
5use crate::{binding, container, pki::CounterPaths, properties};
6use structured_asn1::memory::{OwnedVec, Work};
7
8pub struct CounterStamp<N, D, G> {
11 layout: container::Containers<N, D, G>,
12 stamp: Stamp<N, D, G>,
13}
14
15impl<N: Copy, D: Copy, G: Copy> CounterStamp<N, D, G> {
16 #[must_use]
18 pub fn stamp(&self) -> &Stamp<N, D, G> {
19 &self.stamp
20 }
21
22 pub fn input<'xml, X: TimestampXml<Id = N, Document = D, Generation = G>, W: Work>(
25 &self,
26 xml: &'xml X,
27 execution: &W,
28 ) -> InputResult<Input<'xml, X>, X> {
29 Input::prepare_in(xml, &self.layout, &self.stamp, execution)
30 }
31}
32
33pub struct CounterTimestamps<N, D, G> {
36 pub(super) snapshot: Snapshot<D, G>,
37 pub(super) signature: N,
38 pub(super) entries: OwnedVec<CounterStamp<N, D, G>>,
39 pub(super) signatures: OwnedVec<N>,
40}
41
42impl<N, D, G> CounterTimestamps<N, D, G> {
43 #[must_use]
45 pub fn entries(&self) -> &[CounterStamp<N, D, G>] {
46 &self.entries
47 }
48}
49
50#[derive(Debug)]
52pub enum CounterTimestampError<E, N> {
53 Input(InputError<E, N>),
55 Property(properties::Error<E, N>),
57 Binding(binding::BindingError<E, N>),
59}
60
61pub type CounterTimestampResult<X> = Result<
63 CounterTimestamps<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>,
64 CounterTimestampError<<X as Xml>::Error, <X as Xml>::Id>,
65>;
66
67pub fn counter_timestamps<X: binding::SignatureXml, W: Work>(
74 access: &Access<'_, X, W>,
75 counters: &CounterPaths<'_, '_, X::Id, X::Document, X::Generation>,
76) -> CounterTimestampResult<X> {
77 let root = counters.signature();
78 if counters.snapshot() != access.snapshot() {
79 return Err(CounterTimestampError::Input(InputError::Foreign {
80 node: root,
81 }));
82 }
83 let mut entries = access.execution().vector();
84 let mut signatures = access.execution().vector();
85 for index in 0..counters.actors().len() {
86 pay(access, root)?;
87 let actor = &counters.actors()[index];
88 let signature = actor.signer().counter().original().child();
89 pay(access, signature)?;
90 signatures.try_push(signature).map_err(|cause| {
91 CounterTimestampError::Input(InputError::Resource {
92 node: signature,
93 cause,
94 })
95 })?;
96 let Some(layout) = actor.containers() else {
97 continue;
98 };
99 let [parent, _] = crate::unsigned::containers(access, layout.unsigned())
100 .map_err(CounterTimestampError::Property)?;
101 if let Some(parent) = parent {
102 let mut target_checked = false;
103 for child in access.children(parent) {
104 let node = child
105 .map_err(|cause| CounterTimestampError::Input(InputError::Child(cause)))?;
106 if super::named(access, node, container::XADES, "SignatureTimeStamp")
107 .map_err(CounterTimestampError::Input)?
108 || super::named(access, node, super::XADES_141, "ArchiveTimeStamp")
109 .map_err(CounterTimestampError::Input)?
110 || super::named(access, node, super::XADES_141, "SigAndRefsTimeStampV2")
111 .map_err(CounterTimestampError::Input)?
112 || super::named(access, node, super::XADES_141, "RefsOnlyTimeStampV2")
113 .map_err(CounterTimestampError::Input)?
114 {
115 if !target_checked {
116 binding::check_target(access, layout)
117 .map_err(CounterTimestampError::Binding)?;
118 target_checked = true;
119 }
120 let stamp = super::read_in(access, layout, node)
121 .map_err(CounterTimestampError::Input)?;
122 entries
123 .try_push(CounterStamp {
124 layout: *layout,
125 stamp,
126 })
127 .map_err(|cause| {
128 CounterTimestampError::Input(InputError::Resource { node, cause })
129 })?;
130 }
131 }
132 }
133 let (_, objects) =
134 properties::sections(access, layout).map_err(CounterTimestampError::Property)?;
135 if let Some(parent) = objects {
136 let objects = properties::read_objects(access, parent)
137 .map_err(CounterTimestampError::Property)?;
138 let mut authenticated = false;
139 for entry in objects.entries() {
140 pay(access, entry.node)?;
141 let role = match entry.role {
142 properties::DataObjectRole::AllTimestamp => Role::AllDataObjects,
143 properties::DataObjectRole::IndividualTimestamp => Role::IndividualDataObjects,
144 _ => continue,
145 };
146 if !authenticated {
147 binding::bind(access, layout).map_err(CounterTimestampError::Binding)?;
148 authenticated = true;
149 }
150 let stamp = super::read_object_fields(access, layout, &objects, entry.node, role)
151 .map_err(CounterTimestampError::Input)?;
152 entries
153 .try_push(CounterStamp {
154 layout: *layout,
155 stamp,
156 })
157 .map_err(|cause| {
158 CounterTimestampError::Input(InputError::Resource {
159 node: entry.node,
160 cause,
161 })
162 })?;
163 }
164 }
165 }
166 pay(access, root)?;
167 Ok(CounterTimestamps {
168 snapshot: access.snapshot(),
169 signature: root,
170 entries: entries.into_owned(),
171 signatures: signatures.into_owned(),
172 })
173}
174
175fn pay<X: Xml, W: Work>(
176 access: &Access<'_, X, W>,
177 node: X::Id,
178) -> Result<(), CounterTimestampError<X::Error, X::Id>> {
179 access
180 .query(node, |_, _, work| Ok(work.charge_work(1)))
181 .map_err(|cause| CounterTimestampError::Input(InputError::Access(cause)))?
182 .map_err(|cause| CounterTimestampError::Input(InputError::Resource { node, cause }))
183}