1use super::Role;
4use crate::binary::{
5 self, EncodingDeclaration, Location, OwnedBinaryXml, OwnedDecoded, PkiEncoding,
6};
7use crate::prepare::Prepared;
8use crate::xml::{Access, AccessError, Snapshot, Xml};
9use structured_asn1::{
10 Encoding, Reader,
11 memory::{MemoryError, Work},
12};
13use structured_cms::timestamp::Token;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum TokenProfile {
18 Cms,
20 Etsi,
23}
24
25#[derive(Debug)]
29pub enum EncodingConformance {
30 Matches,
32 Mismatch(structured_cms::Error),
34 Unchecked(PkiEncoding),
37}
38
39pub struct TokenSource<N, D, G> {
42 location: Location<N, D, G>,
43 signature: N,
44 property: N,
45 role: Role,
46 stamp: usize,
47 ordinal: usize,
48 encoding: Encoding,
49 declaration: EncodingDeclaration,
50 conformance: EncodingConformance,
51 source: OwnedDecoded,
52}
53impl<N: Copy, D: Copy, G: Copy> TokenSource<N, D, G> {
54 #[must_use]
56 pub fn declaration(&self) -> EncodingDeclaration {
57 self.declaration
58 }
59 #[must_use]
62 pub fn encoding_conformance(&self) -> &EncodingConformance {
63 &self.conformance
64 }
65 #[must_use]
67 pub fn signature(&self) -> N {
68 self.signature
69 }
70 #[must_use]
72 pub fn location(&self) -> Location<N, D, G> {
73 self.location
74 }
75 #[must_use]
77 pub fn property(&self) -> N {
78 self.property
79 }
80 #[must_use]
82 pub fn role(&self) -> Role {
83 self.role
84 }
85 #[must_use]
88 pub fn stamp_index(&self) -> usize {
89 self.stamp
90 }
91 #[must_use]
93 pub fn token_index(&self) -> usize {
94 self.ordinal
95 }
96 #[must_use]
98 pub fn bytes(&self) -> &[u8] {
99 &self.source.bytes
100 }
101}
102
103pub struct TokenReading<'source> {
106 reader: Reader<'source>,
107 token: Token<'source>,
108}
109
110#[derive(Clone, Copy)]
113pub struct TokenEntry<'view, 'source, N, D, G> {
114 pub(super) source: &'view TokenSource<N, D, G>,
115 pub(super) reading: &'view TokenReading<'source>,
116}
117impl<'source> TokenReading<'source> {
118 #[must_use]
120 pub fn reader(&self) -> &Reader<'source> {
121 &self.reader
122 }
123 #[must_use]
125 pub fn token(&self) -> &Token<'source> {
126 &self.token
127 }
128}
129
130pub struct TokenView<'source, N, D, G> {
133 sources: &'source [TokenSource<N, D, G>],
134 readings: &'source [TokenReading<'source>],
135 snapshot: Snapshot<D, G>,
136 signature: N,
137}
138impl<'source, N, D, G> TokenView<'source, N, D, G> {
139 #[must_use]
142 pub fn entry(&self, index: usize) -> Option<TokenEntry<'_, 'source, N, D, G>> {
143 Some(TokenEntry {
144 source: self.sources.get(index)?,
145 reading: self.readings.get(index)?,
146 })
147 }
148 #[must_use]
150 pub fn sources(&self) -> &'source [TokenSource<N, D, G>] {
151 self.sources
152 }
153 #[must_use]
155 pub fn readings(&self) -> &'source [TokenReading<'source>] {
156 self.readings
157 }
158}
159
160impl<'source, N: Copy, D: Copy, G: Copy> TokenView<'source, N, D, G> {
161 #[must_use]
163 pub fn snapshot(&self) -> Snapshot<D, G> {
164 self.snapshot
165 }
166 #[must_use]
168 pub fn signature(&self) -> N {
169 self.signature
170 }
171
172 pub(super) fn reborrow<'query>(&self) -> TokenView<'query, N, D, G>
173 where
174 'source: 'query,
175 {
176 TokenView {
177 sources: self.sources,
178 readings: self.readings,
179 snapshot: self.snapshot,
180 signature: self.signature,
181 }
182 }
183}
184
185#[derive(Debug)]
187pub enum TokenPipelineError<E, VE, N, D, G> {
188 Foreign {
190 node: N,
192 },
193 Access(AccessError<E, N>),
195 Encoding(binary::Error<E, core::convert::Infallible, N, D, G>),
198 Reader {
200 location: Location<N, D, G>,
202 cause: structured_asn1::Error,
204 },
205 Token {
207 location: Location<N, D, G>,
209 cause: structured_cms::Error,
211 },
212 Resource {
214 node: N,
216 cause: MemoryError,
218 },
219 Visitor(VE),
221}
222
223pub type TokenPipelineResult<T, X, VE> = Result<
225 T,
226 TokenPipelineError<
227 <X as Xml>::Error,
228 VE,
229 <X as Xml>::Id,
230 <X as Xml>::Document,
231 <X as Xml>::Generation,
232 >,
233>;
234
235pub fn with_tokens<X: OwnedBinaryXml, R, VE>(
254 xml: &X,
255 prepared: &Prepared<X>,
256 operation: &Reader<'_>,
257 profile: TokenProfile,
258 visitor: impl for<'source> FnOnce(
259 &Reader<'source>,
260 TokenView<'source, X::Id, X::Document, X::Generation>,
261 ) -> Result<R, VE>,
262) -> TokenPipelineResult<R, X, VE> {
263 with_inputs(xml, prepared, None, operation, profile, visitor)
264}
265
266pub fn with_counter_tokens<X: OwnedBinaryXml, R, VE>(
281 xml: &X,
282 prepared: &Prepared<X>,
283 counters: &super::CounterTimestamps<X::Id, X::Document, X::Generation>,
284 operation: &Reader<'_>,
285 profile: TokenProfile,
286 visitor: impl for<'source> FnOnce(
287 &Reader<'source>,
288 TokenView<'source, X::Id, X::Document, X::Generation>,
289 ) -> Result<R, VE>,
290) -> TokenPipelineResult<R, X, VE> {
291 with_inputs(xml, prepared, Some(counters), operation, profile, visitor)
292}
293
294impl<N: Copy, D: Copy, G: Copy> TokenEntry<'_, '_, N, D, G> {
295 pub(super) fn reader_in<'query>(
296 &'query self,
297 operation: &Reader<'query>,
298 ) -> structured_asn1::Result<Reader<'query>> {
299 self.source
300 .source
301 .reader_in(operation, self.source.encoding)
302 }
303}
304
305fn with_inputs<X: OwnedBinaryXml, R, VE>(
306 xml: &X,
307 prepared: &Prepared<X>,
308 counters: Option<&super::CounterTimestamps<X::Id, X::Document, X::Generation>>,
309 operation: &Reader<'_>,
310 profile: TokenProfile,
311 visitor: impl for<'source> FnOnce(
312 &Reader<'source>,
313 TokenView<'source, X::Id, X::Document, X::Generation>,
314 ) -> Result<R, VE>,
315) -> TokenPipelineResult<R, X, VE> {
316 let layout = prepared.bound().containers();
317 let execution = operation.execution();
318 let access = Access::new(xml, layout.snapshot(), &execution);
319 admit(&access, layout.signature())?;
320 if let Some(counters) = counters
321 && (counters.snapshot != layout.snapshot()
322 || !access
323 .equal_id(counters.signature, layout.signature())
324 .map_err(|cause| TokenPipelineError::Resource {
325 node: layout.signature(),
326 cause,
327 })?)
328 {
329 return Err(TokenPipelineError::Foreign {
330 node: layout.signature(),
331 });
332 }
333 let mut sources = execution.vector();
334 let children = counters
335 .into_iter()
336 .flat_map(|counters| counters.entries.iter().map(super::CounterStamp::stamp));
337 let mut timestamps = prepared.timestamps().iter().chain(children).enumerate();
338 loop {
339 admit(&access, layout.signature())?;
340 let Some((stamp, timestamp)) = timestamps.next() else {
341 break;
342 };
343 for ordinal in 0..timestamp.tokens().len() {
344 admit(&access, timestamp.node())?;
345 let node = timestamp.tokens()[ordinal];
346 let location = Location {
347 snapshot: layout.snapshot(),
348 node,
349 };
350 let (declaration, encoding) = select_encoding(profile, &access, location)?;
351 let source = binary::owned_source(xml, location, operation)
352 .map_err(TokenPipelineError::Access)?
353 .value;
354 let conformance = declaration_conformance::<X, VE>(
355 profile,
356 declaration.encoding(),
357 &source,
358 operation,
359 location,
360 )?;
361 sources
362 .try_push(TokenSource {
363 location,
364 signature: timestamp.signature,
365 property: timestamp.node(),
366 role: timestamp.role(),
367 stamp,
368 ordinal,
369 encoding,
370 declaration,
371 conformance,
372 source,
373 })
374 .map_err(|cause| TokenPipelineError::Resource { node, cause })?;
375 }
376 }
377 let mut readings = execution.vector();
378 for index in 0..sources.len() {
379 admit(&access, layout.signature())?;
380 let source = &sources[index];
381 let mut reader = source
382 .source
383 .reader_in(operation, source.encoding)
384 .map_err(|cause| TokenPipelineError::Reader {
385 location: source.location,
386 cause,
387 })?;
388 let token = Token::read_from(&mut reader).map_err(|cause| TokenPipelineError::Token {
389 location: source.location,
390 cause,
391 })?;
392 readings
393 .try_push(TokenReading { reader, token })
394 .map_err(|cause| TokenPipelineError::Resource {
395 node: source.location.node,
396 cause,
397 })?;
398 }
399 admit(&access, layout.signature())?;
400 let result = visitor(
401 operation,
402 TokenView {
403 sources: &sources,
404 readings: &readings,
405 snapshot: layout.snapshot(),
406 signature: layout.signature(),
407 },
408 )
409 .map_err(TokenPipelineError::Visitor)?;
410 admit(&access, layout.signature())?;
411 Ok(result)
412}
413
414fn select_encoding<X: Xml, W: Work, VE>(
415 profile: TokenProfile,
416 access: &Access<'_, X, W>,
417 location: Location<X::Id, X::Document, X::Generation>,
418) -> TokenPipelineResult<(EncodingDeclaration, Encoding), X, VE> {
419 let declaration = binary::pki_encoding(access, location.node)
420 .map_err(|cause| TokenPipelineError::Encoding(binary::Error::Access { location, cause }))?
421 .ok_or(TokenPipelineError::Encoding(
422 binary::Error::UnknownEncoding { location },
423 ))?;
424 let encoding = match (profile, declaration.encoding()) {
425 (TokenProfile::Cms, PkiEncoding::Der | PkiEncoding::Ber | PkiEncoding::Cer)
426 | (TokenProfile::Etsi, PkiEncoding::Ber) => Encoding::Ber,
427 (TokenProfile::Etsi, PkiEncoding::Der) => Encoding::Der,
428 (_, encoding) => {
429 return Err(TokenPipelineError::Encoding(
430 binary::Error::UnsupportedEncoding { location, encoding },
431 ));
432 }
433 };
434 Ok((declaration, encoding))
435}
436
437fn declaration_conformance<X: Xml, VE>(
438 profile: TokenProfile,
439 declared: PkiEncoding,
440 source: &OwnedDecoded,
441 operation: &Reader<'_>,
442 location: Location<X::Id, X::Document, X::Generation>,
443) -> TokenPipelineResult<EncodingConformance, X, VE> {
444 if profile == TokenProfile::Cms && declared == PkiEncoding::Der {
445 let mut strict = source
450 .reader_in(operation, Encoding::Der)
451 .map_err(|cause| TokenPipelineError::Reader { location, cause })?;
452 match Token::read_from(&mut strict) {
453 Ok(_) => Ok(EncodingConformance::Matches),
454 Err(cause) if cause.is_terminal() => Err(TokenPipelineError::Token { location, cause }),
455 Err(cause) => Ok(EncodingConformance::Mismatch(cause)),
456 }
457 } else if declared == PkiEncoding::Cer {
458 Ok(EncodingConformance::Unchecked(declared))
459 } else {
460 Ok(EncodingConformance::Matches)
462 }
463}
464
465fn admit<X: Xml, W: Work, VE>(
466 access: &Access<'_, X, W>,
467 node: X::Id,
468) -> TokenPipelineResult<(), X, VE> {
469 access
470 .query(node, |_, _, work| Ok(work.charge_work(1)))
471 .map_err(TokenPipelineError::Access)?
472 .map_err(|cause| TokenPipelineError::Resource { node, cause })
473}