1use crate::{
8 ContentInfo, Error, ErrorCode, Octets, Result, SignedData, attribute::Attribute, oid,
9 timestamp::Token,
10};
11use structured_asn1::{
12 Element, Encoding, Oid, Parser, Reader, Span, Tag,
13 memory::{OwnedVec, Work},
14 universal,
15};
16use structured_pkix::algorithm::{self, AlgorithmIdentifier};
17
18const FIELD: &str = "evidenceRecord";
19
20mod input;
21pub use input::{InputError, Membership, ObjectInput};
22mod renewal;
23pub use renewal::PriorSequence;
24mod objects;
25pub use objects::{AsyncObjects, AsyncStreams};
26pub mod verify;
27
28#[derive(Debug, Clone, Copy)]
30pub struct Original<'d> {
31 parser: &'d Parser,
32 element: Element<'d>,
33 encoding: Encoding,
34 outer: u32,
35}
36impl<'d> Original<'d> {
37 fn new(parent: &Reader<'d>, element: Element<'d>) -> Self {
38 Self {
39 parser: parent.parser(),
40 element,
41 encoding: parent.encoding(),
42 outer: parent.depth(),
43 }
44 }
45 #[must_use]
47 pub fn element(&self) -> Element<'d> {
48 self.element
49 }
50 pub fn reader_in<'q>(&self, query: &Reader<'q>) -> Result<Reader<'q>>
52 where
53 'd: 'q,
54 {
55 self.parser
56 .read_query_in(
57 query,
58 self.element.as_bytes(),
59 self.element.span().start,
60 self.encoding,
61 self.outer,
62 )
63 .map_err(|cause| Error::encoding(cause, FIELD))
64 }
65}
66
67#[derive(Debug)]
69pub struct EncryptionInfo<'d> {
70 kind: Oid<'d>,
71 value: Original<'d>,
72}
73impl<'d> EncryptionInfo<'d> {
74 #[must_use]
76 pub fn kind(&self) -> Oid<'d> {
77 self.kind
78 }
79 #[must_use]
81 pub fn value(&self) -> Original<'d> {
82 self.value
83 }
84}
85
86#[derive(Debug)]
88pub struct PartialTree<'d> {
89 original: Original<'d>,
90 hashes: OwnedVec<Octets<'d>>,
91}
92impl<'d> PartialTree<'d> {
93 #[must_use]
95 pub fn original(&self) -> Original<'d> {
96 self.original
97 }
98 #[must_use]
100 pub fn hashes(&self) -> &[Octets<'d>] {
101 &self.hashes
102 }
103}
104
105#[derive(Debug)]
107#[expect(
108 clippy::large_enum_variant,
109 reason = "the normal RFC3161 model is retained inline in the quota-backed flat stamp catalogue; boxing would add a separate allocation for every token"
110)]
111pub enum TimeStamp<'d> {
112 Rfc3161(Token<'d>),
114 Other(Original<'d>),
116}
117
118#[derive(Debug)]
120pub struct ArchiveTimeStamp<'d> {
121 original: Original<'d>,
122 algorithm: Option<AlgorithmIdentifier<'d>>,
123 attributes: Option<OwnedVec<Attribute<'d>>>,
124 attributes_span: Option<Span>,
125 tree: Option<OwnedVec<PartialTree<'d>>>,
126 timestamp: Original<'d>,
127 token: TimeStamp<'d>,
128}
129impl<'d> ArchiveTimeStamp<'d> {
130 #[must_use]
132 pub fn original(&self) -> Original<'d> {
133 self.original
134 }
135 #[must_use]
137 pub fn digest_algorithm(&self) -> Option<AlgorithmIdentifier<'d>> {
138 self.algorithm
139 }
140 #[must_use]
142 pub fn attributes(&self) -> Option<&[Attribute<'d>]> {
143 self.attributes.as_deref()
144 }
145 #[must_use]
147 pub fn reduced_tree(&self) -> Option<&[PartialTree<'d>]> {
148 self.tree.as_deref()
149 }
150 #[must_use]
152 pub fn timestamp_source(&self) -> Original<'d> {
153 self.timestamp
154 }
155 #[must_use]
157 pub fn timestamp(&self) -> &TimeStamp<'d> {
158 &self.token
159 }
160}
161
162#[derive(Debug)]
164pub struct Chain<'d> {
165 original: Original<'d>,
166 first: usize,
167 end: usize,
168}
169impl<'d> Chain<'d> {
170 #[must_use]
172 pub fn original(&self) -> Original<'d> {
173 self.original
174 }
175 #[must_use]
177 pub fn timestamps(&self) -> core::ops::Range<usize> {
178 self.first..self.end
179 }
180}
181
182#[derive(Debug)]
184pub struct EvidenceRecord<'d> {
185 original: Original<'d>,
186 algorithms: OwnedVec<AlgorithmIdentifier<'d>>,
187 crypto: Option<OwnedVec<Attribute<'d>>>,
188 encryption: Option<EncryptionInfo<'d>>,
189 sequence: Original<'d>,
190 chains: OwnedVec<Chain<'d>>,
191 timestamps: OwnedVec<ArchiveTimeStamp<'d>>,
192}
193impl<'d> EvidenceRecord<'d> {
194 pub fn read(parent: &Reader<'d>, element: &Element<'d>) -> Result<Self> {
196 let mut inside = enter(parent, element, Tag::constructed(universal::SEQUENCE))?;
197 let version = required(&mut inside)?;
198 if version.tag() != Tag::primitive(universal::INTEGER) {
199 return Err(syntax(ErrorCode::UnexpectedTag, version.span()));
200 }
201 let version = inside.integer(&version).map_err(encoding)?;
202 if version.as_u64() != Some(1) {
203 return Err(syntax(ErrorCode::UnsupportedVersion, element.span()));
204 }
205 let set = required(&mut inside)?;
206 let mut members = enter(&inside, &set, Tag::constructed(universal::SEQUENCE))?;
207 let work = parent.execution();
208 let mut algorithms = work.vector();
209 while let Some(member) = members.next_element().map_err(encoding)? {
210 let value = algorithm::read(&members, &member, FIELD).map_err(Error::pkix)?;
211 algorithms
212 .try_push(value)
213 .map_err(|cause| Error::resource(cause, FIELD, member.span().start))?;
214 }
215 if algorithms.is_empty() {
216 return Err(syntax(ErrorCode::MissingField, set.span()));
217 }
218 let mut next = required(&mut inside)?;
219 let crypto = if next.tag() == Tag::context(true, 0) {
220 let values = attributes(&inside, &next, Tag::context(true, 0), false)?;
221 next = required(&mut inside)?;
222 Some(values)
223 } else {
224 None
225 };
226 let encryption = if next.tag() == Tag::context(true, 1) {
227 let mut fields = enter(&inside, &next, Tag::context(true, 1))?;
228 let kind = fields.read_oid().map_err(encoding)?;
229 let value = required(&mut fields)?;
230 finish(&fields)?;
231 let result = EncryptionInfo {
232 kind,
233 value: Original::new(&fields, value),
234 };
235 next = required(&mut inside)?;
236 Some(result)
237 } else {
238 None
239 };
240 let mut sequence = enter(&inside, &next, Tag::constructed(universal::SEQUENCE))?;
241 let mut chains = work.vector();
242 let mut timestamps = work.vector();
243 while let Some(chain) = sequence.next_element().map_err(encoding)? {
244 let mut entries = enter(&sequence, &chain, Tag::constructed(universal::SEQUENCE))?;
245 let first = timestamps.len();
246 while let Some(entry) = entries.next_element().map_err(encoding)? {
247 let value = read_timestamp(&entries, entry)?;
248 timestamps
249 .try_push(value)
250 .map_err(|cause| Error::resource(cause, FIELD, entry.span().start))?;
251 }
252 if first == timestamps.len() {
253 return Err(syntax(ErrorCode::MissingField, chain.span()));
254 }
255 chains
256 .try_push(Chain {
257 original: Original::new(&sequence, chain),
258 first,
259 end: timestamps.len(),
260 })
261 .map_err(|cause| Error::resource(cause, FIELD, chain.span().start))?;
262 }
263 if chains.is_empty() {
264 return Err(syntax(ErrorCode::MissingField, next.span()));
265 }
266 finish(&inside)?;
267 Ok(Self {
268 original: Original::new(parent, *element),
269 algorithms: algorithms.into_owned(),
270 crypto,
271 encryption,
272 sequence: Original::new(&inside, next),
273 chains: chains.into_owned(),
274 timestamps: timestamps.into_owned(),
275 })
276 }
277 #[must_use]
279 pub fn original(&self) -> Original<'d> {
280 self.original
281 }
282 #[must_use]
284 pub fn digest_algorithms(&self) -> &[AlgorithmIdentifier<'d>] {
285 &self.algorithms
286 }
287 #[must_use]
289 pub fn crypto_infos(&self) -> Option<&[Attribute<'d>]> {
290 self.crypto.as_deref()
291 }
292 #[must_use]
294 pub fn encryption_info(&self) -> Option<&EncryptionInfo<'d>> {
295 self.encryption.as_ref()
296 }
297 #[must_use]
299 pub fn sequence(&self) -> Original<'d> {
300 self.sequence
301 }
302 #[must_use]
304 pub fn chains(&self) -> &[Chain<'d>] {
305 &self.chains
306 }
307 #[must_use]
309 pub fn timestamps(&self) -> &[ArchiveTimeStamp<'d>] {
310 &self.timestamps
311 }
312}
313
314fn read_timestamp<'d>(parent: &Reader<'d>, element: Element<'d>) -> Result<ArchiveTimeStamp<'d>> {
315 let mut inside = enter(parent, &element, Tag::constructed(universal::SEQUENCE))?;
316 let mut next = required(&mut inside)?;
317 let algorithm = if next.tag() == Tag::context(true, 0) {
318 let value = algorithm::read_implicit(&inside, &next, 0, FIELD).map_err(Error::pkix)?;
319 next = required(&mut inside)?;
320 Some(value)
321 } else {
322 None
323 };
324 let attributes_span = (next.tag() == Tag::context(true, 1)).then_some(next.span());
325 let attributes = if next.tag() == Tag::context(true, 1) {
326 let values = attributes(&inside, &next, Tag::context(true, 1), true)?;
327 next = required(&mut inside)?;
328 Some(values)
329 } else {
330 None
331 };
332 let tree = if next.tag() == Tag::context(true, 2) {
333 let mut levels = enter(&inside, &next, Tag::context(true, 2))?;
334 let work = parent.execution();
335 let mut tree = work.vector();
336 while let Some(level) = levels.next_element().map_err(encoding)? {
337 let mut entries = enter(&levels, &level, Tag::constructed(universal::SEQUENCE))?;
338 let mut hashes = work.vector();
339 while let Some(hash) = entries.next_element().map_err(encoding)? {
340 let value = Octets::read(&entries, &hash, FIELD)?;
341 hashes
342 .try_push(value)
343 .map_err(|cause| Error::resource(cause, FIELD, hash.span().start))?;
344 }
345 tree.try_push(PartialTree {
348 original: Original::new(&levels, level),
349 hashes: hashes.into_owned(),
350 })
351 .map_err(|cause| Error::resource(cause, FIELD, level.span().start))?;
352 }
353 next = required(&mut inside)?;
354 Some(tree.into_owned())
355 } else {
356 None
357 };
358 let (envelope, source) = ContentInfo::read_element(&inside, &next)?;
359 inside
360 .charge(1 + envelope.kind().as_bytes().len() as u64)
361 .map_err(encoding)?;
362 let token = if envelope.kind() == oid::SIGNED_DATA {
363 TimeStamp::Rfc3161(Token::from_message(
364 SignedData::read_element(&source, envelope.content())?,
365 &source,
366 )?)
367 } else {
368 TimeStamp::Other(Original::new(&inside, next))
369 };
370 finish(&inside)?;
371 Ok(ArchiveTimeStamp {
372 original: Original::new(parent, element),
373 algorithm,
374 attributes,
375 attributes_span,
376 tree,
377 timestamp: Original::new(&inside, next),
378 token,
379 })
380}
381
382fn attributes<'d>(
383 parent: &Reader<'d>,
384 element: &Element<'d>,
385 tag: Tag,
386 sorted: bool,
387) -> Result<OwnedVec<Attribute<'d>>> {
388 let mut inside = enter(parent, element, tag)?;
389 let work = parent.execution();
390 let mut values = work.vector();
391 let mut previous = None;
392 while let Some(entry) = inside.next_element().map_err(encoding)? {
393 if sorted && inside.encoding().is_der() {
396 if let Some(previous) = previous
397 && !structured_pkix::der::set_ordered(&inside, previous, &entry, FIELD)
398 .map_err(Error::pkix)?
399 {
400 return Err(syntax(ErrorCode::SetOrder, entry.span()));
401 }
402 previous = Some(entry.as_bytes());
403 }
404 values
405 .try_push(Attribute::read(&inside, &entry, FIELD)?)
406 .map_err(|cause| Error::resource(cause, FIELD, entry.span().start))?;
407 }
408 if values.is_empty() {
409 return Err(syntax(ErrorCode::EmptyAttributes, element.span()));
410 }
411 Ok(values.into_owned())
412}
413fn enter<'d>(parent: &Reader<'d>, element: &Element<'d>, tag: Tag) -> Result<Reader<'d>> {
414 if element.tag() != tag {
415 return Err(syntax(ErrorCode::UnexpectedTag, element.span()));
416 }
417 parent.enter(element).map_err(encoding)
418}
419fn required<'d>(reader: &mut Reader<'d>) -> Result<Element<'d>> {
420 reader
421 .next_element()
422 .map_err(encoding)?
423 .ok_or_else(|| Error::schema(ErrorCode::MissingField, FIELD, reader.offset()))
424}
425fn finish(reader: &Reader<'_>) -> Result<()> {
426 if reader.is_empty() {
427 Ok(())
428 } else {
429 Err(Error::schema(
430 ErrorCode::TrailingData,
431 FIELD,
432 reader.offset(),
433 ))
434 }
435}
436fn syntax(code: ErrorCode, span: Span) -> Error {
437 Error::schema(code, FIELD, span.start)
438}
439fn encoding(cause: structured_asn1::Error) -> Error {
440 Error::encoding(cause, FIELD)
441}