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, Work};
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 work = inside.execution_in(execution);
100 let mut descriptions = work.vector();
101
102 while let Some(entry) = inside.next_element().field(field)? {
103 let at = |code| Error::new(code, field, entry.span().start);
104 if entry.tag() != Tag::constructed(universal::SEQUENCE) {
105 return Err(at(ErrorCode::Encoding(
106 structured_asn1::ErrorCode::UnexpectedTag,
107 )));
108 }
109
110 let mut pair = inside.enter(&entry).field(field)?;
111 let method = pair.read_oid().field(field)?;
112 let location = pair
113 .next_element()
114 .field(field)?
115 .ok_or_else(|| at(ErrorCode::MissingField))?;
116 let location = general_name::read(&pair, &location, field)?;
117 if !pair.is_empty() {
118 return Err(at(ErrorCode::TrailingData));
119 }
120
121 descriptions
122 .try_push(AccessDescription {
123 method,
124 location,
125 at: entry.span().start,
126 })
127 .map_err(|reason| Error::resource(reason, field, entry.span().start))?;
128 }
129
130 if descriptions.is_empty() {
131 return Err(Error::new(
132 ErrorCode::EmptySequence,
133 field,
134 extension.span().start,
135 ));
136 }
137 Ok(Self {
138 descriptions: descriptions.into_owned(),
139 field,
140 })
141 }
142}
143
144#[derive(Debug)]
146pub struct DistributionPoint<'a> {
147 full_name: OwnedVec<GeneralName<'a>>,
148 name_relative_to_issuer: Option<RelativeName<'a>>,
149 reasons: Option<BitString<'a>>,
150 issuer: OwnedVec<GeneralName<'a>>,
151}
152
153impl<'a> DistributionPoint<'a> {
154 #[must_use]
156 pub fn full_name(&self) -> &[GeneralName<'a>] {
157 &self.full_name
158 }
159
160 #[must_use]
163 pub fn name_relative_to_issuer(&self) -> Option<&RelativeName<'a>> {
164 self.name_relative_to_issuer.as_ref()
165 }
166
167 #[must_use]
171 pub fn reasons(&self) -> Option<BitString<'a>> {
172 self.reasons
173 }
174
175 #[must_use]
177 pub fn issuer(&self) -> &[GeneralName<'a>] {
178 &self.issuer
179 }
180}
181
182#[derive(Debug)]
184pub struct DistributionPoints<'a> {
185 points: OwnedVec<DistributionPoint<'a>>,
186}
187
188impl<'a> DistributionPoints<'a> {
189 #[must_use]
191 pub fn points(&self) -> &[DistributionPoint<'a>] {
192 &self.points
193 }
194
195 pub fn read(extension: &Extension<'a>, execution: &Memory) -> Result<Self> {
198 let field = if extension.kind() == oid::FRESHEST_CRL {
199 "extensions.freshestCRL"
200 } else {
201 "extensions.cRLDistributionPoints"
202 };
203
204 let mut inside = extension::sequence(extension, field, execution)?;
205 let work = inside.execution_in(execution);
206 let mut points = work.vector();
207 while let Some(entry) = inside.next_element().field(field)? {
208 points
209 .try_push(read_point(&inside, &entry, field)?)
210 .map_err(|reason| Error::resource(reason, field, entry.span().start))?;
211 }
212
213 if points.is_empty() {
214 return Err(Error::new(
215 ErrorCode::EmptySequence,
216 field,
217 extension.span().start,
218 ));
219 }
220 Ok(Self {
221 points: points.into_owned(),
222 })
223 }
224}
225
226fn read_point<'a>(
227 parent: &Reader<'a>,
228 element: &Element<'a>,
229 field: &'static str,
230) -> Result<DistributionPoint<'a>> {
231 let fail = |code| Error::new(code, field, element.span().start);
232
233 if element.tag() != Tag::constructed(universal::SEQUENCE) {
234 return Err(fail(ErrorCode::Encoding(
235 structured_asn1::ErrorCode::UnexpectedTag,
236 )));
237 }
238
239 let mut inside = parent.enter(element).field(field)?;
240 let mut point = DistributionPoint {
241 full_name: parent.memory().vector(),
242 name_relative_to_issuer: None,
243 reasons: None,
244 issuer: parent.memory().vector(),
245 };
246
247 let mut last_number = None;
250 while let Some(entry) = inside.next_element().field(field)? {
251 let tag = extension::context_of(entry.tag());
252 match tag {
253 Some((0, true)) if last_number.is_none() => {
254 read_point_name(&inside, &entry, field, &mut point)?;
255 }
256 Some((1, false)) if last_number < Some(1) => {
257 let reasons = inside.bit_string(&entry).field(field)?;
258 inside
261 .charge(reasons.as_bytes().len() as u64)
262 .field(field)?;
263 if !(1..=8).any(|bit| reasons.bit(bit)) {
272 return Err(Error::new(
273 ErrorCode::MalformedValue,
274 field,
275 entry.span().start,
276 ));
277 }
278 if inside.encoding().is_der()
285 && (reasons.len() > 9
286 || (!reasons.is_empty() && !reasons.bit(reasons.len() - 1)))
287 {
288 return Err(Error::new(
289 ErrorCode::MalformedValue,
290 field,
291 entry.span().start,
292 ));
293 }
294 point.reasons = Some(reasons);
295 }
296 Some((2, true)) if last_number < Some(2) => {
297 let issuer = general_name::read_all(&inside, &entry, field)?;
298 if !issuer
311 .iter()
312 .all(|name| matches!(name, general_name::GeneralName::Directory(_)))
313 || (point.name_relative_to_issuer.is_some() && issuer.len() > 1)
314 {
315 return Err(Error::new(
316 ErrorCode::MalformedValue,
317 field,
318 entry.span().start,
319 ));
320 }
321 point.issuer = issuer;
322 }
323 _ => {
324 return Err(Error::new(
325 ErrorCode::UnexpectedField,
326 field,
327 entry.span().start,
328 ));
329 }
330 }
331 last_number = tag.map(|(number, _)| number);
332 }
333
334 if point.full_name.is_empty()
347 && point.name_relative_to_issuer.is_none()
348 && point.issuer.is_empty()
349 {
350 return Err(fail(ErrorCode::MalformedValue));
351 }
352
353 Ok(point)
354}
355
356#[derive(Debug)]
360pub(crate) enum PointName<'a> {
361 Full(OwnedVec<GeneralName<'a>>),
362 Relative(RelativeName<'a>),
363}
364
365pub(crate) fn read_distribution_name<'a>(
367 parent: &Reader<'a>,
368 element: &Element<'a>,
369 field: &'static str,
370) -> Result<PointName<'a>> {
371 let fail = |code| Error::new(code, field, element.span().start);
372 let mut inside = parent.enter(element).field(field)?;
373 let chosen = inside
374 .next_element()
375 .field(field)?
376 .ok_or_else(|| fail(ErrorCode::MissingField))?;
377 let name = match extension::context_of(chosen.tag()) {
378 Some((0, true)) => PointName::Full(general_name::read_locations(&inside, &chosen, field)?),
379 Some((1, true)) => {
380 let relative = name::read_relative(&inside, &chosen, field)?;
381 for attribute in relative.attributes() {
382 if !name::well_formed_in(attribute, &inside, field)? {
383 return Err(fail(ErrorCode::MalformedValue));
384 }
385 }
386 PointName::Relative(relative)
387 }
388 _ => {
389 return Err(fail(ErrorCode::Encoding(
390 structured_asn1::ErrorCode::UnexpectedTag,
391 )));
392 }
393 };
394 if !inside.is_empty() {
395 return Err(fail(ErrorCode::TrailingData));
396 }
397 Ok(name)
398}
399
400fn read_point_name<'a>(
401 parent: &Reader<'a>,
402 element: &Element<'a>,
403 field: &'static str,
404 point: &mut DistributionPoint<'a>,
405) -> Result<()> {
406 match read_distribution_name(parent, element, field)? {
407 PointName::Full(names) => point.full_name = names,
408 PointName::Relative(name) => point.name_relative_to_issuer = Some(name),
409 }
410 Ok(())
411}
412
413#[cfg(test)]
414mod tests;