Skip to main content

structured_pades/
baseline.rs

1//! Format/static-time/material composition over sealed original `PAdES` receipts.
2
3use crate::{
4    basic::{Basic, Bound},
5    query::Query,
6    range::RangeSource,
7    timestamp::{ISSUER, Node, Pades, Requirements},
8};
9use structured_ltv::{
10    baseline::{TimeError, Timed},
11    source::Query as _,
12    timestamp::TimestampPaths,
13};
14mod archives;
15mod profile;
16pub use archives::Error as SealsError;
17pub use archives::{Seal, Seals, seals};
18pub use profile::{Assessment, AssessmentOf, Selection, assess};
19
20/// Original root and all-counter stage with one retained receipt lifetime.
21pub type BasicOf<'a, 'd, D, G> = Basic<'a, 'a, 'a, 'a, 'd, 'a, 'a, 'a, D, G>;
22/// Actual SID/ESS/key/path association, independent of application trust.
23pub type BindingOf<'a, 'd, D, G> = Bound<'a, 'a, 'a, 'd, 'a, 'a, 'a, D, G>;
24/// All original CMS/PDF TSA paths plus the signature's static existence time.
25pub type TimedOf<'a, 'd, D, G> =
26    Timed<'a, 'a, 'd, BasicOf<'a, 'd, D, G>, BindingOf<'a, 'd, D, G>, Node, D, G, Pades>;
27
28/// Closed same-source format reports, not caller-implemented positive traits.
29pub type LongTermOf<'s, 'a, 'cl, 'r, 'c, 'd, 'auth, C, D, G> = structured_ltv::baseline::LongTerm<
30    's,
31    TimedOf<'a, 'd, D, G>,
32    crate::material::checks::Checks<'cl, 'r, 'a, 'c, 'd, D, G>,
33    crate::material::credentials::Report<'auth, C, D, G>,
34>;
35
36/// Joins the exact original signer/counters/all-TSA time report with the
37/// format's own complete X.509 and credential-material reports. The common
38/// core verifies actual receipt identities; public booleans or replacement
39/// trait implementations cannot manufacture the `PAdES` stage.
40pub fn long_term<'s, 'a, 'cl, 'r, 'c, 'd: 'a, 'auth, C, S: RangeSource>(
41    timed: &'s TimedOf<'a, 'd, S::Document, S::Generation>,
42    x509: &'s crate::material::checks::Checks<'cl, 'r, 'a, 'c, 'd, S::Document, S::Generation>,
43    credentials: &'s crate::material::credentials::Report<'auth, C, S::Document, S::Generation>,
44    query: &Query<'_, '_, S>,
45) -> Result<
46    LongTermOf<'s, 'a, 'cl, 'r, 'c, 'd, 'auth, C, S::Document, S::Generation>,
47    structured_ltv::pki::ParticipantError<Node>,
48> {
49    let source = timed.basic().binding().prepared().container.signature();
50    if !query.belongs(source.owner().value.session) {
51        return Err(structured_ltv::pki::ParticipantError::Foreign {
52            signature: Node::of(source.location()),
53        });
54    }
55    structured_ltv::baseline::long_term(timed, x509, credentials, query)
56}
57
58/// Closed per-input X.509 and credential material composition. Both reports
59/// must retain the same actual authenticated credential receipt and archive
60/// scope; this performs no replay and makes no historical-trust assertion.
61pub fn archive_material<'s, 'cl, 'r, 'v, 'c, 'd, 'auth, C, S: RangeSource>(
62    x509: &'s structured_ltv::material::ParticipantMaterial<
63        'cl,
64        'r,
65        'v,
66        'c,
67        'd,
68        Node,
69        S::Document,
70        S::Generation,
71        crate::material::Placement,
72        Pades,
73    >,
74    credentials: &'s crate::material::credentials::Report<'auth, C, S::Document, S::Generation>,
75    query: &Query<'_, '_, S>,
76) -> Result<
77    Seal<'s, 'cl, 'r, 'v, 'c, 'd, 'auth, S::Document, S::Generation, C>,
78    structured_ltv::pki::ParticipantError<Node>,
79> {
80    structured_ltv::baseline::archive_material(x509, credentials, query)
81}
82
83/// Joins ALL original root/counter/DTS paths. A covering document timestamp
84/// supplies existence time only when no root signature timestamp is written;
85/// later renewals do not force the root signer to remain valid indefinitely.
86pub fn timestamped<'a, 'd: 'a, S: RangeSource>(
87    basic: &'a BasicOf<'a, 'd, S::Document, S::Generation>,
88    required: &'a Requirements<'a, 'a, S::Document, S::Generation>,
89    paths: &'a TimestampPaths<'a, 'a, 'd, Node, S::Document, S::Generation, Pades>,
90    query: &Query<'_, '_, S>,
91) -> Result<TimedOf<'a, 'd, S::Document, S::Generation>, TimeError<Node>> {
92    let source = basic.binding().mapping;
93    if !query.belongs(
94        basic
95            .binding()
96            .prepared()
97            .container
98            .signature()
99            .owner()
100            .value
101            .session,
102    ) || query.snapshot() != source.snapshot
103        || !core::ptr::eq(required.all(), paths.required())
104    {
105        return Err(TimeError::Foreign {
106            signature: source.root,
107        });
108    }
109    query.admit(source.root, 1).map_err(TimeError::Scope)?;
110    let archive = required
111        .first_existence_timestamp(query.execution())
112        .map_err(|cause| match cause.kind {
113            crate::ErrorKind::Resource(cause) => TimeError::Resource {
114                node: source.root,
115                cause,
116            },
117            _ => TimeError::Foreign {
118                signature: source.root,
119            },
120        })?;
121    structured_ltv::baseline::timestamped_existence(ISSUER, basic, paths, archive, query)
122}