structured_xades/material/
catalogue.rs1use super::Kind;
4use crate::container::XADES;
5use crate::properties::{Error, PropertyResult};
6use crate::xml::{Access, Name, Snapshot, Xml};
7use structured_asn1::memory::{OwnedVec, Work};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum Entry<N> {
12 Encapsulated {
14 node: N,
16 kind: Kind,
18 },
19 OtherCertificate {
22 node: N,
24 },
25 OtherStatus {
28 node: N,
30 },
31}
32
33#[derive(Debug)]
35pub struct Catalogue<N, D, G> {
36 snapshot: Snapshot<D, G>,
37 parent: N,
38 entries: OwnedVec<Entry<N>>,
39}
40
41impl<N: Copy, D: Copy, G: Copy> Catalogue<N, D, G> {
42 #[must_use]
44 pub fn snapshot(&self) -> Snapshot<D, G> {
45 self.snapshot
46 }
47
48 #[must_use]
50 pub fn parent(&self) -> N {
51 self.parent
52 }
53
54 #[must_use]
57 pub fn entries(&self) -> &[Entry<N>] {
58 &self.entries
59 }
60}
61
62pub type Reading<X> = Catalogue<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>;
64
65#[derive(Clone, Copy)]
69pub(super) enum ContainerKind {
70 Certificates,
71 Revocation,
72 AttributeCertificates,
73 AttributeRevocation,
74}
75
76impl ContainerKind {
77 pub(super) fn attribute(self) -> bool {
78 matches!(
79 self,
80 Self::AttributeCertificates | Self::AttributeRevocation
81 )
82 }
83 pub(super) fn certificates(self) -> bool {
84 matches!(self, Self::Certificates | Self::AttributeCertificates)
85 }
86 pub(super) fn inventory(role: crate::unsigned::Role) -> Option<Self> {
87 match role {
88 crate::unsigned::Role::Certificates => Some(Self::Certificates),
89 crate::unsigned::Role::Revocation => Some(Self::Revocation),
90 crate::unsigned::Role::AttributeCertificates => Some(Self::AttributeCertificates),
91 crate::unsigned::Role::AttributeRevocation => Some(Self::AttributeRevocation),
92 _ => None,
93 }
94 }
95}
96
97pub(super) fn container_kind<X: Xml, W: Work>(
98 access: &Access<'_, X, W>,
99 node: X::Id,
100) -> PropertyResult<Option<ContainerKind>, X> {
101 for (local, kind) in [
102 ("CertificateValues", ContainerKind::Certificates),
103 ("RevocationValues", ContainerKind::Revocation),
104 (
105 "AttrAuthoritiesCertValues",
106 ContainerKind::AttributeCertificates,
107 ),
108 (
109 "AttributeRevocationValues",
110 ContainerKind::AttributeRevocation,
111 ),
112 ] {
113 if named(access, node, local)? {
114 return Ok(Some(kind));
115 }
116 }
117 Ok(None)
118}
119
120pub fn read<X: Xml, W: Work>(
128 access: &Access<'_, X, W>,
129 parent: X::Id,
130) -> PropertyResult<Reading<X>, X> {
131 let kind = container_kind(access, parent)?.ok_or(Error::Unexpected { node: parent })?;
135 let certificates = kind.certificates();
136 let mut entries = access
137 .query(parent, |_, _, work| Ok(work.vector()))
138 .map_err(Error::Access)?;
139 if certificates {
140 for child in access.children(parent) {
141 let node = child.map_err(Error::Child)?;
142 let entry = if named(access, node, "EncapsulatedX509Certificate")? {
143 Entry::Encapsulated {
144 node,
145 kind: Kind::Certificate,
146 }
147 } else if named(access, node, "OtherCertificate")? {
148 Entry::OtherCertificate { node }
149 } else {
150 return Err(Error::Unexpected { node });
151 };
152 entries
153 .try_push(entry)
154 .map_err(|cause| Error::Resource { node, cause })?;
155 }
156 } else {
157 let mut previous = None;
158 for child in access.children(parent) {
159 let group = child.map_err(Error::Child)?;
160 let (rank, member, kind) = if named(access, group, "CRLValues")? {
161 (0, "EncapsulatedCRLValue", Some(Kind::Crl))
162 } else if named(access, group, "OCSPValues")? {
163 (1, "EncapsulatedOCSPValue", Some(Kind::Ocsp))
164 } else if named(access, group, "OtherValues")? {
165 (2, "OtherValue", None)
166 } else {
167 return Err(Error::Unexpected { node: group });
168 };
169 if let Some(earlier) = previous {
170 if rank == earlier {
171 return Err(Error::Duplicate { node: group });
172 }
173 if rank < earlier {
174 return Err(Error::Order { node: group });
175 }
176 }
177 previous = Some(rank);
178 let mut present = false;
179 for child in access.children(group) {
180 let node = child.map_err(Error::Child)?;
181 if !named(access, node, member)? {
182 return Err(Error::Unexpected { node });
183 }
184 let entry = match kind {
185 Some(kind) => Entry::Encapsulated { node, kind },
186 None => Entry::OtherStatus { node },
187 };
188 entries
189 .try_push(entry)
190 .map_err(|cause| Error::Resource { node, cause })?;
191 present = true;
192 }
193 if !present {
194 return Err(Error::Missing {
195 parent: group,
196 local: member,
197 });
198 }
199 }
200 }
201 Ok(Catalogue {
202 snapshot: access.snapshot(),
203 parent,
204 entries: entries.into_owned(),
205 })
206}
207
208fn named<X: Xml, W: Work>(
209 access: &Access<'_, X, W>,
210 node: X::Id,
211 local: &'static str,
212) -> PropertyResult<bool, X> {
213 access
214 .has_name(
215 node,
216 Name {
217 namespace: XADES,
218 local,
219 },
220 )
221 .map_err(Error::Access)
222}