1use crate::{
4 Session,
5 basic::Basic,
6 binding::Mapping,
7 error::{Error as PdfError, ErrorKind},
8 model::admit,
9 query::Query,
10 range::RangeSource,
11 timestamp::Node,
12};
13use structured_asn1::memory::{Memory, OwnedVec, Work};
14use structured_cades::credential as cms;
15use structured_ltv::{
16 pki::{self, CredentialGroup, CredentialReceipts},
17 source::{Query as _, Snapshot},
18};
19
20pub struct Report<'m, 'd, 'p, 's, D, G, E> {
22 common: cms::Report<'m, 'd, 'p, E>,
23 mapping: Mapping<'m, 'd, D, G>,
24 session: &'s Session,
25}
26pub struct Group<'a, 'm, 'd, 'p, D, G, E> {
28 pub(crate) common: &'a cms::Group<'m, 'd, 'p, E>,
29 mapping: Mapping<'m, 'd, D, G>,
30}
31impl<'d, 'p, D: Copy, G: Copy, E> CredentialGroup<'p, 'd> for Group<'_, '_, 'd, 'p, D, G, E> {
32 type Id = Node;
33 fn signature(&self) -> Node {
34 self.mapping.node(self.common.signature())
35 }
36 fn len(&self) -> usize {
37 self.common.len()
38 }
39 fn credential(&self, ordinal: usize) -> pki::Credential<'p, 'd, Node> {
40 let actual = self.common.credential(ordinal);
41 pki::Credential {
42 signature: self.mapping.node(actual.signature),
43 node: self.mapping.node(actual.node),
44 authorities: actual.authorities,
45 }
46 }
47}
48pub struct Complete<'a, 'm, 'd, 'p, D, G, E> {
50 common: cms::Complete<'a, 'm, 'd, 'p, E>,
51 pub(crate) mapping: Mapping<'m, 'd, D, G>,
52 pub(crate) root: Option<Group<'a, 'm, 'd, 'p, D, G, E>>,
53 pub(crate) counters: OwnedVec<Group<'a, 'm, 'd, 'p, D, G, E>, Memory>,
54}
55impl<'a, 'm, 'd, 'p, D: Copy + Eq, G: Copy + Eq, E> CredentialReceipts<'p, 'd>
56 for Complete<'a, 'm, 'd, 'p, D, G, E>
57{
58 type Id = Node;
59 type Document = D;
60 type Generation = G;
61 type Group = Group<'a, 'm, 'd, 'p, D, G, E>;
62 fn snapshot(&self) -> Snapshot<D, G> {
63 self.mapping.snapshot
64 }
65 fn signature(&self) -> Node {
66 self.mapping.root
67 }
68 fn root(&self) -> Option<&Self::Group> {
69 self.root.as_ref()
70 }
71 fn counters(&self) -> usize {
72 self.counters.len()
73 }
74 fn counter(&self, ordinal: usize) -> (Node, &Self::Group) {
75 let group = &self.counters[ordinal];
76 (group.signature(), group)
77 }
78}
79impl<'m, 'd, 'p, D: Copy + Eq, G: Copy + Eq, E> Report<'m, 'd, 'p, '_, D, G, E> {
80 #[must_use]
82 pub fn common(&self) -> &cms::Report<'m, 'd, 'p, E> {
83 &self.common
84 }
85 pub fn complete<'a>(
92 &'a self,
93 operation: &impl Work,
94 ) -> crate::Result<Option<Complete<'a, 'm, 'd, 'p, D, G, E>>> {
95 let work = self.session.query(operation);
96 let location = self.mapping.carrier;
97 admit(&work, location, 1)?;
98 let Some(common) = self.common.complete() else {
99 return Ok(None);
100 };
101 let root = common.root_group().map(|value| Group {
102 common: value,
103 mapping: self.mapping,
104 });
105 let mut counters = work.vector();
106 counters
107 .try_reserve_exact(common.counters())
108 .map_err(|cause| PdfError {
109 kind: ErrorKind::Resource(cause),
110 location,
111 })?;
112 for ordinal in 0..common.counters() {
113 let value = common
114 .counter_group(ordinal, &work)
115 .map_err(|cause| PdfError {
116 kind: ErrorKind::Resource(cause),
117 location,
118 })?
119 .expect("bounded original counter group");
120 counters
121 .try_push(Group {
122 common: value,
123 mapping: self.mapping,
124 })
125 .map_err(|cause| PdfError {
126 kind: ErrorKind::Resource(cause),
127 location,
128 })?;
129 }
130 Ok(Some(Complete {
131 common,
132 mapping: self.mapping,
133 root,
134 counters: counters.into_owned(),
135 }))
136 }
137}
138impl<'a, 'm, 'd, 'p, D, G, E> Complete<'a, 'm, 'd, 'p, D, G, E> {
139 #[must_use]
141 pub fn common(&self) -> &cms::Complete<'a, 'm, 'd, 'p, E> {
142 &self.common
143 }
144}
145
146#[derive(Debug)]
148pub enum Error<E> {
149 Pdf(PdfError),
151 Scope(structured_ltv::source::ScopeError<Node>),
153 Nonconforming {
155 location: crate::source::Location,
157 },
158 Cms(cms::CheckError<E>),
160}
161impl<'m, 'd, 'p, 's, D: Copy + Eq, G: Copy + Eq> Basic<'_, '_, '_, 'm, 'd, '_, 's, 'p, D, G> {
162 pub fn participants<'r, 'certificate, E, S: RangeSource<Document = D, Generation = G>>(
166 &'p self,
167 credentials: &'p Complete<'r, 'm, 'd, 'p, D, G, E>,
168 timestamps: &'p structured_ltv::timestamp::TimestampPaths<
169 'p,
170 'certificate,
171 'd,
172 Node,
173 D,
174 G,
175 crate::timestamp::Pades,
176 >,
177 query: &Query<'_, '_, S>,
178 ) -> Result<
179 pki::ParticipantRequirements<'p, 'd, Node, D, G, crate::timestamp::Pades>,
180 pki::ParticipantError<Node>,
181 > {
182 let source = self.binding().prepared().container.signature();
183 query.admit(self.binding().mapping.root, 1)?;
184 if !query.belongs(source.owner().value.session)
185 || credentials.mapping.snapshot != self.binding().mapping.snapshot
186 || credentials.mapping.root != self.binding().mapping.root
187 {
188 return Err(pki::ParticipantError::Foreign {
189 signature: self.binding().mapping.root,
190 });
191 }
192 pki::participants(
193 crate::timestamp::ISSUER,
194 self.binding(),
195 self.counters(),
196 credentials,
197 timestamps,
198 query,
199 )
200 }
201
202 pub fn authenticate_credentials<
206 P: cms::Provider<'p, 'd>,
207 S: RangeSource<Document = D, Generation = G>,
208 >(
209 &self,
210 provider: &P,
211 query: &Query<'_, '_, S>,
212 ) -> Result<Report<'m, 'd, 'p, 's, D, G, P::Evidence>, Error<P::Error>> {
213 let bound = self.binding();
214 let prepared = bound.prepared();
215 let signature = prepared.container.signature();
216 let location = signature.location();
217 query.admit(bound.mapping.root, 1).map_err(Error::Scope)?;
218 if !query.belongs(signature.owner().value.session)
219 || query.snapshot() != bound.mapping.snapshot
220 {
221 return Err(Error::Pdf(PdfError {
222 kind: ErrorKind::Foreign,
223 location,
224 }));
225 }
226 if !self.all_basic_requirements_met() {
227 return Err(Error::Nonconforming { location });
228 }
229 let work = signature.owner().value.session.query(query.execution());
230 let reader = prepared
231 .cms
232 .signer()
233 .fields_source()
234 .reader_in(&work)
235 .map_err(|cause| Error::Cms(cms::CheckError::Processing(cause.into())))?;
236 let common = cms::check_properties(
237 prepared.cms,
238 bound.binding(),
239 &self.counters().common,
240 provider,
241 &reader,
242 )
243 .map_err(Error::Cms)?;
244 query.admit(bound.mapping.root, 1).map_err(Error::Scope)?;
245 Ok(Report {
246 common,
247 mapping: bound.mapping,
248 session: signature.owner().value.session,
249 })
250 }
251}