1use crate::container::{DS, XADES};
4use crate::identifier;
5use crate::properties::{self, Error, PropertyResult};
6use crate::timestamp::XADES_141;
7use crate::unsigned;
8use crate::xml::{Access, AccessError, Name, Snapshot, Xml};
9use structured_asn1::memory::{OwnedVec, Work};
10
11mod syntax;
12pub use syntax::{SyntaxError, SyntaxResult, check_qualifier_syntax};
13
14#[derive(Debug)]
16pub enum Declaration<N> {
17 Implied(N),
19 Explicit(Explicit<N>),
21}
22
23pub struct Reading<N, D, G> {
26 snapshot: Snapshot<D, G>,
27 signature: N,
28 node: N,
29 declaration: Declaration<N>,
30}
31
32impl<N: Copy, D: Copy, G: Copy> Reading<N, D, G> {
33 #[must_use]
35 pub fn snapshot(&self) -> Snapshot<D, G> {
36 self.snapshot
37 }
38 #[must_use]
40 pub fn signature(&self) -> N {
41 self.signature
42 }
43 #[must_use]
45 pub fn node(&self) -> N {
46 self.node
47 }
48 #[must_use]
50 pub fn declaration(&self) -> &Declaration<N> {
51 &self.declaration
52 }
53}
54
55pub type Original<X> = Reading<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>;
57
58#[derive(Debug, Clone, Copy)]
60pub enum StoredDocument<N> {
61 Embedded(N),
63 Local(N),
65}
66
67pub struct Store<N, D, G> {
70 snapshot: Snapshot<D, G>,
71 signature: N,
72 node: N,
73 specification: identifier::Reading<N>,
74 document: StoredDocument<N>,
75}
76
77impl<N: Copy, D: Copy, G: Copy> Store<N, D, G> {
78 #[must_use]
80 pub fn snapshot(&self) -> Snapshot<D, G> {
81 self.snapshot
82 }
83 #[must_use]
85 pub fn signature(&self) -> N {
86 self.signature
87 }
88 #[must_use]
90 pub fn node(&self) -> N {
91 self.node
92 }
93 #[must_use]
95 pub fn specification(&self) -> &identifier::Reading<N> {
96 &self.specification
97 }
98 #[must_use]
100 pub fn document(&self) -> StoredDocument<N> {
101 self.document
102 }
103}
104
105pub type OriginalStore<X> = Store<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>;
107
108pub fn read_store<X: Xml, W: Work>(
112 access: &Access<'_, X, W>,
113 inventory: &unsigned::Reading<X>,
114 policy: Option<&Original<X>>,
115) -> PropertyResult<Option<OriginalStore<X>>, X> {
116 if access.snapshot() != inventory.snapshot() {
117 return Err(Error::Access(AccessError::Changed {
118 node: inventory.signature(),
119 }));
120 }
121 access
122 .query(inventory.signature(), |_, _, _| Ok(()))
123 .map_err(Error::Access)?;
124 if let Some(policy) = policy
125 && (policy.snapshot != inventory.snapshot()
126 || !access
127 .equal_id(policy.signature, inventory.signature())
128 .map_err(|cause| Error::Resource {
129 node: policy.node,
130 cause,
131 })?)
132 {
133 return Err(Error::Access(AccessError::Changed { node: policy.node }));
134 }
135 let mut store = None;
136 for index in 0..inventory.entries().len() {
137 access
138 .query(inventory.signature(), |_, _, work| Ok(work.charge_work(1)))
139 .map_err(Error::Access)?
140 .map_err(|cause| Error::Resource {
141 node: inventory.signature(),
142 cause,
143 })?;
144 let entry = inventory.entries()[index];
145 if entry.role == unsigned::Role::PolicyStore {
146 store = Some(entry.node);
147 break;
148 }
149 }
150 let Some(node) = store else { return Ok(None) };
151 if !matches!(
152 policy.map(|value| &value.declaration),
153 Some(Declaration::Explicit(_))
154 ) {
155 return Err(Error::Forbidden { node });
156 }
157 let mut fields = access.children(node);
158 let spec = fields
159 .next()
160 .transpose()
161 .map_err(Error::Child)?
162 .ok_or(Error::Missing {
163 parent: node,
164 local: "SPDocSpecification",
165 })?;
166 if !named(access, spec, XADES_141, "SPDocSpecification")? {
167 return Err(Error::Unexpected { node: spec });
168 }
169 let specification = read_specification(access, spec)?;
170 let value = fields
171 .next()
172 .transpose()
173 .map_err(Error::Child)?
174 .ok_or(Error::Missing {
175 parent: node,
176 local: "SignaturePolicyDocument or SigPolDocLocalURI",
177 })?;
178 let document = if named(access, value, XADES_141, "SignaturePolicyDocument")? {
179 StoredDocument::Embedded(value)
180 } else if named(access, value, XADES_141, "SigPolDocLocalURI")? {
181 StoredDocument::Local(value)
182 } else {
183 return Err(Error::Unexpected { node: value });
184 };
185 properties::simple_content(access, value)?;
186 if let Some(extra) = fields.next() {
187 return Err(Error::Unexpected {
188 node: extra.map_err(Error::Child)?,
189 });
190 }
191 Ok(Some(Store {
192 snapshot: inventory.snapshot(),
193 signature: inventory.signature(),
194 node,
195 specification,
196 document,
197 }))
198}
199
200#[derive(Debug)]
202pub struct Qualifier<N> {
203 pub node: N,
205 pub specifications: OwnedVec<N>,
208}
209
210#[derive(Debug)]
212pub struct Explicit<N> {
213 pub node: N,
215 pub identifier: identifier::Reading<N>,
217 pub transforms: Option<N>,
219 pub method: N,
221 pub digest: N,
223 pub qualifiers: OwnedVec<Qualifier<N>>,
225}
226
227pub fn read<X: Xml, W: Work>(
234 access: &Access<'_, X, W>,
235 signed: &properties::Reading<X>,
236) -> PropertyResult<Option<Original<X>>, X> {
237 if access.snapshot() != signed.snapshot() {
238 return Err(Error::Access(AccessError::Changed {
239 node: signed.parent(),
240 }));
241 }
242 access
243 .query(signed.parent(), |_, _, _| Ok(()))
244 .map_err(Error::Access)?;
245 let Some(parent) = signed.policy() else {
246 return Ok(None);
247 };
248 let mut children = access.children(parent);
249 let node = children
250 .next()
251 .transpose()
252 .map_err(Error::Child)?
253 .ok_or(Error::Missing {
254 parent,
255 local: "SignaturePolicyId or SignaturePolicyImplied",
256 })?;
257 if let Some(extra) = children.next() {
258 return Err(Error::Unexpected {
259 node: extra.map_err(Error::Child)?,
260 });
261 }
262 if named(access, node, XADES, "SignaturePolicyImplied")? {
263 if let Some(extra) = access.children(node).next() {
264 return Err(Error::Unexpected {
265 node: extra.map_err(Error::Child)?,
266 });
267 }
268 return Ok(Some(Reading {
269 snapshot: signed.snapshot(),
270 signature: signed.signature(),
271 node: parent,
272 declaration: Declaration::Implied(node),
273 }));
274 }
275 if !named(access, node, XADES, "SignaturePolicyId")? {
276 return Err(Error::Unexpected { node });
277 }
278 explicit(access, node).map(|value| {
279 Some(Reading {
280 snapshot: signed.snapshot(),
281 signature: signed.signature(),
282 node: parent,
283 declaration: Declaration::Explicit(value),
284 })
285 })
286}
287
288fn explicit<X: Xml, W: Work>(
289 access: &Access<'_, X, W>,
290 node: X::Id,
291) -> PropertyResult<Explicit<X::Id>, X> {
292 let mut fields = [None; 4];
293 let mut previous = 0;
294 for child in access.children(node) {
295 let child = child.map_err(Error::Child)?;
296 let mut selected = None;
297 for (rank, (ns, local)) in [
298 (XADES, "SigPolicyId"),
299 (DS, "Transforms"),
300 (XADES, "SigPolicyHash"),
301 (XADES, "SigPolicyQualifiers"),
302 ]
303 .iter()
304 .enumerate()
305 {
306 if named(access, child, ns, local)? {
307 selected = Some(rank);
308 break;
309 }
310 }
311 let rank = selected.ok_or(Error::Unexpected { node: child })?;
312 if fields[rank].is_some() {
313 return Err(Error::Duplicate { node: child });
314 }
315 if rank < previous {
316 return Err(Error::Order { node: child });
317 }
318 fields[rank] = Some(child);
319 previous = rank;
320 }
321 let identifier = identifier::read(
322 access,
323 fields[0].ok_or(Error::Missing {
324 parent: node,
325 local: "SigPolicyId",
326 })?,
327 )?;
328 let (method, digest) = properties::digest_value(
329 access,
330 fields[2].ok_or(Error::Missing {
331 parent: node,
332 local: "SigPolicyHash",
333 })?,
334 )?;
335 let qualifiers = qualifiers(access, node, fields[3])?;
336 if let Some(transforms) = fields[1] {
337 check_transforms(access, transforms, &qualifiers)?;
338 }
339 Ok(Explicit {
340 node,
341 identifier,
342 transforms: fields[1],
343 method,
344 digest,
345 qualifiers,
346 })
347}
348
349fn qualifiers<X: Xml, W: Work>(
350 access: &Access<'_, X, W>,
351 enclosure: X::Id,
352 parent: Option<X::Id>,
353) -> PropertyResult<OwnedVec<Qualifier<X::Id>>, X> {
354 let mut output = access
355 .query(enclosure, |_, _, work| Ok(work.vector()))
356 .map_err(Error::Access)?;
357 if let Some(parent) = parent {
358 for child in access.children(parent) {
359 let node = child.map_err(Error::Child)?;
360 if !named(access, node, XADES, "SigPolicyQualifier")? {
361 return Err(Error::Unexpected { node });
362 }
363 let mut specifications = access
366 .query(node, |_, _, work| Ok(work.vector()))
367 .map_err(Error::Access)?;
368 let mut child = access.first_child(node).map_err(Error::Access)?;
369 while let Some(value) = child {
370 if named(access, value, XADES_141, "SPDocSpecification")? {
371 read_specification(access, value)?;
372 specifications
373 .try_push(value)
374 .map_err(|cause| Error::Resource { node: value, cause })?;
375 } else if named(access, value, XADES, "SPURI")? {
376 properties::simple_content(access, value)?;
377 } else if named(access, value, XADES, "SPUserNotice")? {
378 user_notice(access, value)?;
379 }
380 child = access.next_sibling(node, value).map_err(Error::Access)?;
381 }
382 output
383 .try_push(Qualifier {
384 node,
385 specifications: specifications.into_owned(),
386 })
387 .map_err(|cause| Error::Resource { node, cause })?;
388 }
389 if output.is_empty() {
390 return Err(Error::Missing {
391 parent,
392 local: "SigPolicyQualifier",
393 });
394 }
395 }
396 Ok(output.into_owned())
397}
398
399fn user_notice<X: Xml, W: Work>(access: &Access<'_, X, W>, parent: X::Id) -> PropertyResult<(), X> {
400 user_notice_with(access, parent, |number| {
401 properties::simple_content(access, number)
402 })
403}
404
405fn user_notice_with<X: Xml, W: Work, E: From<Error<X::Error, X::Id>>>(
408 access: &Access<'_, X, W>,
409 parent: X::Id,
410 mut integer: impl FnMut(X::Id) -> Result<(), E>,
411) -> Result<(), E> {
412 let mut notice = None;
413 let mut text = None;
414 for child in access.children(parent) {
415 let node = child.map_err(Error::Child)?;
416 if named(access, node, XADES, "NoticeRef")? {
417 if notice.is_some() {
418 return Err(Error::Duplicate { node }.into());
419 }
420 if text.is_some() {
421 return Err(Error::Order { node }.into());
422 }
423 notice = Some(node);
424 let mut fields = access.children(node);
425 let organization =
426 fields
427 .next()
428 .transpose()
429 .map_err(Error::Child)?
430 .ok_or(Error::Missing {
431 parent: node,
432 local: "Organization",
433 })?;
434 if !named(access, organization, XADES, "Organization")? {
435 return Err(Error::Unexpected { node: organization }.into());
436 }
437 properties::simple_content(access, organization)?;
438 let numbers =
439 fields
440 .next()
441 .transpose()
442 .map_err(Error::Child)?
443 .ok_or(Error::Missing {
444 parent: node,
445 local: "NoticeNumbers",
446 })?;
447 if !named(access, numbers, XADES, "NoticeNumbers")? {
448 return Err(Error::Unexpected { node: numbers }.into());
449 }
450 if let Some(extra) = fields.next() {
451 return Err(Error::Unexpected {
452 node: extra.map_err(Error::Child)?,
453 }
454 .into());
455 }
456 for number in access.children(numbers) {
457 let number = number.map_err(Error::Child)?;
458 if !named(access, number, XADES, "int")? {
459 return Err(Error::Unexpected { node: number }.into());
460 }
461 integer(number)?;
462 }
463 } else if named(access, node, XADES, "ExplicitText")? {
464 if text.is_some() {
465 return Err(Error::Duplicate { node }.into());
466 }
467 properties::simple_content(access, node)?;
468 text = Some(node);
469 } else {
470 return Err(Error::Unexpected { node }.into());
471 }
472 }
473 Ok(())
474}
475
476fn check_transforms<X: Xml, W: Work>(
477 access: &Access<'_, X, W>,
478 parent: X::Id,
479 qualifiers: &[Qualifier<X::Id>],
480) -> PropertyResult<(), X> {
481 let mut populated = false;
482 let mut specification = None;
483 for child in access.children(parent) {
484 let node = child.map_err(Error::Child)?;
485 if !named(access, node, DS, "Transform")? {
486 return Err(Error::Unexpected { node });
487 }
488 let special = access.attribute(node, Name { namespace: "", local: "Algorithm" }, |value| {
489 let Some(value) = value else { return Ok(None) };
490 let value = access.trim_xml_whitespace(value)?;
491 access.equal(value, "http://uri.etsi.org/01903/v1.3.2/SignaturePolicy/SPDocDigestAsInSpecification").map(Some)
492 }).map_err(Error::Access)?.map_err(|cause| Error::Resource { node, cause })?;
493 let Some(special) = special else {
494 return Err(Error::Missing {
495 parent: node,
496 local: "Algorithm",
497 });
498 };
499 if special {
500 specification = Some(node);
501 }
502 populated = true;
503 }
504 if !populated {
505 return Err(Error::Missing {
506 parent,
507 local: "Transform",
508 });
509 }
510 if let Some(node) = specification {
511 let mut index = 0;
512 while index < qualifiers.len() {
513 access
515 .query(node, |_, _, work| Ok(work.charge_work(1)))
516 .map_err(Error::Access)?
517 .map_err(|cause| Error::Resource { node, cause })?;
518 if !qualifiers[index].specifications.is_empty() {
519 return Ok(());
520 }
521 index += 1;
522 }
523 return Err(Error::Missing {
524 parent: node,
525 local: "SPDocSpecification",
526 });
527 }
528 Ok(())
529}
530
531fn named<X: Xml, W: Work>(
532 access: &Access<'_, X, W>,
533 node: X::Id,
534 namespace: &str,
535 local: &str,
536) -> PropertyResult<bool, X> {
537 access
538 .has_name(node, Name { namespace, local })
539 .map_err(Error::Access)
540}
541
542fn read_specification<X: Xml, W: Work>(
543 access: &Access<'_, X, W>,
544 node: X::Id,
545) -> PropertyResult<identifier::Reading<X::Id>, X> {
546 let reading = identifier::read(access, node)?;
547 if reading.qualifier == Some(identifier::Qualifier::Uri) {
548 return Err(Error::Forbidden {
549 node: reading.identifier,
550 });
551 }
552 Ok(reading)
553}