1use super::{AccuracyReading, MessageImprint, TokenExtensions, TsaReading, record};
4use crate::{Error, ErrorCode, Result};
5use structured_asn1::memory::{OwnedVec, Work};
6use structured_asn1::{Element, Encoding, Integer, Oid, Reader, Span, Tag, universal};
7use structured_pkix::temporal::Reading;
8
9const FIELD: &str = "tstInfo";
10
11#[derive(Debug, Clone, Copy)]
13pub struct IntegerField<'a> {
14 element: Element<'a>,
15 value: Integer<'a>,
16}
17impl<'a> IntegerField<'a> {
18 fn read<W: Work>(
19 parent: &Reader<'a>,
20 element: &Element<'a>,
21 field: &'static str,
22 faults: &mut OwnedVec<Error, W>,
23 ) -> Result<Self> {
24 let (value, fault) = parent
25 .integer_reading(element)
26 .map_err(|error| Error::encoding(error, field))?
27 .into_parts();
28 if let Some(fault) = fault {
29 record(faults, Error::encoding(fault, field))?;
30 }
31 Ok(Self {
32 element: *element,
33 value,
34 })
35 }
36 #[must_use]
38 pub fn element(self) -> Element<'a> {
39 self.element
40 }
41 #[must_use]
43 pub fn value(self) -> Integer<'a> {
44 self.value
45 }
46}
47
48#[derive(Debug)]
51pub struct TokenInfo<'a> {
52 policy: Oid<'a>,
53 imprint: MessageImprint<'a>,
54 serial: IntegerField<'a>,
55 gen_time: Reading,
56 accuracy: Option<AccuracyReading<'a>>,
57 ordering: bool,
58 nonce: Option<IntegerField<'a>>,
59 tsa: Option<TsaReading<'a>>,
60 extensions: Option<TokenExtensions<'a>>,
61 faults: OwnedVec<Error>,
62 span: Span,
63}
64
65impl<'a> TokenInfo<'a> {
66 pub(super) fn read_carried(parent: &mut Reader<'a>) -> Result<Self> {
67 let element = parent
68 .expect(Tag::constructed(universal::SEQUENCE))
69 .map_err(|error| Error::encoding(error, FIELD))?;
70 let info = Self::read(parent, &element)?;
71 if parent.is_empty() {
72 return Ok(info);
73 }
74 info.with_tail(parent)
75 }
76
77 fn with_tail(mut self, parent: &Reader<'_>) -> Result<Self> {
78 let at = parent.offset();
79 let work = parent.execution();
80 let mut faults = self.faults.with_execution(&work).map_err(|_| {
86 Error::pkix(structured_pkix::Error::new(
87 structured_pkix::ErrorCode::ForeignReader,
88 FIELD,
89 at,
90 ))
91 })?;
92 record(
93 &mut faults,
94 Error::schema(ErrorCode::TrailingData, FIELD, at),
95 )?;
96 self.faults = faults.into_owned();
97 Ok(self)
98 }
99
100 pub fn read(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
109 if element.tag() != Tag::constructed(universal::SEQUENCE) {
110 return Err(Error::schema(
111 ErrorCode::UnexpectedTag,
112 FIELD,
113 element.span().start,
114 ));
115 }
116 let execution = parent.execution();
117 let mut faults = execution.vector();
118 distinguished(parent, element, &mut faults)?;
119 let mut inside = parent
120 .enter(element)
121 .map_err(|error| Error::encoding(error, FIELD))?;
122 let mut fields = Fields::default();
123 let mut seen: [Option<Element<'a>>; 10] = [None; 10];
126 let mut last = None;
127 while let Some(element) = inside
128 .next_element()
129 .map_err(|error| Error::encoding(error, FIELD))?
130 {
131 execution
132 .charge_work(1)
133 .map_err(|reason| Error::resource(reason, FIELD, element.span().start))?;
134 let Some(slot) = fields.slot(&inside, &element)? else {
135 if carries(element.tag()) {
136 if !same_duplicate(&inside, &fields, &seen, &element)? {
137 return Err(Error::schema(
138 ErrorCode::DuplicateField,
139 FIELD,
140 element.span().start,
141 ));
142 }
143 record(
144 &mut faults,
145 Error::schema(ErrorCode::DuplicateField, FIELD, element.span().start),
146 )?;
147 } else {
148 record(
149 &mut faults,
150 Error::schema(ErrorCode::UnknownField, FIELD, element.span().start),
151 )?;
152 }
153 continue;
154 };
155 if (slot == Slot::Serial && fields.gen_time.is_some())
156 || (slot == Slot::Nonce && (fields.serial_displaced || fields.gen_time.is_none()))
157 {
158 return Err(Error::schema(
159 ErrorCode::DuplicateField,
160 FIELD,
161 element.span().start,
162 ));
163 }
164 if last.is_some_and(|last| slot < last) {
165 record(
166 &mut faults,
167 Error::schema(ErrorCode::FieldOrder, FIELD, element.span().start),
168 )?;
169 }
170 last = Some(last.map_or(slot, |last| last.max(slot)));
171 fields.read(slot, &inside, &element, &mut faults)?;
172 seen[slot as usize] = Some(element);
173 }
174 fields.finish(element.span(), faults.into_owned())
175 }
176
177 #[must_use]
179 pub fn policy(&self) -> Oid<'a> {
180 self.policy
181 }
182 #[must_use]
184 pub fn imprint(&self) -> &MessageImprint<'a> {
185 &self.imprint
186 }
187 #[must_use]
189 pub fn serial(&self) -> IntegerField<'a> {
190 self.serial
191 }
192 #[must_use]
194 pub fn gen_time(&self) -> Reading {
195 self.gen_time
196 }
197 #[must_use]
199 pub fn accuracy(&self) -> Option<&AccuracyReading<'a>> {
200 self.accuracy.as_ref()
201 }
202 #[must_use]
204 pub fn ordering(&self) -> bool {
205 self.ordering
206 }
207 #[must_use]
209 pub fn nonce(&self) -> Option<IntegerField<'a>> {
210 self.nonce
211 }
212 #[must_use]
214 pub fn tsa(&self) -> Option<&TsaReading<'a>> {
215 self.tsa.as_ref()
216 }
217 #[must_use]
219 pub fn extensions(&self) -> Option<&TokenExtensions<'a>> {
220 self.extensions.as_ref()
221 }
222 #[must_use]
224 pub fn faults(&self) -> &[Error] {
225 &self.faults
226 }
227 #[must_use]
229 pub fn has_faults(&self) -> bool {
230 !self.faults.is_empty()
231 || !self.imprint.faults().is_empty()
232 || self
233 .accuracy
234 .as_ref()
235 .is_some_and(|reading| !reading.faults().is_empty())
236 || self
237 .extensions
238 .as_ref()
239 .is_some_and(|reading| !reading.faults().is_empty())
240 }
241 #[must_use]
243 pub fn span(&self) -> Span {
244 self.span
245 }
246}
247
248fn same_duplicate(
249 parent: &Reader<'_>,
250 fields: &Fields<'_>,
251 seen: &[Option<Element<'_>>; 10],
252 element: &Element<'_>,
253) -> Result<bool> {
254 let execution = parent.execution();
255 let refusal = |reason| Error::resource(reason, FIELD, element.span().start);
256 if element.tag() == Tag::primitive(universal::OID)
257 && let Some(policy) = fields.policy
258 {
259 let other = parent
263 .oid(element)
264 .map_err(|error| Error::encoding(error, "tstInfo.policy"))?;
265 execution.charge_work(1).map_err(refusal)?;
266 if policy.as_bytes().len() != other.as_bytes().len() {
267 return Ok(false);
268 }
269 execution
270 .charge_work(policy.as_bytes().len() as u64)
271 .map_err(refusal)?;
272 return Ok(policy.as_bytes() == other.as_bytes());
273 }
274 let applicable = if element.tag() == Tag::primitive(universal::INTEGER) {
279 &seen[Slot::Nonce as usize..=Slot::Nonce as usize]
280 } else {
281 &seen[..]
282 };
283 for prior in applicable.iter().flatten() {
284 execution.charge_work(1).map_err(refusal)?;
285 if prior.as_bytes().len() != element.as_bytes().len() {
286 continue;
287 }
288 execution
289 .charge_work(element.as_bytes().len() as u64)
290 .map_err(refusal)?;
291 if prior.as_bytes() == element.as_bytes() {
292 return Ok(true);
293 }
294 }
295 Ok(false)
296}
297
298#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
299#[repr(usize)]
300enum Slot {
301 Version,
302 Policy,
303 Imprint,
304 Serial,
305 GenTime,
306 Accuracy,
307 Ordering,
308 Nonce,
309 Tsa,
310 Extensions,
311}
312
313#[derive(Default)]
314struct Fields<'a> {
315 version: bool,
316 policy: Option<Oid<'a>>,
317 imprint: Option<MessageImprint<'a>>,
318 serial: Option<IntegerField<'a>>,
319 serial_displaced: bool,
320 gen_time: Option<Reading>,
321 accuracy: Option<AccuracyReading<'a>>,
322 ordering: Option<bool>,
323 nonce: Option<IntegerField<'a>>,
324 tsa: Option<TsaReading<'a>>,
325 extensions: Option<TokenExtensions<'a>>,
326}
327
328impl<'a> Fields<'a> {
329 fn slot(&self, parent: &Reader<'a>, element: &Element<'a>) -> Result<Option<Slot>> {
330 let tag = element.tag();
331 let slot = if tag == Tag::primitive(universal::INTEGER) {
332 if !self.version {
333 if self.policy.is_some() || self.imprint.is_some() || self.gen_time.is_some() {
339 return Err(Error::schema(
340 ErrorCode::DuplicateField,
341 FIELD,
342 element.span().start,
343 ));
344 }
345 Slot::Version
346 } else if self.serial.is_none() {
347 Slot::Serial
348 } else if self.nonce.is_none() {
349 Slot::Nonce
350 } else {
351 return Ok(None);
352 }
353 } else if tag == Tag::primitive(universal::OID) {
354 Slot::Policy
355 } else if tag == Tag::constructed(universal::SEQUENCE) {
356 let mut probe = parent
357 .enter(element)
358 .map_err(|error| Error::encoding(error, FIELD))?;
359 let first = probe
360 .next_element()
361 .map_err(|error| Error::encoding(error, FIELD))?;
362 if first.is_some_and(|first| {
365 first.tag() == Tag::constructed(universal::SEQUENCE)
366 || first.tag() == Tag::primitive(universal::OID)
367 }) {
368 Slot::Imprint
369 } else {
370 Slot::Accuracy
371 }
372 } else if tag == Tag::primitive(universal::GENERALIZED_TIME)
373 || tag == Tag::constructed(universal::GENERALIZED_TIME)
374 {
375 Slot::GenTime
376 } else if tag == Tag::primitive(universal::BOOLEAN) {
377 Slot::Ordering
378 } else if tag == Tag::context(true, 0) {
379 Slot::Tsa
380 } else if tag == Tag::context(true, 1) {
381 Slot::Extensions
382 } else {
383 return Ok(None);
384 };
385 let found = match slot {
386 Slot::Version => self.version,
387 Slot::Policy => self.policy.is_some(),
388 Slot::Imprint => self.imprint.is_some(),
389 Slot::Serial => self.serial.is_some(),
390 Slot::GenTime => self.gen_time.is_some(),
391 Slot::Accuracy => self.accuracy.is_some(),
392 Slot::Ordering => self.ordering.is_some(),
393 Slot::Nonce => self.nonce.is_some(),
394 Slot::Tsa => self.tsa.is_some(),
395 Slot::Extensions => self.extensions.is_some(),
396 };
397 Ok(if found { None } else { Some(slot) })
398 }
399
400 fn read<W: Work>(
401 &mut self,
402 slot: Slot,
403 parent: &Reader<'a>,
404 element: &Element<'a>,
405 faults: &mut OwnedVec<Error, W>,
406 ) -> Result<()> {
407 match slot {
408 Slot::Version => {
409 let version = IntegerField::read(parent, element, "tstInfo.version", faults)?;
410 if version.value.as_u64() != Some(1) {
411 return Err(Error::schema(
412 ErrorCode::UnsupportedVersion,
413 "tstInfo.version",
414 element.span().start,
415 ));
416 }
417 self.version = true;
418 }
419 Slot::Policy => {
420 self.policy = Some(
421 parent
422 .oid(element)
423 .map_err(|error| Error::encoding(error, "tstInfo.policy"))?,
424 );
425 }
426 Slot::Imprint => self.imprint = Some(MessageImprint::read(parent, element)?),
427 Slot::Serial => {
428 let serial = IntegerField::read(parent, element, "tstInfo.serialNumber", faults)?;
429 if self.imprint.is_none() && serial.value.as_u64() == Some(1) {
434 return Err(Error::schema(
435 ErrorCode::DuplicateField,
436 FIELD,
437 element.span().start,
438 ));
439 }
440 self.serial_displaced = self.imprint.is_none() || self.gen_time.is_some();
441 self.serial = Some(serial);
442 }
443 Slot::GenTime => {
444 self.gen_time = Some(
445 structured_pkix::temporal::read_generalized(parent, element, "tstInfo.genTime")
446 .map_err(Error::pkix)?,
447 );
448 }
449 Slot::Accuracy => self.accuracy = Some(AccuracyReading::read(parent, element)?),
450 Slot::Ordering => {
451 let ordering = parent
452 .boolean(element)
453 .map_err(|error| Error::encoding(error, "tstInfo.ordering"))?;
454 if !ordering {
455 record(
456 faults,
457 Error::schema(
458 ErrorCode::DefaultWritten,
459 "tstInfo.ordering",
460 element.span().start,
461 ),
462 )?;
463 }
464 self.ordering = Some(ordering);
465 }
466 Slot::Nonce => {
467 self.nonce = Some(IntegerField::read(
468 parent,
469 element,
470 "tstInfo.nonce",
471 faults,
472 )?);
473 }
474 Slot::Tsa => self.tsa = Some(TsaReading::read(parent, element, faults)?),
475 Slot::Extensions => self.extensions = Some(TokenExtensions::read(parent, element)?),
476 }
477 Ok(())
478 }
479
480 fn finish(self, span: Span, faults: OwnedVec<Error>) -> Result<TokenInfo<'a>> {
481 let missing = |field| Error::schema(ErrorCode::MissingField, field, span.start);
482 if !self.version {
483 return Err(missing("tstInfo.version"));
484 }
485 Ok(TokenInfo {
486 policy: self.policy.ok_or_else(|| missing("tstInfo.policy"))?,
487 imprint: self
488 .imprint
489 .ok_or_else(|| missing("tstInfo.messageImprint"))?,
490 serial: self.serial.ok_or_else(|| missing("tstInfo.serialNumber"))?,
491 gen_time: self.gen_time.ok_or_else(|| missing("tstInfo.genTime"))?,
492 accuracy: self.accuracy,
493 ordering: self.ordering.unwrap_or(false),
494 nonce: self.nonce,
495 tsa: self.tsa,
496 extensions: self.extensions,
497 faults,
498 span,
499 })
500 }
501}
502
503fn carries(tag: Tag) -> bool {
504 tag == Tag::primitive(universal::INTEGER)
505 || tag == Tag::primitive(universal::OID)
506 || tag == Tag::constructed(universal::SEQUENCE)
507 || tag == Tag::primitive(universal::GENERALIZED_TIME)
508 || tag == Tag::constructed(universal::GENERALIZED_TIME)
509 || tag == Tag::primitive(universal::BOOLEAN)
510 || tag == Tag::context(true, 0)
511 || tag == Tag::context(true, 1)
512}
513
514fn distinguished<W: Work>(
515 parent: &Reader<'_>,
516 element: &Element<'_>,
517 faults: &mut OwnedVec<Error, W>,
518) -> Result<()> {
519 let mut strict = parent
520 .reread(element, Encoding::Der)
521 .map_err(|error| Error::encoding(error, FIELD))?;
522 let result = strict
523 .expect(element.tag())
524 .map_err(|error| Error::encoding(error, FIELD))
525 .and_then(|again| {
526 structured_pkix::der::conforms(&strict, &again, FIELD).map_err(Error::pkix)
527 });
528 match result {
529 Ok(()) => Ok(()),
530 Err(error) => record(faults, error),
531 }
532}
533
534#[cfg(test)]
535mod tail_tests {
536 use super::*;
537 use alloc::sync::Arc;
538 use structured_asn1::{
539 Parser,
540 memory::{Memory, MemoryAccount, MemoryError},
541 };
542
543 fn carried_bytes() -> [u8; 42] {
544 [
545 0x30, 37, 2, 1, 1, 6, 1, 43, 0x30, 9, 0x30, 3, 6, 1, 42, 4, 2, b'a', b'b', 2, 1, 7,
546 0x18, 15, b'2', b'0', b'2', b'6', b'0', b'1', b'0', b'1', b'0', b'0', b'0', b'0', b'0',
547 b'0', b'Z', 0xff, 0xfe, 0xfd,
548 ]
549 }
550
551 #[test]
552 fn tail_capacity_refusal_rolls_back_without_funding_a_successful_reading() {
553 let bytes = carried_bytes();
556 let memory = Memory::new(Arc::new(MemoryAccount::new(65_536, 1_000_000)));
557 let parser = Parser::ber(memory.clone());
558 let mut parent = parser.read(&bytes, 70).unwrap();
559 let element = parent
560 .expect(Tag::constructed(universal::SEQUENCE))
561 .unwrap();
562 let info = TokenInfo::read(&parent, &element).unwrap();
563 assert_eq!(info.faults().len(), 0);
564 let mut held = memory.vector::<u8>();
565 held.try_reserve_exact(memory.limit() - memory.used())
566 .unwrap();
567 assert_eq!(memory.used(), memory.limit());
568 let error = info.with_tail(&parent).unwrap_err();
569 assert!(error.is_terminal());
570 assert_eq!(error.offset(), 109);
571 assert_eq!(error.field(), "tstInfo");
572 assert_eq!(
573 error.code(),
574 ErrorCode::Encoding(structured_asn1::ErrorCode::from(MemoryError::LimitExceeded))
575 );
576 drop(error);
577 drop(held);
578 assert_eq!(memory.used(), 0);
579 }
580
581 #[test]
582 fn retained_tail_diagnostic_keeps_charge_after_original_parser_drops() {
583 let bytes = carried_bytes();
586 let memory = Memory::new(Arc::new(MemoryAccount::new(65_536, 1_000_000)));
587 let faults = {
588 let parser = Parser::ber(memory.clone());
589 let mut reader = parser.read(&bytes, 70).unwrap();
590 let TokenInfo { faults, .. } = TokenInfo::read_carried(&mut reader).unwrap();
591 faults
592 };
593 assert_eq!(faults.len(), 1);
594 assert_eq!(faults[0].code(), ErrorCode::TrailingData);
595 assert_eq!(faults[0].offset(), 109);
596 assert_eq!(faults[0].field(), "tstInfo");
597 assert!(memory.used() >= core::mem::size_of::<Error>());
598 drop(faults);
599 assert_eq!(memory.used(), 0);
600 }
601}