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 fn read(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
75 if element.tag() != Tag::constructed(universal::SEQUENCE) {
76 return Err(Error::schema(
77 ErrorCode::UnexpectedTag,
78 FIELD,
79 element.span().start,
80 ));
81 }
82 let execution = parent.execution();
83 let mut faults = execution.vector();
84 distinguished(parent, element, &mut faults)?;
85 let mut inside = parent
86 .enter(element)
87 .map_err(|error| Error::encoding(error, FIELD))?;
88 let mut fields = Fields::default();
89 let mut seen: [Option<Element<'a>>; 10] = [None; 10];
92 let mut last = None;
93 while let Some(element) = inside
94 .next_element()
95 .map_err(|error| Error::encoding(error, FIELD))?
96 {
97 execution
98 .charge_work(1)
99 .map_err(|reason| Error::resource(reason, FIELD, element.span().start))?;
100 let Some(slot) = fields.slot(&inside, &element)? else {
101 if carries(element.tag()) {
102 if !same_duplicate(&inside, &fields, &seen, &element)? {
103 return Err(Error::schema(
104 ErrorCode::DuplicateField,
105 FIELD,
106 element.span().start,
107 ));
108 }
109 record(
110 &mut faults,
111 Error::schema(ErrorCode::DuplicateField, FIELD, element.span().start),
112 )?;
113 } else {
114 record(
115 &mut faults,
116 Error::schema(ErrorCode::UnknownField, FIELD, element.span().start),
117 )?;
118 }
119 continue;
120 };
121 if (slot == Slot::Serial && fields.gen_time.is_some())
122 || (slot == Slot::Nonce && (fields.serial_displaced || fields.gen_time.is_none()))
123 {
124 return Err(Error::schema(
125 ErrorCode::DuplicateField,
126 FIELD,
127 element.span().start,
128 ));
129 }
130 if last.is_some_and(|last| slot < last) {
131 record(
132 &mut faults,
133 Error::schema(ErrorCode::FieldOrder, FIELD, element.span().start),
134 )?;
135 }
136 last = Some(last.map_or(slot, |last| last.max(slot)));
137 fields.read(slot, &inside, &element, &mut faults)?;
138 seen[slot as usize] = Some(element);
139 }
140 fields.finish(element.span(), faults.into_owned())
141 }
142
143 #[must_use]
145 pub fn policy(&self) -> Oid<'a> {
146 self.policy
147 }
148 #[must_use]
150 pub fn imprint(&self) -> &MessageImprint<'a> {
151 &self.imprint
152 }
153 #[must_use]
155 pub fn serial(&self) -> IntegerField<'a> {
156 self.serial
157 }
158 #[must_use]
160 pub fn gen_time(&self) -> Reading {
161 self.gen_time
162 }
163 #[must_use]
165 pub fn accuracy(&self) -> Option<&AccuracyReading<'a>> {
166 self.accuracy.as_ref()
167 }
168 #[must_use]
170 pub fn ordering(&self) -> bool {
171 self.ordering
172 }
173 #[must_use]
175 pub fn nonce(&self) -> Option<IntegerField<'a>> {
176 self.nonce
177 }
178 #[must_use]
180 pub fn tsa(&self) -> Option<&TsaReading<'a>> {
181 self.tsa.as_ref()
182 }
183 #[must_use]
185 pub fn extensions(&self) -> Option<&TokenExtensions<'a>> {
186 self.extensions.as_ref()
187 }
188 #[must_use]
190 pub fn faults(&self) -> &[Error] {
191 &self.faults
192 }
193 #[must_use]
195 pub fn has_faults(&self) -> bool {
196 !self.faults.is_empty()
197 || !self.imprint.faults().is_empty()
198 || self
199 .accuracy
200 .as_ref()
201 .is_some_and(|reading| !reading.faults().is_empty())
202 || self
203 .extensions
204 .as_ref()
205 .is_some_and(|reading| !reading.faults().is_empty())
206 }
207 #[must_use]
209 pub fn span(&self) -> Span {
210 self.span
211 }
212}
213
214fn same_duplicate(
215 parent: &Reader<'_>,
216 fields: &Fields<'_>,
217 seen: &[Option<Element<'_>>; 10],
218 element: &Element<'_>,
219) -> Result<bool> {
220 let execution = parent.execution();
221 let refusal = |reason| Error::resource(reason, FIELD, element.span().start);
222 if element.tag() == Tag::primitive(universal::OID)
223 && let Some(policy) = fields.policy
224 {
225 let other = parent
229 .oid(element)
230 .map_err(|error| Error::encoding(error, "tstInfo.policy"))?;
231 execution.charge_work(1).map_err(refusal)?;
232 if policy.as_bytes().len() != other.as_bytes().len() {
233 return Ok(false);
234 }
235 execution
236 .charge_work(policy.as_bytes().len() as u64)
237 .map_err(refusal)?;
238 return Ok(policy.as_bytes() == other.as_bytes());
239 }
240 let applicable = if element.tag() == Tag::primitive(universal::INTEGER) {
245 &seen[Slot::Nonce as usize..=Slot::Nonce as usize]
246 } else {
247 &seen[..]
248 };
249 for prior in applicable.iter().flatten() {
250 execution.charge_work(1).map_err(refusal)?;
251 if prior.as_bytes().len() != element.as_bytes().len() {
252 continue;
253 }
254 execution
255 .charge_work(element.as_bytes().len() as u64)
256 .map_err(refusal)?;
257 if prior.as_bytes() == element.as_bytes() {
258 return Ok(true);
259 }
260 }
261 Ok(false)
262}
263
264#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
265#[repr(usize)]
266enum Slot {
267 Version,
268 Policy,
269 Imprint,
270 Serial,
271 GenTime,
272 Accuracy,
273 Ordering,
274 Nonce,
275 Tsa,
276 Extensions,
277}
278
279#[derive(Default)]
280struct Fields<'a> {
281 version: bool,
282 policy: Option<Oid<'a>>,
283 imprint: Option<MessageImprint<'a>>,
284 serial: Option<IntegerField<'a>>,
285 serial_displaced: bool,
286 gen_time: Option<Reading>,
287 accuracy: Option<AccuracyReading<'a>>,
288 ordering: Option<bool>,
289 nonce: Option<IntegerField<'a>>,
290 tsa: Option<TsaReading<'a>>,
291 extensions: Option<TokenExtensions<'a>>,
292}
293
294impl<'a> Fields<'a> {
295 fn slot(&self, parent: &Reader<'a>, element: &Element<'a>) -> Result<Option<Slot>> {
296 let tag = element.tag();
297 let slot = if tag == Tag::primitive(universal::INTEGER) {
298 if !self.version {
299 if self.policy.is_some() || self.imprint.is_some() || self.gen_time.is_some() {
305 return Err(Error::schema(
306 ErrorCode::DuplicateField,
307 FIELD,
308 element.span().start,
309 ));
310 }
311 Slot::Version
312 } else if self.serial.is_none() {
313 Slot::Serial
314 } else if self.nonce.is_none() {
315 Slot::Nonce
316 } else {
317 return Ok(None);
318 }
319 } else if tag == Tag::primitive(universal::OID) {
320 Slot::Policy
321 } else if tag == Tag::constructed(universal::SEQUENCE) {
322 let mut probe = parent
323 .enter(element)
324 .map_err(|error| Error::encoding(error, FIELD))?;
325 let first = probe
326 .next_element()
327 .map_err(|error| Error::encoding(error, FIELD))?;
328 if first.is_some_and(|first| {
331 first.tag() == Tag::constructed(universal::SEQUENCE)
332 || first.tag() == Tag::primitive(universal::OID)
333 }) {
334 Slot::Imprint
335 } else {
336 Slot::Accuracy
337 }
338 } else if tag == Tag::primitive(universal::GENERALIZED_TIME)
339 || tag == Tag::constructed(universal::GENERALIZED_TIME)
340 {
341 Slot::GenTime
342 } else if tag == Tag::primitive(universal::BOOLEAN) {
343 Slot::Ordering
344 } else if tag == Tag::context(true, 0) {
345 Slot::Tsa
346 } else if tag == Tag::context(true, 1) {
347 Slot::Extensions
348 } else {
349 return Ok(None);
350 };
351 let found = match slot {
352 Slot::Version => self.version,
353 Slot::Policy => self.policy.is_some(),
354 Slot::Imprint => self.imprint.is_some(),
355 Slot::Serial => self.serial.is_some(),
356 Slot::GenTime => self.gen_time.is_some(),
357 Slot::Accuracy => self.accuracy.is_some(),
358 Slot::Ordering => self.ordering.is_some(),
359 Slot::Nonce => self.nonce.is_some(),
360 Slot::Tsa => self.tsa.is_some(),
361 Slot::Extensions => self.extensions.is_some(),
362 };
363 Ok(if found { None } else { Some(slot) })
364 }
365
366 fn read<W: Work>(
367 &mut self,
368 slot: Slot,
369 parent: &Reader<'a>,
370 element: &Element<'a>,
371 faults: &mut OwnedVec<Error, W>,
372 ) -> Result<()> {
373 match slot {
374 Slot::Version => {
375 let version = IntegerField::read(parent, element, "tstInfo.version", faults)?;
376 if version.value.as_u64() != Some(1) {
377 return Err(Error::schema(
378 ErrorCode::UnsupportedVersion,
379 "tstInfo.version",
380 element.span().start,
381 ));
382 }
383 self.version = true;
384 }
385 Slot::Policy => {
386 self.policy = Some(
387 parent
388 .oid(element)
389 .map_err(|error| Error::encoding(error, "tstInfo.policy"))?,
390 );
391 }
392 Slot::Imprint => self.imprint = Some(MessageImprint::read(parent, element)?),
393 Slot::Serial => {
394 self.serial_displaced = self.imprint.is_none() || self.gen_time.is_some();
395 self.serial = Some(IntegerField::read(
396 parent,
397 element,
398 "tstInfo.serialNumber",
399 faults,
400 )?);
401 }
402 Slot::GenTime => {
403 self.gen_time = Some(
404 structured_pkix::temporal::read_generalized(parent, element, "tstInfo.genTime")
405 .map_err(Error::pkix)?,
406 );
407 }
408 Slot::Accuracy => self.accuracy = Some(AccuracyReading::read(parent, element)?),
409 Slot::Ordering => {
410 let ordering = parent
411 .boolean(element)
412 .map_err(|error| Error::encoding(error, "tstInfo.ordering"))?;
413 if !ordering {
414 record(
415 faults,
416 Error::schema(
417 ErrorCode::DefaultWritten,
418 "tstInfo.ordering",
419 element.span().start,
420 ),
421 )?;
422 }
423 self.ordering = Some(ordering);
424 }
425 Slot::Nonce => {
426 self.nonce = Some(IntegerField::read(
427 parent,
428 element,
429 "tstInfo.nonce",
430 faults,
431 )?);
432 }
433 Slot::Tsa => self.tsa = Some(TsaReading::read(parent, element, faults)?),
434 Slot::Extensions => self.extensions = Some(TokenExtensions::read(parent, element)?),
435 }
436 Ok(())
437 }
438
439 fn finish(self, span: Span, faults: OwnedVec<Error>) -> Result<TokenInfo<'a>> {
440 let missing = |field| Error::schema(ErrorCode::MissingField, field, span.start);
441 if !self.version {
442 return Err(missing("tstInfo.version"));
443 }
444 Ok(TokenInfo {
445 policy: self.policy.ok_or_else(|| missing("tstInfo.policy"))?,
446 imprint: self
447 .imprint
448 .ok_or_else(|| missing("tstInfo.messageImprint"))?,
449 serial: self.serial.ok_or_else(|| missing("tstInfo.serialNumber"))?,
450 gen_time: self.gen_time.ok_or_else(|| missing("tstInfo.genTime"))?,
451 accuracy: self.accuracy,
452 ordering: self.ordering.unwrap_or(false),
453 nonce: self.nonce,
454 tsa: self.tsa,
455 extensions: self.extensions,
456 faults,
457 span,
458 })
459 }
460}
461
462fn carries(tag: Tag) -> bool {
463 tag == Tag::primitive(universal::INTEGER)
464 || tag == Tag::primitive(universal::OID)
465 || tag == Tag::constructed(universal::SEQUENCE)
466 || tag == Tag::primitive(universal::GENERALIZED_TIME)
467 || tag == Tag::constructed(universal::GENERALIZED_TIME)
468 || tag == Tag::primitive(universal::BOOLEAN)
469 || tag == Tag::context(true, 0)
470 || tag == Tag::context(true, 1)
471}
472
473fn distinguished<W: Work>(
474 parent: &Reader<'_>,
475 element: &Element<'_>,
476 faults: &mut OwnedVec<Error, W>,
477) -> Result<()> {
478 let mut strict = parent
479 .reread(element, Encoding::Der)
480 .map_err(|error| Error::encoding(error, FIELD))?;
481 let result = strict
482 .expect(element.tag())
483 .map_err(|error| Error::encoding(error, FIELD))
484 .and_then(|again| {
485 structured_pkix::der::conforms(&strict, &again, FIELD).map_err(Error::pkix)
486 });
487 match result {
488 Ok(()) => Ok(()),
489 Err(error) => record(faults, error),
490 }
491}