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: structured_pkix::temporal::ExactReading,
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.reading()
196 }
197 pub(super) fn precise_gen_time(&self) -> &structured_pkix::temporal::ExactReading {
198 &self.gen_time
199 }
200 #[must_use]
202 pub fn accuracy(&self) -> Option<&AccuracyReading<'a>> {
203 self.accuracy.as_ref()
204 }
205 #[must_use]
207 pub fn ordering(&self) -> bool {
208 self.ordering
209 }
210 #[must_use]
212 pub fn nonce(&self) -> Option<IntegerField<'a>> {
213 self.nonce
214 }
215 #[must_use]
217 pub fn tsa(&self) -> Option<&TsaReading<'a>> {
218 self.tsa.as_ref()
219 }
220 #[must_use]
222 pub fn extensions(&self) -> Option<&TokenExtensions<'a>> {
223 self.extensions.as_ref()
224 }
225 #[must_use]
227 pub fn faults(&self) -> &[Error] {
228 &self.faults
229 }
230 #[must_use]
232 pub fn has_faults(&self) -> bool {
233 !self.faults.is_empty()
234 || !self.imprint.faults().is_empty()
235 || self
236 .accuracy
237 .as_ref()
238 .is_some_and(|reading| !reading.faults().is_empty())
239 || self
240 .extensions
241 .as_ref()
242 .is_some_and(|reading| !reading.faults().is_empty())
243 }
244 #[must_use]
246 pub fn span(&self) -> Span {
247 self.span
248 }
249}
250
251fn same_duplicate(
252 parent: &Reader<'_>,
253 fields: &Fields<'_>,
254 seen: &[Option<Element<'_>>; 10],
255 element: &Element<'_>,
256) -> Result<bool> {
257 let execution = parent.execution();
258 let refusal = |reason| Error::resource(reason, FIELD, element.span().start);
259 if element.tag() == Tag::primitive(universal::OID)
260 && let Some(policy) = fields.policy
261 {
262 let other = parent
266 .oid(element)
267 .map_err(|error| Error::encoding(error, "tstInfo.policy"))?;
268 execution.charge_work(1).map_err(refusal)?;
269 if policy.as_bytes().len() != other.as_bytes().len() {
270 return Ok(false);
271 }
272 execution
273 .charge_work(policy.as_bytes().len() as u64)
274 .map_err(refusal)?;
275 return Ok(policy.as_bytes() == other.as_bytes());
276 }
277 let applicable = if element.tag() == Tag::primitive(universal::INTEGER) {
282 &seen[Slot::Nonce as usize..=Slot::Nonce as usize]
283 } else {
284 &seen[..]
285 };
286 for prior in applicable.iter().flatten() {
287 execution.charge_work(1).map_err(refusal)?;
288 if prior.as_bytes().len() != element.as_bytes().len() {
289 continue;
290 }
291 execution
292 .charge_work(element.as_bytes().len() as u64)
293 .map_err(refusal)?;
294 if prior.as_bytes() == element.as_bytes() {
295 return Ok(true);
296 }
297 }
298 Ok(false)
299}
300
301#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
302#[repr(usize)]
303enum Slot {
304 Version,
305 Policy,
306 Imprint,
307 Serial,
308 GenTime,
309 Accuracy,
310 Ordering,
311 Nonce,
312 Tsa,
313 Extensions,
314}
315
316#[derive(Default)]
317struct Fields<'a> {
318 version: bool,
319 policy: Option<Oid<'a>>,
320 imprint: Option<MessageImprint<'a>>,
321 serial: Option<IntegerField<'a>>,
322 serial_displaced: bool,
323 gen_time: Option<structured_pkix::temporal::ExactReading>,
324 accuracy: Option<AccuracyReading<'a>>,
325 ordering: Option<bool>,
326 nonce: Option<IntegerField<'a>>,
327 tsa: Option<TsaReading<'a>>,
328 extensions: Option<TokenExtensions<'a>>,
329}
330
331impl<'a> Fields<'a> {
332 fn slot(&self, parent: &Reader<'a>, element: &Element<'a>) -> Result<Option<Slot>> {
333 let tag = element.tag();
334 let slot = if tag == Tag::primitive(universal::INTEGER) {
335 if !self.version {
336 if self.policy.is_some() || self.imprint.is_some() || self.gen_time.is_some() {
342 return Err(Error::schema(
343 ErrorCode::DuplicateField,
344 FIELD,
345 element.span().start,
346 ));
347 }
348 Slot::Version
349 } else if self.serial.is_none() {
350 Slot::Serial
351 } else if self.nonce.is_none() {
352 Slot::Nonce
353 } else {
354 return Ok(None);
355 }
356 } else if tag == Tag::primitive(universal::OID) {
357 Slot::Policy
358 } else if tag == Tag::constructed(universal::SEQUENCE) {
359 let mut probe = parent
360 .enter(element)
361 .map_err(|error| Error::encoding(error, FIELD))?;
362 let first = probe
363 .next_element()
364 .map_err(|error| Error::encoding(error, FIELD))?;
365 if first.is_some_and(|first| {
368 first.tag() == Tag::constructed(universal::SEQUENCE)
369 || first.tag() == Tag::primitive(universal::OID)
370 }) {
371 Slot::Imprint
372 } else {
373 Slot::Accuracy
374 }
375 } else if tag == Tag::primitive(universal::GENERALIZED_TIME)
376 || tag == Tag::constructed(universal::GENERALIZED_TIME)
377 {
378 Slot::GenTime
379 } else if tag == Tag::primitive(universal::BOOLEAN) {
380 Slot::Ordering
381 } else if tag == Tag::context(true, 0) {
382 Slot::Tsa
383 } else if tag == Tag::context(true, 1) {
384 Slot::Extensions
385 } else {
386 return Ok(None);
387 };
388 let found = match slot {
389 Slot::Version => self.version,
390 Slot::Policy => self.policy.is_some(),
391 Slot::Imprint => self.imprint.is_some(),
392 Slot::Serial => self.serial.is_some(),
393 Slot::GenTime => self.gen_time.is_some(),
394 Slot::Accuracy => self.accuracy.is_some(),
395 Slot::Ordering => self.ordering.is_some(),
396 Slot::Nonce => self.nonce.is_some(),
397 Slot::Tsa => self.tsa.is_some(),
398 Slot::Extensions => self.extensions.is_some(),
399 };
400 Ok(if found { None } else { Some(slot) })
401 }
402
403 fn read<W: Work>(
404 &mut self,
405 slot: Slot,
406 parent: &Reader<'a>,
407 element: &Element<'a>,
408 faults: &mut OwnedVec<Error, W>,
409 ) -> Result<()> {
410 match slot {
411 Slot::Version => {
412 let version = IntegerField::read(parent, element, "tstInfo.version", faults)?;
413 if version.value.as_u64() != Some(1) {
414 return Err(Error::schema(
415 ErrorCode::UnsupportedVersion,
416 "tstInfo.version",
417 element.span().start,
418 ));
419 }
420 self.version = true;
421 }
422 Slot::Policy => {
423 self.policy = Some(
424 parent
425 .oid(element)
426 .map_err(|error| Error::encoding(error, "tstInfo.policy"))?,
427 );
428 }
429 Slot::Imprint => self.imprint = Some(MessageImprint::read(parent, element)?),
430 Slot::Serial => {
431 let serial = IntegerField::read(parent, element, "tstInfo.serialNumber", faults)?;
432 if self.imprint.is_none() && serial.value.as_u64() == Some(1) {
437 return Err(Error::schema(
438 ErrorCode::DuplicateField,
439 FIELD,
440 element.span().start,
441 ));
442 }
443 self.serial_displaced = self.imprint.is_none() || self.gen_time.is_some();
444 self.serial = Some(serial);
445 }
446 Slot::GenTime => {
447 self.gen_time = Some(
448 structured_pkix::temporal::read_generalized_exact(
449 parent,
450 element,
451 "tstInfo.genTime",
452 )
453 .map_err(Error::pkix)?,
454 );
455 }
456 Slot::Accuracy => self.accuracy = Some(AccuracyReading::read(parent, element)?),
457 Slot::Ordering => {
458 let ordering = parent
459 .boolean(element)
460 .map_err(|error| Error::encoding(error, "tstInfo.ordering"))?;
461 if !ordering {
462 record(
463 faults,
464 Error::schema(
465 ErrorCode::DefaultWritten,
466 "tstInfo.ordering",
467 element.span().start,
468 ),
469 )?;
470 }
471 self.ordering = Some(ordering);
472 }
473 Slot::Nonce => {
474 self.nonce = Some(IntegerField::read(
475 parent,
476 element,
477 "tstInfo.nonce",
478 faults,
479 )?);
480 }
481 Slot::Tsa => self.tsa = Some(TsaReading::read(parent, element, faults)?),
482 Slot::Extensions => self.extensions = Some(TokenExtensions::read(parent, element)?),
483 }
484 Ok(())
485 }
486
487 fn finish(self, span: Span, faults: OwnedVec<Error>) -> Result<TokenInfo<'a>> {
488 let missing = |field| Error::schema(ErrorCode::MissingField, field, span.start);
489 if !self.version {
490 return Err(missing("tstInfo.version"));
491 }
492 Ok(TokenInfo {
493 policy: self.policy.ok_or_else(|| missing("tstInfo.policy"))?,
494 imprint: self
495 .imprint
496 .ok_or_else(|| missing("tstInfo.messageImprint"))?,
497 serial: self.serial.ok_or_else(|| missing("tstInfo.serialNumber"))?,
498 gen_time: self.gen_time.ok_or_else(|| missing("tstInfo.genTime"))?,
499 accuracy: self.accuracy,
500 ordering: self.ordering.unwrap_or(false),
501 nonce: self.nonce,
502 tsa: self.tsa,
503 extensions: self.extensions,
504 faults,
505 span,
506 })
507 }
508}
509
510fn carries(tag: Tag) -> bool {
511 tag == Tag::primitive(universal::INTEGER)
512 || tag == Tag::primitive(universal::OID)
513 || tag == Tag::constructed(universal::SEQUENCE)
514 || tag == Tag::primitive(universal::GENERALIZED_TIME)
515 || tag == Tag::constructed(universal::GENERALIZED_TIME)
516 || tag == Tag::primitive(universal::BOOLEAN)
517 || tag == Tag::context(true, 0)
518 || tag == Tag::context(true, 1)
519}
520
521fn distinguished<W: Work>(
522 parent: &Reader<'_>,
523 element: &Element<'_>,
524 faults: &mut OwnedVec<Error, W>,
525) -> Result<()> {
526 let mut strict = parent
527 .reread(element, Encoding::Der)
528 .map_err(|error| Error::encoding(error, FIELD))?;
529 let result = strict
530 .expect(element.tag())
531 .map_err(|error| Error::encoding(error, FIELD))
532 .and_then(|again| {
533 structured_pkix::der::conforms(&strict, &again, FIELD).map_err(Error::pkix)
534 });
535 match result {
536 Ok(()) => Ok(()),
537 Err(error) => record(faults, error),
538 }
539}
540
541#[cfg(test)]
542mod tail_tests {
543 use super::*;
544 use alloc::sync::Arc;
545 use structured_asn1::{
546 Parser,
547 memory::{Memory, MemoryAccount, MemoryError},
548 };
549
550 fn carried_bytes() -> [u8; 42] {
551 [
552 0x30, 37, 2, 1, 1, 6, 1, 43, 0x30, 9, 0x30, 3, 6, 1, 42, 4, 2, b'a', b'b', 2, 1, 7,
553 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',
554 b'0', b'Z', 0xff, 0xfe, 0xfd,
555 ]
556 }
557
558 #[test]
559 fn tail_capacity_refusal_rolls_back_without_funding_a_successful_reading() {
560 let bytes = carried_bytes();
563 let memory = Memory::new(Arc::new(MemoryAccount::new(65_536, 1_000_000)));
564 let parser = Parser::ber(memory.clone());
565 let mut parent = parser.read(&bytes, 70).unwrap();
566 let element = parent
567 .expect(Tag::constructed(universal::SEQUENCE))
568 .unwrap();
569 let info = TokenInfo::read(&parent, &element).unwrap();
570 assert_eq!(info.faults().len(), 0);
571 let mut held = memory.vector::<u8>();
572 held.try_reserve_exact(memory.limit() - memory.used())
573 .unwrap();
574 assert_eq!(memory.used(), memory.limit());
575 let error = info.with_tail(&parent).unwrap_err();
576 assert!(error.is_terminal());
577 assert_eq!(error.offset(), 109);
578 assert_eq!(error.field(), "tstInfo");
579 assert_eq!(
580 error.code(),
581 ErrorCode::Encoding(structured_asn1::ErrorCode::from(MemoryError::LimitExceeded))
582 );
583 drop(error);
584 drop(held);
585 assert_eq!(memory.used(), 0);
586 }
587
588 #[test]
589 fn retained_tail_diagnostic_keeps_charge_after_original_parser_drops() {
590 let bytes = carried_bytes();
593 let memory = Memory::new(Arc::new(MemoryAccount::new(65_536, 1_000_000)));
594 let faults = {
595 let parser = Parser::ber(memory.clone());
596 let mut reader = parser.read(&bytes, 70).unwrap();
597 let TokenInfo { faults, .. } = TokenInfo::read_carried(&mut reader).unwrap();
598 faults
599 };
600 assert_eq!(faults.len(), 1);
601 assert_eq!(faults[0].code(), ErrorCode::TrailingData);
602 assert_eq!(faults[0].offset(), 109);
603 assert_eq!(faults[0].field(), "tstInfo");
604 assert!(memory.used() >= core::mem::size_of::<Error>());
605 drop(faults);
606 assert_eq!(memory.used(), 0);
607 }
608}