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