Skip to main content

structured_ltv/
lib.rs

1//! Format-neutral long-term signature validation facts.
2//!
3//! EN 319 102-1 defines path validation at a time, revocation material bound
4//! to path members, timestamp generation intervals and the coverage of
5//! validation material by archive timestamps once for every `AdES` format. This
6//! crate implements those facts over `structured-pkix` and `structured-cms`
7//! processors and the caller's [`source::Query`]; `XAdES`, `CAdES` and `PAdES`
8//! layers say only where the material and timestamps were written. No XML or PDF type
9//! crosses it, and no fact is a trust verdict.
10//!
11//! - [`source`]: the document owner's identities and the current query.
12//! - [`timestamp`]: retained token checks, generation intervals, signature-time
13//!   association and the complete token obligations of one scope.
14//! - [`pki`]: actor paths, status binding, the authority closure and the
15//!   participant census derived from the format's receipts.
16//! - [`material`]: incorporated artifacts, their uses and archive coverage.
17//! - [`baseline`]: compositions over the format's stage reports.
18//!
19//! # Issuers
20//!
21//! The receipts a format asserts from its own checks (a checked timestamp,
22//! its signer, an archive input's coverage, the token census, the material
23//! index, the participant census) carry an issuer type `I`, and constructing
24//! one takes a value of `I`. A format defines its issuer as a type only it can construct, so a
25//! caller of the format cannot relabel evidence or supply a fabricated
26//! receipt to the format's own APIs. Facts derived from receipts keep their
27//! issuer, and receipts of different issuers do not combine:
28//!
29//! ```
30//! # use structured_asn1::memory::Memory;
31//! # use structured_ltv::{material::Coverage, source::Query, timestamp::Verified};
32//! struct Cades;
33//! fn bind<Q: Query<Id = usize, Document = u8, Generation = u8>>(
34//!     coverage: &Coverage<usize, u8, u8, Memory, Cades>,
35//!     evidence: &Verified<usize, u8, u8, Cades>,
36//!     query: &Q,
37//! ) {
38//!     let _ = coverage.covers(evidence, 0, query);
39//! }
40//! ```
41//!
42//! ```compile_fail
43//! # use structured_asn1::memory::Memory;
44//! # use structured_ltv::{material::Coverage, source::Query, timestamp::Verified};
45//! struct Cades;
46//! struct Pades;
47//! fn bind<Q: Query<Id = usize, Document = u8, Generation = u8>>(
48//!     coverage: &Coverage<usize, u8, u8, Memory, Cades>,
49//!     evidence: &Verified<usize, u8, u8, Pades>,
50//!     query: &Q,
51//! ) {
52//!     let _ = coverage.covers(evidence, 0, query);
53//! }
54//! ```
55//!
56//! # Examples
57//!
58//! A document owner implements [`source::Source`] over its own identities; the
59//! [`source::Scope`] of one operation then funds every check and refuses a
60//! rewritten document.
61//!
62//! ```
63//! use core::cell::Cell;
64//! use std::sync::Arc;
65//! use structured_asn1::memory::{Memory, MemoryAccount};
66//! use structured_ltv::material::Coverage;
67//! use structured_ltv::source::{Query, Scope, ScopeError, Snapshot, Source};
68//! use structured_ltv::timestamp::Purpose;
69//!
70//! // A CMS signature whose unsigned attributes are identified by ordinal.
71//! struct SignerInfo {
72//!     generation: Cell<u8>,
73//! }
74//! impl Source for SignerInfo {
75//!     type Id = usize;
76//!     type Document = u8;
77//!     type Generation = u8;
78//!     fn snapshot(&self) -> Snapshot<u8, u8> {
79//!         Snapshot { document: 1, generation: self.generation.get() }
80//!     }
81//! }
82//! // The format's issuer: its private field keeps other crates from creating one.
83//! #[derive(Clone, Copy)]
84//! pub struct Cades(());
85//!
86//! let source = SignerInfo { generation: Cell::new(1) };
87//! let memory = Memory::new(Arc::new(MemoryAccount::new(4096, 10_000)));
88//! let query = Scope::new(&source, source.snapshot(), &memory);
89//! // Attribute 3 lies in archive attribute 5's input; attribute 7 does not.
90//! let mut items = memory.map();
91//! items.try_insert(3, true).unwrap();
92//! let coverage = Coverage::new(Cades(()), source.snapshot(), 0, 5, Purpose::Archive, items);
93//! assert_eq!(coverage.selects(3, &query), Ok(true));
94//! assert_eq!(coverage.selects(7, &query), Ok(false));
95//! source.generation.set(2);
96//! assert_eq!(query.admit(3, 1), Err(ScopeError::Changed { node: 3 }));
97//! ```
98
99#![cfg_attr(not(feature = "std"), no_std)]
100
101extern crate alloc;
102
103pub mod baseline;
104pub mod credential;
105pub mod material;
106pub mod pki;
107pub mod source;
108pub mod timestamp;