structured_cms/timestamp/
retained.rs1use super::{Accuracy, EffectiveAccuracy, HashAlgorithmReading, TokenInfo};
4use crate::{Error, ErrorCode, Result};
5use structured_asn1::{
6 Oid, Reader, Span,
7 memory::{OwnedVec, Work},
8 value::OwnedOid,
9};
10use structured_pkix::temporal::Reading;
11
12#[derive(Debug)]
16pub struct RetainedImprint {
17 algorithm: OwnedOid,
18 parameters: Option<OwnedVec<u8>>,
19 hashed: OwnedVec<u8>,
20}
21impl RetainedImprint {
22 #[must_use]
24 pub fn algorithm(&self) -> Oid<'_> {
25 self.algorithm.as_oid()
26 }
27 #[must_use]
29 pub fn parameters(&self) -> Option<&[u8]> {
30 self.parameters.as_deref()
31 }
32 #[must_use]
34 pub fn hashed(&self) -> &[u8] {
35 &self.hashed
36 }
37}
38
39#[derive(Debug)]
46pub struct RetainedFacts {
47 imprint: RetainedImprint,
48 policy: OwnedOid,
49 serial: OwnedVec<u8>,
50 nonce: Option<OwnedVec<u8>>,
51 gen_time: structured_pkix::temporal::ExactReading,
52 accuracy: Option<EffectiveAccuracy>,
53 ordering: bool,
54 source_span: Span,
55}
56
57impl TokenInfo<'_> {
58 pub fn retain_facts(&self, parent: &Reader<'_>) -> Result<RetainedFacts> {
65 self.imprint().require_session(parent)?;
66 if self.has_faults() {
67 return Err(Error::schema(
68 ErrorCode::MalformedValue,
69 "tstInfo",
70 self.span().start,
71 ));
72 }
73 let HashAlgorithmReading::Identifier(algorithm) = self.imprint().algorithm() else {
74 return Err(Error::schema(
75 ErrorCode::MalformedValue,
76 "tstInfo.messageImprint",
77 self.imprint().span().start,
78 ));
79 };
80 let accuracy = self
81 .accuracy()
82 .map(super::AccuracyReading::deviation)
83 .transpose()
84 .map_err(|error| {
85 Error::schema(
86 ErrorCode::MalformedValue,
87 "tstInfo.accuracy",
88 error.span.start,
89 )
90 })?;
91 let work = parent.execution();
92 work.charge_work(8)
93 .map_err(|reason| Error::resource(reason, "tstInfo", self.span().start))?;
94 let hash_algorithm =
95 OwnedOid::from_oid_in(algorithm.algorithm(), &work).map_err(|reason| {
96 Error::resource(
97 reason,
98 "tstInfo.messageImprint.hashAlgorithm",
99 algorithm.offset(),
100 )
101 })?;
102 let parameters = algorithm
103 .parameters()
104 .map(|bytes| {
105 retain(
106 bytes,
107 &work,
108 "tstInfo.messageImprint.hashAlgorithm.parameters",
109 algorithm.offset(),
110 )
111 })
112 .transpose()?;
113 let hashed = self
114 .imprint()
115 .hashed()
116 .copy_in(
117 parent,
118 "tstInfo.messageImprint.hashedMessage",
119 self.imprint().hashed().span().start,
120 )?
121 .into_owned();
122 let policy = OwnedOid::from_oid_in(self.policy(), &work)
123 .map_err(|reason| Error::resource(reason, "tstInfo.policy", self.span().start))?;
124 let serial = retain(
125 self.serial().element().contents(),
126 &work,
127 "tstInfo.serialNumber",
128 self.serial().element().span().start,
129 )?;
130 let nonce = self
131 .nonce()
132 .map(|nonce| {
133 retain(
134 nonce.element().contents(),
135 &work,
136 "tstInfo.nonce",
137 nonce.element().span().start,
138 )
139 })
140 .transpose()?;
141 let gen_time = self
142 .precise_gen_time()
143 .try_copy_in(&work, "tstInfo.genTime", self.span().start)
144 .map_err(Error::pkix)?;
145 Ok(RetainedFacts {
146 imprint: RetainedImprint {
147 algorithm: hash_algorithm,
148 parameters,
149 hashed,
150 },
151 policy,
152 serial,
153 nonce,
154 gen_time,
155 accuracy: accuracy.map(EffectiveAccuracy::Token),
156 ordering: self.ordering(),
157 source_span: self.span(),
158 })
159 }
160}
161
162fn retain<W: Work>(bytes: &[u8], work: &W, field: &'static str, at: u64) -> Result<OwnedVec<u8>> {
163 let mut owned = work.vector();
164 owned
165 .try_extend_from_slice(bytes)
166 .map_err(|reason| Error::resource(reason, field, at))?;
167 Ok(owned.into_owned())
168}
169
170impl RetainedFacts {
171 pub(super) fn with_effective_accuracy(mut self, accuracy: Option<EffectiveAccuracy>) -> Self {
174 self.accuracy = accuracy;
175 self
176 }
177 pub fn try_copy_in<W: Work>(&self, work: &W) -> Result<Self> {
181 work.charge_work(8)
182 .map_err(|reason| Error::resource(reason, "tstInfo", self.source_span.start))?;
183 let algorithm =
184 OwnedOid::from_oid_in(self.imprint.algorithm(), work).map_err(|reason| {
185 Error::resource(
186 reason,
187 "tstInfo.messageImprint.hashAlgorithm",
188 self.source_span.start,
189 )
190 })?;
191 let parameters = self
192 .imprint
193 .parameters()
194 .map(|bytes| {
195 retain(
196 bytes,
197 work,
198 "tstInfo.messageImprint.hashAlgorithm.parameters",
199 self.source_span.start,
200 )
201 })
202 .transpose()?;
203 let hashed = retain(
204 self.imprint.hashed(),
205 work,
206 "tstInfo.messageImprint.hashedMessage",
207 self.source_span.start,
208 )?;
209 let policy = OwnedOid::from_oid_in(self.policy(), work)
210 .map_err(|reason| Error::resource(reason, "tstInfo.policy", self.source_span.start))?;
211 let serial = retain(
212 self.serial(),
213 work,
214 "tstInfo.serialNumber",
215 self.source_span.start,
216 )?;
217 let nonce = self
218 .nonce()
219 .map(|bytes| retain(bytes, work, "tstInfo.nonce", self.source_span.start))
220 .transpose()?;
221 let gen_time = self
222 .gen_time
223 .try_copy_in(work, "tstInfo.genTime", self.source_span.start)
224 .map_err(Error::pkix)?;
225 Ok(Self {
226 imprint: RetainedImprint {
227 algorithm,
228 parameters,
229 hashed,
230 },
231 policy,
232 serial,
233 nonce,
234 gen_time,
235 accuracy: self.accuracy,
236 ordering: self.ordering,
237 source_span: self.source_span,
238 })
239 }
240 #[must_use]
242 pub fn imprint(&self) -> &RetainedImprint {
243 &self.imprint
244 }
245 #[must_use]
247 pub fn policy(&self) -> Oid<'_> {
248 self.policy.as_oid()
249 }
250 #[must_use]
252 pub fn serial(&self) -> &[u8] {
253 &self.serial
254 }
255 #[must_use]
257 pub fn nonce(&self) -> Option<&[u8]> {
258 self.nonce.as_deref()
259 }
260 #[must_use]
262 pub fn gen_time(&self) -> Reading {
263 self.gen_time.reading()
264 }
265 pub fn compare_generation<W: Work>(
270 &self,
271 other: &Self,
272 utc: &super::LeapTable<'_>,
273 work: &W,
274 ) -> core::result::Result<core::cmp::Ordering, super::GenerationOrderError> {
275 self.gen_time.compare(&other.gen_time, utc, work)
276 }
277 #[must_use]
279 pub fn accuracy(&self) -> Option<Accuracy> {
280 match self.accuracy {
281 Some(EffectiveAccuracy::Token(value)) => Some(value),
282 None | Some(EffectiveAccuracy::CallerPolicy(_)) => None,
283 }
284 }
285 #[must_use]
288 pub fn effective_accuracy(&self) -> Option<EffectiveAccuracy> {
289 self.accuracy
290 }
291 #[must_use]
293 pub fn ordering(&self) -> bool {
294 self.ordering
295 }
296 #[must_use]
299 pub fn source_span(&self) -> Span {
300 self.source_span
301 }
302}