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 for prior in seen.iter().flatten() {
241 execution.charge_work(1).map_err(refusal)?;
242 if prior.as_bytes().len() != element.as_bytes().len() {
243 continue;
244 }
245 execution
246 .charge_work(element.as_bytes().len() as u64)
247 .map_err(refusal)?;
248 if prior.as_bytes() == element.as_bytes() {
249 return Ok(true);
250 }
251 }
252 Ok(false)
253}
254
255#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
256#[repr(usize)]
257enum Slot {
258 Version,
259 Policy,
260 Imprint,
261 Serial,
262 GenTime,
263 Accuracy,
264 Ordering,
265 Nonce,
266 Tsa,
267 Extensions,
268}
269
270#[derive(Default)]
271struct Fields<'a> {
272 version: bool,
273 policy: Option<Oid<'a>>,
274 imprint: Option<MessageImprint<'a>>,
275 serial: Option<IntegerField<'a>>,
276 serial_displaced: bool,
277 gen_time: Option<Reading>,
278 accuracy: Option<AccuracyReading<'a>>,
279 ordering: Option<bool>,
280 nonce: Option<IntegerField<'a>>,
281 tsa: Option<TsaReading<'a>>,
282 extensions: Option<TokenExtensions<'a>>,
283}
284
285impl<'a> Fields<'a> {
286 fn slot(&self, parent: &Reader<'a>, element: &Element<'a>) -> Result<Option<Slot>> {
287 let tag = element.tag();
288 let slot = if tag == Tag::primitive(universal::INTEGER) {
289 if !self.version {
290 if self.policy.is_some() || self.imprint.is_some() || self.gen_time.is_some() {
296 return Err(Error::schema(
297 ErrorCode::DuplicateField,
298 FIELD,
299 element.span().start,
300 ));
301 }
302 Slot::Version
303 } else if self.serial.is_none() {
304 Slot::Serial
305 } else if self.nonce.is_none() {
306 Slot::Nonce
307 } else {
308 return Ok(None);
309 }
310 } else if tag == Tag::primitive(universal::OID) {
311 Slot::Policy
312 } else if tag == Tag::constructed(universal::SEQUENCE) {
313 let mut probe = parent
314 .enter(element)
315 .map_err(|error| Error::encoding(error, FIELD))?;
316 let first = probe
317 .next_element()
318 .map_err(|error| Error::encoding(error, FIELD))?;
319 if first.is_some_and(|first| {
322 first.tag() == Tag::constructed(universal::SEQUENCE)
323 || first.tag() == Tag::primitive(universal::OID)
324 }) {
325 Slot::Imprint
326 } else {
327 Slot::Accuracy
328 }
329 } else if tag == Tag::primitive(universal::GENERALIZED_TIME)
330 || tag == Tag::constructed(universal::GENERALIZED_TIME)
331 {
332 Slot::GenTime
333 } else if tag == Tag::primitive(universal::BOOLEAN) {
334 Slot::Ordering
335 } else if tag == Tag::context(true, 0) {
336 Slot::Tsa
337 } else if tag == Tag::context(true, 1) {
338 Slot::Extensions
339 } else {
340 return Ok(None);
341 };
342 let found = match slot {
343 Slot::Version => self.version,
344 Slot::Policy => self.policy.is_some(),
345 Slot::Imprint => self.imprint.is_some(),
346 Slot::Serial => self.serial.is_some(),
347 Slot::GenTime => self.gen_time.is_some(),
348 Slot::Accuracy => self.accuracy.is_some(),
349 Slot::Ordering => self.ordering.is_some(),
350 Slot::Nonce => self.nonce.is_some(),
351 Slot::Tsa => self.tsa.is_some(),
352 Slot::Extensions => self.extensions.is_some(),
353 };
354 Ok(if found { None } else { Some(slot) })
355 }
356
357 fn read<W: Work>(
358 &mut self,
359 slot: Slot,
360 parent: &Reader<'a>,
361 element: &Element<'a>,
362 faults: &mut OwnedVec<Error, W>,
363 ) -> Result<()> {
364 match slot {
365 Slot::Version => {
366 let version = IntegerField::read(parent, element, "tstInfo.version", faults)?;
367 if version.value.as_u64() != Some(1) {
368 return Err(Error::schema(
369 ErrorCode::UnsupportedVersion,
370 "tstInfo.version",
371 element.span().start,
372 ));
373 }
374 self.version = true;
375 }
376 Slot::Policy => {
377 self.policy = Some(
378 parent
379 .oid(element)
380 .map_err(|error| Error::encoding(error, "tstInfo.policy"))?,
381 );
382 }
383 Slot::Imprint => self.imprint = Some(MessageImprint::read(parent, element)?),
384 Slot::Serial => {
385 self.serial_displaced = self.imprint.is_none() || self.gen_time.is_some();
386 self.serial = Some(IntegerField::read(
387 parent,
388 element,
389 "tstInfo.serialNumber",
390 faults,
391 )?);
392 }
393 Slot::GenTime => {
394 self.gen_time = Some(
395 structured_pkix::temporal::read_generalized(parent, element, "tstInfo.genTime")
396 .map_err(Error::pkix)?,
397 );
398 }
399 Slot::Accuracy => self.accuracy = Some(AccuracyReading::read(parent, element)?),
400 Slot::Ordering => {
401 let ordering = parent
402 .boolean(element)
403 .map_err(|error| Error::encoding(error, "tstInfo.ordering"))?;
404 if !ordering {
405 record(
406 faults,
407 Error::schema(
408 ErrorCode::DefaultWritten,
409 "tstInfo.ordering",
410 element.span().start,
411 ),
412 )?;
413 }
414 self.ordering = Some(ordering);
415 }
416 Slot::Nonce => {
417 self.nonce = Some(IntegerField::read(
418 parent,
419 element,
420 "tstInfo.nonce",
421 faults,
422 )?);
423 }
424 Slot::Tsa => self.tsa = Some(TsaReading::read(parent, element, faults)?),
425 Slot::Extensions => self.extensions = Some(TokenExtensions::read(parent, element)?),
426 }
427 Ok(())
428 }
429
430 fn finish(self, span: Span, faults: OwnedVec<Error>) -> Result<TokenInfo<'a>> {
431 let missing = |field| Error::schema(ErrorCode::MissingField, field, span.start);
432 if !self.version {
433 return Err(missing("tstInfo.version"));
434 }
435 Ok(TokenInfo {
436 policy: self.policy.ok_or_else(|| missing("tstInfo.policy"))?,
437 imprint: self
438 .imprint
439 .ok_or_else(|| missing("tstInfo.messageImprint"))?,
440 serial: self.serial.ok_or_else(|| missing("tstInfo.serialNumber"))?,
441 gen_time: self.gen_time.ok_or_else(|| missing("tstInfo.genTime"))?,
442 accuracy: self.accuracy,
443 ordering: self.ordering.unwrap_or(false),
444 nonce: self.nonce,
445 tsa: self.tsa,
446 extensions: self.extensions,
447 faults,
448 span,
449 })
450 }
451}
452
453fn carries(tag: Tag) -> bool {
454 tag == Tag::primitive(universal::INTEGER)
455 || tag == Tag::primitive(universal::OID)
456 || tag == Tag::constructed(universal::SEQUENCE)
457 || tag == Tag::primitive(universal::GENERALIZED_TIME)
458 || tag == Tag::constructed(universal::GENERALIZED_TIME)
459 || tag == Tag::primitive(universal::BOOLEAN)
460 || tag == Tag::context(true, 0)
461 || tag == Tag::context(true, 1)
462}
463
464fn distinguished<W: Work>(
465 parent: &Reader<'_>,
466 element: &Element<'_>,
467 faults: &mut OwnedVec<Error, W>,
468) -> Result<()> {
469 let mut strict = parent
470 .reread(element, Encoding::Der)
471 .map_err(|error| Error::encoding(error, FIELD))?;
472 let result = strict
473 .expect(element.tag())
474 .map_err(|error| Error::encoding(error, FIELD))
475 .and_then(|again| {
476 structured_pkix::der::conforms(&strict, &again, FIELD).map_err(Error::pkix)
477 });
478 match result {
479 Ok(()) => Ok(()),
480 Err(error) => record(faults, error),
481 }
482}