1use crate::{
7 Cades, Level,
8 basic::{Basic, SignerBinding},
9 material::{self, Placement},
10 prepare::Preparation,
11 source::{DocumentId, Node},
12};
13use structured_asn1::memory::Work;
14use structured_ltv::baseline::{ArchiveMaterial, Archives, CredentialMaterial, LongTerm, Timed};
15
16pub use structured_ltv::baseline::{archive_material, archives, long_term, timestamped};
17
18pub type BasicOf<'a, 'm, 'd> = Basic<'a, 'a, 'm, 'd, 'a>;
20pub type TimedOf<'a, 'm, 'd> = Timed<
22 'a,
23 'a,
24 'd,
25 BasicOf<'a, 'm, 'd>,
26 SignerBinding<'a, 'm, 'd, 'a>,
27 Node,
28 DocumentId<'m, 'd>,
29 (),
30 Cades,
31>;
32pub type CredentialsOf<'a, 'm, 'd, E> = material::credentials::Report<'a, 'a, 'm, 'd, 'a, E>;
34pub type LongTermOf<'a, 'm, 'd, E> = LongTerm<
36 'a,
37 TimedOf<'a, 'm, 'd>,
38 material::Checks<'a, 'a, 'a, 'a, 'd, 'm>,
39 CredentialsOf<'a, 'm, 'd, E>,
40>;
41pub type ArchivesOf<'a, 'm, 'd, E> = Archives<
43 'a,
44 Preparation<'m, 'd>,
45 ArchiveMaterial<
46 'a,
47 structured_ltv::material::ParticipantMaterial<
48 'a,
49 'a,
50 'a,
51 'a,
52 'd,
53 Node,
54 DocumentId<'m, 'd>,
55 (),
56 Placement,
57 Cades,
58 >,
59 CredentialsOf<'a, 'm, 'd, E>,
60 >,
61>;
62
63pub enum Evidence<'a, 'm, 'd, E> {
67 Basic(&'a BasicOf<'a, 'm, 'd>),
69 Timestamped(&'a TimedOf<'a, 'm, 'd>),
71 LongTerm(&'a LongTermOf<'a, 'm, 'd, E>),
73 Archival {
75 long_term: &'a LongTermOf<'a, 'm, 'd, E>,
77 archives: &'a ArchivesOf<'a, 'm, 'd, E>,
79 },
80}
81impl<'a, 'm, 'd> Evidence<'a, 'm, 'd, ()> {
82 #[must_use]
84 pub fn basic(report: &'a BasicOf<'a, 'm, 'd>) -> Self {
85 Self::Basic(report)
86 }
87 #[must_use]
89 pub fn timestamped(report: &'a TimedOf<'a, 'm, 'd>) -> Self {
90 Self::Timestamped(report)
91 }
92}
93impl<'m, 'd, E> Evidence<'_, 'm, 'd, E> {
94 #[must_use]
96 pub fn level(&self) -> Level {
97 match self {
98 Self::Basic(_) => Level::Basic,
99 Self::Timestamped(_) => Level::Timestamped,
100 Self::LongTerm(_) => Level::LongTerm,
101 Self::Archival { .. } => Level::Archival,
102 }
103 }
104 fn prepared(&self) -> &Preparation<'m, 'd> {
105 match self {
106 Self::Basic(basic) => basic.binding().prepared(),
107 Self::Timestamped(timed) => timed.basic().binding().prepared(),
108 Self::LongTerm(long)
109 | Self::Archival {
110 long_term: long, ..
111 } => long.timed().basic().binding().prepared(),
112 }
113 }
114}
115
116pub struct Assessment<'a, 'm, 'd, E> {
121 evidence: Evidence<'a, 'm, 'd, E>,
122 met: bool,
123}
124impl<'a, 'm, 'd, E> Assessment<'a, 'm, 'd, E> {
125 #[must_use]
127 pub fn requested(&self) -> Level {
128 self.evidence.level()
129 }
130 #[must_use]
132 pub fn evidence(&self) -> &Evidence<'a, 'm, 'd, E> {
133 &self.evidence
134 }
135 #[must_use]
137 pub fn all_requirements_met(&self) -> bool {
138 self.met
139 }
140}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq)]
144pub enum LevelError {
145 UnavailablePreservation {
148 property: Node,
150 kind: crate::preservation::Kind,
152 },
153 UnavailablePreservationSource {
155 source: Node,
157 },
158 Mismatch {
160 requested: Level,
162 supplied: Level,
164 },
165 Foreign,
167 Resource(structured_asn1::memory::MemoryError),
169}
170
171pub fn assess<'a, 'm, 'd, E>(
178 evidence: Evidence<'a, 'm, 'd, E>,
179 operation: &structured_asn1::Reader<'_>,
180) -> Result<Assessment<'a, 'm, 'd, E>, LevelError> {
181 assess_in(evidence, None, operation)
182}
183
184pub fn assess_preserved<'a, 'm, 'd, E>(
188 evidence: Evidence<'a, 'm, 'd, E>,
189 preservation: &crate::evidence::Closure<'_, '_, 'm, 'd, '_>,
190 operation: &structured_asn1::Reader<'_>,
191) -> Result<Assessment<'a, 'm, 'd, E>, LevelError> {
192 assess_in(evidence, Some(preservation), operation)
193}
194fn assess_in<'a, 'm, 'd, E>(
195 evidence: Evidence<'a, 'm, 'd, E>,
196 preservation: Option<&crate::evidence::Closure<'_, '_, 'm, 'd, '_>>,
197 operation: &structured_asn1::Reader<'_>,
198) -> Result<Assessment<'a, 'm, 'd, E>, LevelError> {
199 let prepared = evidence.prepared();
200 if let Some(proofs) = preservation
201 && !core::ptr::eq(proofs.prepared(), prepared)
202 {
203 return Err(LevelError::Foreign);
204 }
205 let requested = prepared.requested();
206 let supplied = evidence.level();
207 if requested != supplied {
208 return Err(LevelError::Mismatch {
209 requested,
210 supplied,
211 });
212 }
213 prepared
214 .document()
215 .message()
216 .require_session(operation, "cades.baseline")
217 .map_err(|_| LevelError::Foreign)?;
218 let work = operation.execution();
219 work.charge_work(1).map_err(LevelError::Resource)?;
220 if requested >= Level::Timestamped {
221 for required in prepared.preservation() {
222 work.charge_work(1).map_err(LevelError::Resource)?;
223 if !required.kind.is_reference_timestamp() && !required.kind.is_archive() {
228 if let Some(proofs) = preservation
229 && required.kind.is_evidence()
230 && proofs
231 .contains(required, &work)
232 .map_err(LevelError::Resource)?
233 {
234 continue;
235 }
236
237 return Err(LevelError::UnavailablePreservation {
238 property: required.property,
239 kind: required.kind,
240 });
241 }
242 }
243 if !prepared.preservation().is_empty() {
244 for finding in prepared.preservation_findings() {
245 work.charge_work(1).map_err(LevelError::Resource)?;
246 if finding.severity == crate::prepare::Severity::Required {
247 return Err(LevelError::UnavailablePreservationSource {
248 source: finding.location.node,
249 });
250 }
251 }
252 }
253 }
254 let met = match &evidence {
255 Evidence::Basic(basic) => basic.all_basic_requirements_met(),
256 Evidence::Timestamped(timed) => timed_met(timed),
257 Evidence::LongTerm(long) => long_met(long),
258 Evidence::Archival {
259 long_term,
260 archives,
261 } => {
262 work.charge_work(1).map_err(LevelError::Resource)?;
263 if !core::ptr::eq(archives.census(), prepared) {
264 return Err(LevelError::Foreign);
265 }
266 let credentials = long_term.credentials().credentials();
267 for archive in archives.reports() {
268 work.charge_work(1).map_err(LevelError::Resource)?;
269 if !core::ptr::eq(archive.credentials().credentials(), credentials) {
270 return Err(LevelError::Foreign);
271 }
272 }
273 long_met(long_term) && archives.all_archive_material_covered()
274 }
275 };
276 let met = met && prepared.all_format_requirements_met();
277 Ok(Assessment { evidence, met })
278}
279
280fn timed_met(timed: &TimedOf<'_, '_, '_>) -> bool {
281 timed.basic().all_basic_requirements_met() && timed.all_static_time_requirements_met()
282}
283fn long_met<E>(long: &LongTermOf<'_, '_, '_, E>) -> bool {
284 timed_met(long.timed()) && long.all_material_requirements_met()
285}