1use crate::error::{Error, ErrorCode, Located, Result};
10use crate::extension::{self, Extension};
11use crate::general_name::{self, GeneralName};
12use crate::name::{self, RelativeName};
13use crate::oid;
14use structured_asn1::memory::{Memory, OwnedVec};
15use structured_asn1::{BitString, Element, Oid, Reader, Tag, universal};
16
17#[derive(Debug)]
19pub struct AccessDescription<'a> {
20 method: Oid<'a>,
21 location: GeneralName<'a>,
22 at: u64,
23}
24
25impl<'a> AccessDescription<'a> {
26 #[must_use]
28 pub fn method(&self) -> Oid<'a> {
29 self.method
30 }
31
32 #[must_use]
34 pub fn location(&self) -> &GeneralName<'a> {
35 &self.location
36 }
37}
38
39#[derive(Debug)]
42pub struct InfoAccess<'a> {
43 descriptions: OwnedVec<AccessDescription<'a>>,
44 field: &'static str,
45}
46
47impl<'a> InfoAccess<'a> {
48 #[must_use]
50 pub fn descriptions(&self) -> &[AccessDescription<'a>] {
51 &self.descriptions
52 }
53
54 pub fn locations_for<'n, 'q>(
58 &'n self,
59 method: Oid<'q>,
60 execution: &'q Memory,
61 ) -> impl Iterator<Item = Result<&'n GeneralName<'a>>> + 'q
62 where
63 'n: 'q,
64 {
65 let mut descriptions = self.descriptions.iter();
66 let mut failed = false;
67 core::iter::from_fn(move || {
68 if failed {
69 return None;
70 }
71 for description in descriptions.by_ref() {
72 let work = 1 + description
73 .method
74 .as_bytes()
75 .len()
76 .max(method.as_bytes().len()) as u64;
77 if let Err(reason) = execution.charge_work(work) {
78 failed = true;
79 return Some(Err(Error::resource(reason, self.field, description.at)));
80 }
81 if description.method == method {
82 return Some(Ok(description.location()));
83 }
84 }
85 None
86 })
87 }
88
89 pub fn read(extension: &Extension<'a>, execution: &Memory) -> Result<Self> {
92 let field = if extension.kind() == oid::SUBJECT_INFO_ACCESS {
93 "extensions.subjectInfoAccess"
94 } else {
95 "extensions.authorityInfoAccess"
96 };
97
98 let mut inside = extension::sequence(extension, field, execution)?;
99 let mut descriptions = inside.memory().vector();
100
101 while let Some(entry) = inside.next_element().field(field)? {
102 let at = |code| Error::new(code, field, entry.span().start);
103 if entry.tag() != Tag::constructed(universal::SEQUENCE) {
104 return Err(at(ErrorCode::Encoding(
105 structured_asn1::ErrorCode::UnexpectedTag,
106 )));
107 }
108
109 let mut pair = inside.enter(&entry).field(field)?;
110 let method = pair.read_oid().field(field)?;
111 let location = pair
112 .next_element()
113 .field(field)?
114 .ok_or_else(|| at(ErrorCode::MissingField))?;
115 let location = general_name::read(&pair, &location, field)?;
116 if !pair.is_empty() {
117 return Err(at(ErrorCode::TrailingData));
118 }
119
120 descriptions
121 .try_push(AccessDescription {
122 method,
123 location,
124 at: entry.span().start,
125 })
126 .map_err(|reason| Error::resource(reason, field, entry.span().start))?;
127 }
128
129 if descriptions.is_empty() {
130 return Err(Error::new(
131 ErrorCode::EmptySequence,
132 field,
133 extension.span().start,
134 ));
135 }
136 Ok(Self {
137 descriptions,
138 field,
139 })
140 }
141}
142
143#[derive(Debug)]
145pub struct DistributionPoint<'a> {
146 full_name: OwnedVec<GeneralName<'a>>,
147 name_relative_to_issuer: Option<RelativeName<'a>>,
148 reasons: Option<BitString<'a>>,
149 issuer: OwnedVec<GeneralName<'a>>,
150}
151
152impl<'a> DistributionPoint<'a> {
153 #[must_use]
155 pub fn full_name(&self) -> &[GeneralName<'a>] {
156 &self.full_name
157 }
158
159 #[must_use]
162 pub fn name_relative_to_issuer(&self) -> Option<&RelativeName<'a>> {
163 self.name_relative_to_issuer.as_ref()
164 }
165
166 #[must_use]
170 pub fn reasons(&self) -> Option<BitString<'a>> {
171 self.reasons
172 }
173
174 #[must_use]
176 pub fn issuer(&self) -> &[GeneralName<'a>] {
177 &self.issuer
178 }
179}
180
181#[derive(Debug)]
183pub struct DistributionPoints<'a> {
184 points: OwnedVec<DistributionPoint<'a>>,
185}
186
187impl<'a> DistributionPoints<'a> {
188 #[must_use]
190 pub fn points(&self) -> &[DistributionPoint<'a>] {
191 &self.points
192 }
193
194 pub fn read(extension: &Extension<'a>, execution: &Memory) -> Result<Self> {
197 let field = if extension.kind() == oid::FRESHEST_CRL {
198 "extensions.freshestCRL"
199 } else {
200 "extensions.cRLDistributionPoints"
201 };
202
203 let mut inside = extension::sequence(extension, field, execution)?;
204 let mut points = inside.memory().vector();
205 while let Some(entry) = inside.next_element().field(field)? {
206 points
207 .try_push(read_point(&inside, &entry, field)?)
208 .map_err(|reason| Error::resource(reason, field, entry.span().start))?;
209 }
210
211 if points.is_empty() {
212 return Err(Error::new(
213 ErrorCode::EmptySequence,
214 field,
215 extension.span().start,
216 ));
217 }
218 Ok(Self { points })
219 }
220}
221
222fn read_point<'a>(
223 parent: &Reader<'a>,
224 element: &Element<'a>,
225 field: &'static str,
226) -> Result<DistributionPoint<'a>> {
227 let fail = |code| Error::new(code, field, element.span().start);
228
229 if element.tag() != Tag::constructed(universal::SEQUENCE) {
230 return Err(fail(ErrorCode::Encoding(
231 structured_asn1::ErrorCode::UnexpectedTag,
232 )));
233 }
234
235 let mut inside = parent.enter(element).field(field)?;
236 let mut point = DistributionPoint {
237 full_name: parent.memory().vector(),
238 name_relative_to_issuer: None,
239 reasons: None,
240 issuer: parent.memory().vector(),
241 };
242
243 let mut last_number = None;
246 while let Some(entry) = inside.next_element().field(field)? {
247 let tag = extension::context_of(entry.tag());
248 match tag {
249 Some((0, true)) if last_number.is_none() => {
250 read_point_name(&inside, &entry, field, &mut point)?;
251 }
252 Some((1, false)) if last_number < Some(1) => {
253 let reasons = inside.bit_string(&entry).field(field)?;
254 inside
257 .charge(reasons.as_bytes().len() as u64)
258 .field(field)?;
259 if !(1..=8).any(|bit| reasons.bit(bit)) {
268 return Err(Error::new(
269 ErrorCode::MalformedValue,
270 field,
271 entry.span().start,
272 ));
273 }
274 if inside.encoding().is_der()
281 && (reasons.len() > 9
282 || (!reasons.is_empty() && !reasons.bit(reasons.len() - 1)))
283 {
284 return Err(Error::new(
285 ErrorCode::MalformedValue,
286 field,
287 entry.span().start,
288 ));
289 }
290 point.reasons = Some(reasons);
291 }
292 Some((2, true)) if last_number < Some(2) => {
293 let issuer = general_name::read_all(&inside, &entry, field)?;
294 if !issuer
307 .iter()
308 .all(|name| matches!(name, general_name::GeneralName::Directory(_)))
309 || (point.name_relative_to_issuer.is_some() && issuer.len() > 1)
310 {
311 return Err(Error::new(
312 ErrorCode::MalformedValue,
313 field,
314 entry.span().start,
315 ));
316 }
317 point.issuer = issuer;
318 }
319 _ => {
320 return Err(Error::new(
321 ErrorCode::UnexpectedField,
322 field,
323 entry.span().start,
324 ));
325 }
326 }
327 last_number = tag.map(|(number, _)| number);
328 }
329
330 if point.full_name.is_empty()
343 && point.name_relative_to_issuer.is_none()
344 && point.issuer.is_empty()
345 {
346 return Err(fail(ErrorCode::MalformedValue));
347 }
348
349 Ok(point)
350}
351
352fn read_point_name<'a>(
356 parent: &Reader<'a>,
357 element: &Element<'a>,
358 field: &'static str,
359 point: &mut DistributionPoint<'a>,
360) -> Result<()> {
361 let fail = |code| Error::new(code, field, element.span().start);
362
363 let mut inside = parent.enter(element).field(field)?;
364 let chosen = inside
365 .next_element()
366 .field(field)?
367 .ok_or_else(|| fail(ErrorCode::MissingField))?;
368
369 match extension::context_of(chosen.tag()) {
370 Some((0, true)) => point.full_name = general_name::read_all(&inside, &chosen, field)?,
371 Some((1, true)) => {
372 let relative = name::read_relative(&inside, &chosen, field)?;
373 for attribute in relative.attributes() {
377 if !name::well_formed_in(attribute, &inside, field)? {
378 return Err(fail(ErrorCode::MalformedValue));
379 }
380 }
381 point.name_relative_to_issuer = Some(relative);
382 }
383 _ => {
384 return Err(fail(ErrorCode::Encoding(
385 structured_asn1::ErrorCode::UnexpectedTag,
386 )));
387 }
388 }
389
390 if !inside.is_empty() {
391 return Err(fail(ErrorCode::TrailingData));
392 }
393 Ok(())
394}
395
396#[cfg(test)]
397mod tests;