structured_cms/attribute_certificate/
proxy.rs1use super::target::{CheckError, Membership, TargetInformation};
7use crate::{Error, Result};
8use structured_asn1::memory::{Execution, Work};
9use structured_asn1::{Element, Oid, Parser};
10use structured_pkix::Extension;
11use structured_pkix::general_name::GeneralName;
12
13const FIELD: &str = "attributeCertificate.proxyInfo";
14pub const IDENTIFIER: Oid<'static> = Oid::from_bytes(&[43, 6, 1, 5, 5, 7, 1, 10]);
16
17#[derive(Debug, Clone, Copy)]
19pub enum Sender<'a, 'n> {
20 Holder,
22 Proxy(&'n [GeneralName<'a>]),
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum Subject {
29 Sender,
31 Recipient,
33 Intermediate(usize),
35}
36
37#[derive(Debug)]
39pub struct ProxyInfo<'a> {
40 parser: &'a Parser,
41 targets: TargetInformation<'a>,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum Decision {
47 Matches {
49 group: usize,
51 },
52 Differs,
54 Unproven,
56 NonCritical,
58 ProhibitedTargetCertificate {
60 target: usize,
62 },
63}
64
65impl<'a> ProxyInfo<'a> {
66 pub fn read<W: Work>(extension: &Extension<'a>, work: &W) -> Result<Self> {
69 Ok(Self {
70 parser: extension.parser(),
71 targets: TargetInformation::read_as(extension, work, IDENTIFIER, FIELD)?,
72 })
73 }
74
75 #[must_use]
77 pub fn element(&self) -> Element<'a> {
78 self.targets.element()
79 }
80
81 #[must_use]
84 pub fn groups(&self) -> &[super::target::Group<'a>] {
85 self.targets.groups()
86 }
87
88 #[must_use]
90 pub fn targets(&self) -> &[super::target::Target<'a>] {
91 self.targets.targets()
92 }
93
94 #[must_use]
96 pub fn certificates(&self) -> &[super::target::TargetCertificate<'a>] {
97 self.targets.certificates()
98 }
99
100 #[must_use]
102 pub fn is_critical(&self) -> bool {
103 self.targets.is_critical()
104 }
105
106 pub fn check<W: Work, E>(
116 &self,
117 sender: Sender<'_, '_>,
118 recipient: &[GeneralName<'_>],
119 intermediates: &[&[GeneralName<'_>]],
120 work: &W,
121 mut membership: impl FnMut(
122 Subject,
123 &GeneralName<'a>,
124 &Execution<'_>,
125 ) -> core::result::Result<Membership, E>,
126 ) -> core::result::Result<Decision, CheckError<E>> {
127 let execution = work.execution_for(self.parser);
128 let pay = |at| {
129 execution
130 .charge_work(1)
131 .map_err(|e| CheckError::Processing(Error::resource(e, FIELD, at)))
132 };
133 pay(self.targets.element().span().start)?;
134 if !self.targets.is_critical() {
135 return Ok(Decision::NonCritical);
136 }
137 if let Some(entry) = self.targets.certificates().first() {
138 return Ok(Decision::ProhibitedTargetCertificate {
139 target: entry.target,
140 });
141 }
142 let mut unknown = false;
143 for (index, group) in self.targets.groups().iter().enumerate() {
147 pay(group.element.span().start)?;
148 let mut undecided = false;
149 match self.matches(
150 index,
151 Subject::Recipient,
152 recipient,
153 &execution,
154 &mut membership,
155 )? {
156 Membership::NotMember => continue,
157 Membership::Unknown => undecided = true,
158 Membership::Member => {}
159 }
160 if let Sender::Proxy(names) = sender {
161 match self.matches(index, Subject::Sender, names, &execution, &mut membership)? {
162 Membership::NotMember => continue,
163 Membership::Unknown => undecided = true,
164 Membership::Member => {}
165 }
166 }
167 let mut excluded = false;
168 for (ordinal, names) in intermediates.iter().enumerate() {
169 pay(group.element.span().start)?;
170 match self.matches(
171 index,
172 Subject::Intermediate(ordinal),
173 names,
174 &execution,
175 &mut membership,
176 )? {
177 Membership::NotMember => {
178 excluded = true;
179 break;
180 }
181 Membership::Unknown => undecided = true,
182 Membership::Member => {}
183 }
184 }
185 if excluded {
186 continue;
187 }
188 if !undecided {
189 return Ok(Decision::Matches { group: index });
190 }
191 unknown = true;
192 }
193 Ok(if unknown {
194 Decision::Unproven
195 } else {
196 Decision::Differs
197 })
198 }
199
200 fn matches<E>(
201 &self,
202 group: usize,
203 subject: Subject,
204 names: &[GeneralName<'_>],
205 execution: &Execution<'_>,
206 membership: &mut impl FnMut(
207 Subject,
208 &GeneralName<'a>,
209 &Execution<'_>,
210 ) -> core::result::Result<Membership, E>,
211 ) -> core::result::Result<Membership, CheckError<E>> {
212 let mut unknown = false;
213 for target in &self.targets.targets()[self.targets.groups()[group].targets.clone()] {
214 match super::target::matches_target(
215 target,
216 names,
217 execution,
218 FIELD,
219 &mut |name, work| membership(subject, name, work),
220 )? {
221 Membership::Member => return Ok(Membership::Member),
222 Membership::Unknown => unknown = true,
223 Membership::NotMember => {}
224 }
225 }
226 Ok(if unknown {
227 Membership::Unknown
228 } else {
229 Membership::NotMember
230 })
231 }
232}