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
7const SIGNED_SINGLETONS: [Oid<'static>; 4] = [
8 crate::oid::CONTENT_TYPE,
9 crate::oid::MESSAGE_DIGEST,
10 crate::oid::SIGNING_TIME,
11 crate::oid::ALGORITHM_PROTECTION,
12];
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum Placement {
17 Signed,
19 Unsigned,
21}
22
23impl Placement {
24 fn field(self) -> &'static str {
25 match self {
26 Self::Signed => "signerInfo.signedAttrs",
27 Self::Unsigned => "signerInfo.unsignedAttrs",
28 }
29 }
30 fn tag(self) -> Tag {
31 Tag::context(
32 true,
33 match self {
34 Self::Signed => 0,
35 Self::Unsigned => 1,
36 },
37 )
38 }
39}
40
41#[derive(Debug)]
43pub struct Attribute<'a> {
44 kind: Oid<'a>,
45 kind_element: Element<'a>,
46 values: OwnedVec<Element<'a>>,
47 element: Element<'a>,
48 parser: &'a Parser,
49 depth: u32,
50 encoding: Encoding,
51}
52
53impl<'a> Attribute<'a> {
54 fn read(parent: &Reader<'a>, element: &Element<'a>, field: &'static str) -> Result<Self> {
55 if element.tag() != Tag::constructed(universal::SEQUENCE) {
56 return Err(Error::schema(
57 ErrorCode::UnexpectedTag,
58 field,
59 element.span().start,
60 ));
61 }
62 let mut inside = parent
63 .enter(element)
64 .map_err(|error| Error::encoding(error, field))?;
65 let kind_element = inside
66 .expect(Tag::primitive(universal::OID))
67 .map_err(|error| Error::encoding(error, field))?;
68 let kind = inside
69 .oid(&kind_element)
70 .map_err(|error| Error::encoding(error, field))?;
71 let set = inside
72 .expect(Tag::constructed(universal::SET))
73 .map_err(|error| Error::encoding(error, field))?;
74 let mut members = inside
75 .enter(&set)
76 .map_err(|error| Error::encoding(error, field))?;
77 let execution = parent.execution();
78 let mut values = execution.vector();
79 let mut previous = None;
80 while let Some(value) = members
87 .next_element()
88 .map_err(|error| Error::encoding(error, field))?
89 {
90 if members.encoding().is_der() {
91 structured_pkix::der::conforms(&members, &value, field).map_err(Error::pkix)?;
92 if let Some(earlier) = previous
93 && !structured_pkix::der::set_ordered(&members, earlier, &value, field)
94 .map_err(Error::pkix)?
95 {
96 return Err(Error::schema(
97 ErrorCode::AttributeOrder,
98 field,
99 value.span().start,
100 ));
101 }
102 previous = Some(value.as_bytes());
103 }
104 values
105 .try_push(value)
106 .map_err(|reason| Error::resource(reason, field, value.span().start))?;
107 }
108 if !inside.is_empty() {
109 return Err(Error::schema(
110 ErrorCode::TrailingData,
111 field,
112 inside.offset(),
113 ));
114 }
115 Ok(Self {
116 kind,
117 kind_element,
118 values: values.into_owned(),
119 element: *element,
120 parser: members.parser(),
121 depth: members.depth(),
122 encoding: members.encoding(),
123 })
124 }
125
126 #[must_use]
128 pub fn kind(&self) -> Oid<'a> {
129 self.kind
130 }
131
132 #[must_use]
134 pub fn kind_encoding(&self) -> &'a [u8] {
135 self.kind_element.as_bytes()
136 }
137
138 #[must_use]
140 pub fn values(&self) -> &[Element<'a>] {
141 &self.values
142 }
143
144 #[must_use]
146 pub fn span(&self) -> Span {
147 self.element.span()
148 }
149
150 #[must_use]
152 pub fn as_bytes(&self) -> &'a [u8] {
153 self.element.as_bytes()
154 }
155
156 pub(crate) fn element(&self) -> &Element<'a> {
157 &self.element
158 }
159
160 pub fn value_reader(
166 &self,
167 index: usize,
168 execution: &Memory,
169 field: &'static str,
170 ) -> Result<Option<Reader<'a>>> {
171 let Some(value) = self.selected_value(index, execution, field)? else {
172 return Ok(None);
173 };
174 debug_assert!(self.depth > 0);
175 self.parser
176 .read_nested_in(
177 value.as_bytes(),
178 value.span().start,
179 self.encoding,
180 self.depth - 1,
181 execution,
182 )
183 .map(Some)
184 .map_err(|error| Error::encoding(error, field))
185 }
186
187 pub fn value_reader_in<'query>(
191 &self,
192 index: usize,
193 parent: &Reader<'query>,
194 field: &'static str,
195 ) -> Result<Option<Reader<'query>>>
196 where
197 'a: 'query,
198 {
199 if !core::ptr::eq(self.parser, parent.parser()) {
200 return Err(Error::pkix(structured_pkix::Error::new(
201 structured_pkix::ErrorCode::ForeignReader,
202 field,
203 self.element.span().start,
204 )));
205 }
206 let Some(value) = self.selected_value(index, &parent.execution(), field)? else {
207 return Ok(None);
208 };
209 debug_assert!(self.depth > 0);
210 self.parser
211 .read_nested_query_in(
212 parent,
213 value.as_bytes(),
214 value.span().start,
215 self.encoding,
216 self.depth - 1,
217 )
218 .map(Some)
219 .map_err(|error| Error::encoding(error, field))
220 }
221
222 fn selected_value<W: Work>(
223 &self,
224 index: usize,
225 execution: &W,
226 field: &'static str,
227 ) -> Result<Option<Element<'a>>> {
228 execution
229 .charge_work(1)
230 .map_err(|reason| Error::resource(reason, field, self.element.span().start))?;
231 Ok(self.values.get(index).copied())
232 }
233
234 pub fn single(&self, field: &'static str) -> Result<&Element<'a>> {
236 match &*self.values {
237 [value] => Ok(value),
238 _ => Err(Error::schema(
239 ErrorCode::AttributeCardinality,
240 field,
241 self.element.span().start,
242 )),
243 }
244 }
245}
246
247#[derive(Debug)]
249pub struct Attributes<'a> {
250 items: OwnedVec<Attribute<'a>>,
251 element: Element<'a>,
252 placement: Placement,
253 parser: &'a Parser,
254}
255
256#[derive(Debug)]
262#[must_use]
263pub struct SingletonReading<'s, 'a> {
264 attribute: Option<&'s Attribute<'a>>,
265 repeats: usize,
266}
267
268impl<'s, 'a> SingletonReading<'s, 'a> {
269 #[must_use]
271 pub fn attribute(&self) -> Option<&'s Attribute<'a>> {
272 self.attribute
273 }
274
275 #[must_use]
280 pub fn repeats(&self) -> usize {
281 self.repeats
282 }
283}
284
285impl<'a> Attributes<'a> {
286 pub fn read(parent: &Reader<'a>, element: &Element<'a>, placement: Placement) -> Result<Self> {
294 let reading = Self::read_inspection(parent, element, placement)?;
295 if let Some(fault) = reading.fault() {
296 return Err(fault);
297 }
298 Ok(reading)
299 }
300
301 pub fn read_inspection(
308 parent: &Reader<'a>,
309 element: &Element<'a>,
310 placement: Placement,
311 ) -> Result<Self> {
312 if element.tag() != placement.tag() {
313 return Err(Error::schema(
314 ErrorCode::UnexpectedTag,
315 placement.field(),
316 element.span().start,
317 ));
318 }
319 if placement == Placement::Signed {
320 let mut strict = parent
321 .reread(element, Encoding::Der)
322 .map_err(|error| Error::encoding(error, placement.field()))?;
323 let original = strict
324 .expect(placement.tag())
325 .map_err(|error| Error::encoding(error, placement.field()))?;
326 Self::read_set(&strict, &original, placement)
327 } else {
328 Self::read_set(parent, element, placement)
329 }
330 }
331
332 fn read_set(parent: &Reader<'a>, element: &Element<'a>, placement: Placement) -> Result<Self> {
333 let field = placement.field();
334 let mut inside = parent
335 .enter(element)
336 .map_err(|error| Error::encoding(error, field))?;
337 let execution = parent.execution();
338 let mut items = execution.vector();
339 let mut previous = None;
340 while let Some(member) = inside
341 .next_element()
342 .map_err(|error| Error::encoding(error, field))?
343 {
344 if inside.encoding().is_der() {
345 if let Some(earlier) = previous
346 && !structured_pkix::der::set_ordered(&inside, earlier, &member, field)
347 .map_err(Error::pkix)?
348 {
349 return Err(Error::schema(
350 ErrorCode::AttributeOrder,
351 field,
352 member.span().start,
353 ));
354 }
355 previous = Some(member.as_bytes());
356 }
357 let attribute = Attribute::read(&inside, &member, field)?;
358 items
359 .try_push(attribute)
360 .map_err(|reason| Error::resource(reason, field, member.span().start))?;
361 }
362 Ok(Self {
363 items: items.into_owned(),
364 element: *element,
365 placement,
366 parser: parent.parser(),
367 })
368 }
369
370 #[must_use]
375 pub fn fault(&self) -> Option<Error> {
376 if self.items.is_empty() {
377 return Some(Error::schema(
378 ErrorCode::EmptyAttributes,
379 self.placement.field(),
380 self.element.span().start,
381 ));
382 }
383 None
384 }
385
386 #[must_use]
388 pub fn items(&self) -> &[Attribute<'a>] {
389 &self.items
390 }
391
392 #[must_use]
394 pub fn element(&self) -> &Element<'a> {
395 &self.element
396 }
397
398 pub fn all<'s>(&'s self, kind: Oid<'s>, execution: &Memory) -> Matching<'s, 'a> {
403 Matching {
404 attributes: self,
405 kind,
406 execution: execution.clone(),
407 next: 0,
408 stopped: false,
409 }
410 }
411
412 pub fn all_in<'s>(
414 &'s self,
415 kind: Oid<'s>,
416 parent: &'s Reader<'_>,
417 ) -> Matching<'s, 'a, Execution<'s>> {
418 Matching {
419 attributes: self,
420 kind,
421 execution: parent.execution(),
422 next: 0,
423 stopped: false,
424 }
425 }
426
427 pub fn unique_in<'s>(
432 &'s self,
433 kind: Oid<'s>,
434 parent: &'s Reader<'_>,
435 ) -> Result<Option<&'s Attribute<'a>>> {
436 let mut found = None;
437 for result in self.all_in(kind, parent) {
438 let attribute = result?;
439 if found.is_some() {
440 return Err(Error::schema(
441 ErrorCode::DuplicateAttribute,
442 self.placement.field(),
443 attribute.span().start,
444 ));
445 }
446 found = Some(attribute);
447 }
448 Ok(found)
449 }
450
451 pub fn singleton_inspection_in<'s>(
463 &'s self,
464 kind: Oid<'_>,
465 parent: &Reader<'_>,
466 ) -> Result<SingletonReading<'s, 'a>> {
467 self.require_session(parent)?;
468 let mut first: Option<&Attribute<'a>> = None;
469 let mut repeats = 0;
470 let mut next = 0;
471 let mut stopped = false;
472 let execution = parent.execution();
473 while let Some(result) = self.next_matching(kind, &execution, &mut next, &mut stopped) {
474 let attribute = result?;
475 if let Some(original) = first {
476 if !same_encoding(
477 parent,
478 original.as_bytes(),
479 attribute.as_bytes(),
480 self.placement.field(),
481 attribute.span().start,
482 )? {
483 return Err(Error::schema(
484 ErrorCode::DuplicateAttribute,
485 self.placement.field(),
486 attribute.span().start,
487 ));
488 }
489 debug_assert!(repeats < self.items.len());
490 repeats += 1;
491 } else {
492 first = Some(attribute);
493 }
494 }
495 Ok(SingletonReading {
496 attribute: first,
497 repeats,
498 })
499 }
500
501 fn require_session(&self, parent: &Reader<'_>) -> Result<()> {
502 if !core::ptr::eq(self.parser, parent.parser()) {
503 return Err(Error::pkix(structured_pkix::Error::new(
504 structured_pkix::ErrorCode::ForeignReader,
505 self.placement.field(),
506 self.element.span().start,
507 )));
508 }
509 Ok(())
510 }
511
512 pub(crate) fn placement_faults_in(
513 &self,
514 parent: &Reader<'_>,
515 mut report: impl FnMut(Error) -> Result<()>,
516 ) -> Result<()> {
517 self.require_session(parent)?;
518 if self.items.is_empty() {
519 return Ok(());
520 }
521 if self.placement == Placement::Unsigned {
526 for kind in SIGNED_SINGLETONS {
527 for result in self.all_in(kind, parent) {
528 let attribute = result?;
529 report(Error::schema(
530 ErrorCode::AttributePlacement,
531 self.placement.field(),
532 attribute.span().start,
533 ))?;
534 }
535 }
536 } else {
537 for result in self.all_in(crate::oid::COUNTERSIGNATURE, parent) {
540 let attribute = result?;
541 report(Error::schema(
542 ErrorCode::AttributePlacement,
543 "signerInfo.signedAttrs.counterSignature",
544 attribute.span().start,
545 ))?;
546 }
547 }
548 Ok(())
549 }
550
551 pub(crate) fn inspect_registered<W: Work>(
552 &self,
553 parent: &Reader<'_>,
554 faults: &mut OwnedVec<Error, W>,
555 ) -> Result<()> {
556 self.placement_faults_in(parent, |fault| retain(faults, fault))?;
557 if self.placement != Placement::Signed || self.items.is_empty() {
558 return Ok(());
559 }
560 for kind in SIGNED_SINGLETONS {
565 let mut seen = false;
566 for result in self.all_in(kind, parent) {
567 let attribute = result?;
568 if !seen {
569 seen = true;
570 continue;
571 }
572 retain(
573 faults,
574 Error::schema(
575 ErrorCode::DuplicateAttribute,
576 self.placement.field(),
577 attribute.span().start,
578 ),
579 )?;
580 }
581 }
582 Ok(())
583 }
584
585 #[must_use]
590 pub fn signed_bytes(&self) -> Option<[&'a [u8]; 2]> {
591 if self.placement != Placement::Signed {
592 return None;
593 }
594 Some([&[0x31], &self.element.as_bytes()[1..]])
595 }
596}
597
598fn retain<W: Work>(faults: &mut OwnedVec<Error, W>, fault: Error) -> Result<()> {
599 let field = fault.field();
600 let at = fault.offset();
601 faults
602 .try_push(fault)
603 .map_err(|reason| Error::resource(reason, field, at))
604}
605
606pub(crate) fn same_encoding(
607 parent: &Reader<'_>,
608 left: &[u8],
609 right: &[u8],
610 field: &'static str,
611 at: u64,
612) -> Result<bool> {
613 let execution = parent.execution();
614 execution
615 .charge_work(1)
616 .map_err(|reason| Error::resource(reason, field, at))?;
617 if left.len() != right.len() {
618 return Ok(false);
619 }
620 execution
621 .charge_work(left.len() as u64)
622 .map_err(|reason| Error::resource(reason, field, at))?;
623 Ok(left == right)
624}
625
626pub struct Matching<'s, 'a, W: Work = Memory> {
628 attributes: &'s Attributes<'a>,
629 kind: Oid<'s>,
630 execution: W,
631 next: usize,
632 stopped: bool,
633}
634
635impl<'s, 'a, W: Work> Iterator for Matching<'s, 'a, W> {
636 type Item = Result<&'s Attribute<'a>>;
637
638 fn next(&mut self) -> Option<Self::Item> {
639 self.attributes.next_matching(
640 self.kind,
641 &self.execution,
642 &mut self.next,
643 &mut self.stopped,
644 )
645 }
646}
647
648impl<'a> Attributes<'a> {
649 pub(crate) fn next_matching<'s>(
650 &'s self,
651 kind: Oid<'_>,
652 execution: &impl Work,
653 next: &mut usize,
654 stopped: &mut bool,
655 ) -> Option<Result<&'s Attribute<'a>>> {
656 if *stopped {
657 return None;
658 }
659 let field = self.placement.field();
660 loop {
661 if let Err(reason) = execution.charge_work(1) {
662 *stopped = true;
663 let at = self
664 .items
665 .get(*next)
666 .map_or(self.element.span().start, |attribute| {
667 attribute.span().start
668 });
669 return Some(Err(Error::resource(reason, field, at)));
670 }
671 let Some(attribute) = self.items.get(*next) else {
672 *stopped = true;
673 return None;
674 };
675 *next += 1;
676 if attribute.kind.as_bytes().len() != kind.as_bytes().len() {
677 continue;
678 }
679 if let Err(reason) = execution.charge_work(attribute.kind.as_bytes().len() as u64) {
680 *stopped = true;
681 return Some(Err(Error::resource(reason, field, attribute.span().start)));
682 }
683 if attribute.kind == kind {
684 return Some(Ok(attribute));
685 }
686 }
687 }
688}
689
690impl<W: Work> core::iter::FusedIterator for Matching<'_, '_, W> {}
691
692#[cfg(test)]
693mod tests;