1use crate::{Error, ErrorCode, Result};
4use structured_asn1::memory::{Execution, Memory, OwnedVec, Work};
5use structured_asn1::{Element, Encoding, Oid, Parser, Reader, Span, Tag, universal};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Placement {
10 Signed,
12 Unsigned,
14}
15
16impl Placement {
17 fn field(self) -> &'static str {
18 match self {
19 Self::Signed => "signerInfo.signedAttrs",
20 Self::Unsigned => "signerInfo.unsignedAttrs",
21 }
22 }
23 fn tag(self) -> Tag {
24 Tag::context(
25 true,
26 match self {
27 Self::Signed => 0,
28 Self::Unsigned => 1,
29 },
30 )
31 }
32}
33
34#[derive(Debug)]
36pub struct Attribute<'a> {
37 kind: Oid<'a>,
38 values: OwnedVec<Element<'a>>,
39 element: Element<'a>,
40 parser: &'a Parser,
41 depth: u32,
42 encoding: Encoding,
43}
44
45impl<'a> Attribute<'a> {
46 fn read(parent: &Reader<'a>, element: &Element<'a>, field: &'static str) -> Result<Self> {
47 if element.tag() != Tag::constructed(universal::SEQUENCE) {
48 return Err(Error::schema(
49 ErrorCode::UnexpectedTag,
50 field,
51 element.span().start,
52 ));
53 }
54 let mut inside = parent
55 .enter(element)
56 .map_err(|error| Error::encoding(error, field))?;
57 let kind = inside
58 .read_oid()
59 .map_err(|error| Error::encoding(error, field))?;
60 let set = inside
61 .expect(Tag::constructed(universal::SET))
62 .map_err(|error| Error::encoding(error, field))?;
63 let mut members = inside
64 .enter(&set)
65 .map_err(|error| Error::encoding(error, field))?;
66 let execution = parent.execution();
67 let mut values = execution.vector();
68 let mut previous = None;
69 while let Some(value) = members
76 .next_element()
77 .map_err(|error| Error::encoding(error, field))?
78 {
79 if members.encoding().is_der() {
80 structured_pkix::der::conforms(&members, &value, field).map_err(Error::pkix)?;
81 if let Some(earlier) = previous
82 && !structured_pkix::der::set_ordered(&members, earlier, &value, field)
83 .map_err(Error::pkix)?
84 {
85 return Err(Error::schema(
86 ErrorCode::AttributeOrder,
87 field,
88 value.span().start,
89 ));
90 }
91 previous = Some(value.as_bytes());
92 }
93 values
94 .try_push(value)
95 .map_err(|reason| Error::resource(reason, field, value.span().start))?;
96 }
97 if !inside.is_empty() {
98 return Err(Error::schema(
99 ErrorCode::TrailingData,
100 field,
101 inside.offset(),
102 ));
103 }
104 Ok(Self {
105 kind,
106 values: values.into_owned(),
107 element: *element,
108 parser: members.parser(),
109 depth: members.depth(),
110 encoding: members.encoding(),
111 })
112 }
113
114 #[must_use]
116 pub fn kind(&self) -> Oid<'a> {
117 self.kind
118 }
119
120 #[must_use]
122 pub fn values(&self) -> &[Element<'a>] {
123 &self.values
124 }
125
126 #[must_use]
128 pub fn span(&self) -> Span {
129 self.element.span()
130 }
131
132 #[must_use]
134 pub fn as_bytes(&self) -> &'a [u8] {
135 self.element.as_bytes()
136 }
137
138 pub fn value_reader(
144 &self,
145 index: usize,
146 execution: &Memory,
147 field: &'static str,
148 ) -> Result<Option<Reader<'a>>> {
149 let Some(value) = self.selected_value(index, execution, field)? else {
150 return Ok(None);
151 };
152 debug_assert!(self.depth > 0);
153 self.parser
154 .read_nested_in(
155 value.as_bytes(),
156 value.span().start,
157 self.encoding,
158 self.depth - 1,
159 execution,
160 )
161 .map(Some)
162 .map_err(|error| Error::encoding(error, field))
163 }
164
165 pub fn value_reader_in<'query>(
169 &self,
170 index: usize,
171 parent: &Reader<'query>,
172 field: &'static str,
173 ) -> Result<Option<Reader<'query>>>
174 where
175 'a: 'query,
176 {
177 if !core::ptr::eq(self.parser, parent.parser()) {
178 return Err(Error::pkix(structured_pkix::Error::new(
179 structured_pkix::ErrorCode::ForeignReader,
180 field,
181 self.element.span().start,
182 )));
183 }
184 let Some(value) = self.selected_value(index, &parent.execution(), field)? else {
185 return Ok(None);
186 };
187 debug_assert!(self.depth > 0);
188 self.parser
189 .read_nested_query_in(
190 parent,
191 value.as_bytes(),
192 value.span().start,
193 self.encoding,
194 self.depth - 1,
195 )
196 .map(Some)
197 .map_err(|error| Error::encoding(error, field))
198 }
199
200 fn selected_value<W: Work>(
201 &self,
202 index: usize,
203 execution: &W,
204 field: &'static str,
205 ) -> Result<Option<Element<'a>>> {
206 execution
207 .charge_work(1)
208 .map_err(|reason| Error::resource(reason, field, self.element.span().start))?;
209 Ok(self.values.get(index).copied())
210 }
211
212 pub fn single(&self, field: &'static str) -> Result<&Element<'a>> {
214 match &*self.values {
215 [value] => Ok(value),
216 _ => Err(Error::schema(
217 ErrorCode::AttributeCardinality,
218 field,
219 self.element.span().start,
220 )),
221 }
222 }
223}
224
225#[derive(Debug)]
227pub struct Attributes<'a> {
228 items: OwnedVec<Attribute<'a>>,
229 element: Element<'a>,
230 placement: Placement,
231}
232
233impl<'a> Attributes<'a> {
234 pub fn read(parent: &Reader<'a>, element: &Element<'a>, placement: Placement) -> Result<Self> {
242 if element.tag() != placement.tag() {
243 return Err(Error::schema(
244 ErrorCode::UnexpectedTag,
245 placement.field(),
246 element.span().start,
247 ));
248 }
249 if placement == Placement::Signed {
250 let mut strict = parent
251 .reread(element, Encoding::Der)
252 .map_err(|error| Error::encoding(error, placement.field()))?;
253 let original = strict
254 .expect(placement.tag())
255 .map_err(|error| Error::encoding(error, placement.field()))?;
256 Self::read_set(&strict, &original, placement)
257 } else {
258 Self::read_set(parent, element, placement)
259 }
260 }
261
262 fn read_set(parent: &Reader<'a>, element: &Element<'a>, placement: Placement) -> Result<Self> {
263 let field = placement.field();
264 let mut inside = parent
265 .enter(element)
266 .map_err(|error| Error::encoding(error, field))?;
267 let execution = parent.execution();
268 let mut items = execution.vector();
269 let mut previous = None;
270 while let Some(member) = inside
271 .next_element()
272 .map_err(|error| Error::encoding(error, field))?
273 {
274 if inside.encoding().is_der() {
275 if let Some(earlier) = previous
276 && !structured_pkix::der::set_ordered(&inside, earlier, &member, field)
277 .map_err(Error::pkix)?
278 {
279 return Err(Error::schema(
280 ErrorCode::AttributeOrder,
281 field,
282 member.span().start,
283 ));
284 }
285 previous = Some(member.as_bytes());
286 }
287 let attribute = Attribute::read(&inside, &member, field)?;
288 items
289 .try_push(attribute)
290 .map_err(|reason| Error::resource(reason, field, member.span().start))?;
291 }
292 if items.is_empty() {
293 return Err(Error::schema(
294 ErrorCode::EmptyAttributes,
295 field,
296 element.span().start,
297 ));
298 }
299 Ok(Self {
300 items: items.into_owned(),
301 element: *element,
302 placement,
303 })
304 }
305
306 #[must_use]
308 pub fn items(&self) -> &[Attribute<'a>] {
309 &self.items
310 }
311
312 #[must_use]
314 pub fn element(&self) -> &Element<'a> {
315 &self.element
316 }
317
318 pub fn all<'s>(&'s self, kind: Oid<'s>, execution: &Memory) -> Matching<'s, 'a> {
323 Matching {
324 attributes: self,
325 kind,
326 execution: execution.clone(),
327 next: 0,
328 stopped: false,
329 }
330 }
331
332 pub fn all_in<'s>(
334 &'s self,
335 kind: Oid<'s>,
336 parent: &'s Reader<'_>,
337 ) -> Matching<'s, 'a, Execution<'s>> {
338 Matching {
339 attributes: self,
340 kind,
341 execution: parent.execution(),
342 next: 0,
343 stopped: false,
344 }
345 }
346
347 pub fn unique_in<'s>(
352 &'s self,
353 kind: Oid<'s>,
354 parent: &'s Reader<'_>,
355 ) -> Result<Option<&'s Attribute<'a>>> {
356 let mut found = None;
357 for result in self.all_in(kind, parent) {
358 let attribute = result?;
359 if found.is_some() {
360 return Err(Error::schema(
361 ErrorCode::AttributeCardinality,
362 self.placement.field(),
363 attribute.span().start,
364 ));
365 }
366 found = Some(attribute);
367 }
368 Ok(found)
369 }
370
371 #[must_use]
376 pub fn signed_bytes(&self) -> Option<[&'a [u8]; 2]> {
377 if self.placement != Placement::Signed {
378 return None;
379 }
380 Some([&[0x31], &self.element.as_bytes()[1..]])
381 }
382}
383
384pub struct Matching<'s, 'a, W: Work = Memory> {
386 attributes: &'s Attributes<'a>,
387 kind: Oid<'s>,
388 execution: W,
389 next: usize,
390 stopped: bool,
391}
392
393impl<'s, 'a, W: Work> Iterator for Matching<'s, 'a, W> {
394 type Item = Result<&'s Attribute<'a>>;
395
396 fn next(&mut self) -> Option<Self::Item> {
397 self.attributes.next_matching(
398 self.kind,
399 &self.execution,
400 &mut self.next,
401 &mut self.stopped,
402 )
403 }
404}
405
406impl<'a> Attributes<'a> {
407 pub(crate) fn next_matching<'s>(
408 &'s self,
409 kind: Oid<'_>,
410 execution: &impl Work,
411 next: &mut usize,
412 stopped: &mut bool,
413 ) -> Option<Result<&'s Attribute<'a>>> {
414 if *stopped {
415 return None;
416 }
417 let field = self.placement.field();
418 loop {
419 if let Err(reason) = execution.charge_work(1) {
420 *stopped = true;
421 let at = self
422 .items
423 .get(*next)
424 .map_or(self.element.span().start, |attribute| {
425 attribute.span().start
426 });
427 return Some(Err(Error::resource(reason, field, at)));
428 }
429 let Some(attribute) = self.items.get(*next) else {
430 *stopped = true;
431 return None;
432 };
433 *next += 1;
434 if attribute.kind.as_bytes().len() != kind.as_bytes().len() {
435 continue;
436 }
437 if let Err(reason) = execution.charge_work(attribute.kind.as_bytes().len() as u64) {
438 *stopped = true;
439 return Some(Err(Error::resource(reason, field, attribute.span().start)));
440 }
441 if attribute.kind == kind {
442 return Some(Ok(attribute));
443 }
444 }
445 }
446}
447
448impl<W: Work> core::iter::FusedIterator for Matching<'_, '_, W> {}