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 values: OwnedVec<Element<'a>>,
46 element: Element<'a>,
47 parser: &'a Parser,
48 depth: u32,
49 encoding: Encoding,
50}
51
52impl<'a> Attribute<'a> {
53 fn read(parent: &Reader<'a>, element: &Element<'a>, field: &'static str) -> Result<Self> {
54 if element.tag() != Tag::constructed(universal::SEQUENCE) {
55 return Err(Error::schema(
56 ErrorCode::UnexpectedTag,
57 field,
58 element.span().start,
59 ));
60 }
61 let mut inside = parent
62 .enter(element)
63 .map_err(|error| Error::encoding(error, field))?;
64 let kind = inside
65 .read_oid()
66 .map_err(|error| Error::encoding(error, field))?;
67 let set = inside
68 .expect(Tag::constructed(universal::SET))
69 .map_err(|error| Error::encoding(error, field))?;
70 let mut members = inside
71 .enter(&set)
72 .map_err(|error| Error::encoding(error, field))?;
73 let execution = parent.execution();
74 let mut values = execution.vector();
75 let mut previous = None;
76 while let Some(value) = members
83 .next_element()
84 .map_err(|error| Error::encoding(error, field))?
85 {
86 if members.encoding().is_der() {
87 structured_pkix::der::conforms(&members, &value, field).map_err(Error::pkix)?;
88 if let Some(earlier) = previous
89 && !structured_pkix::der::set_ordered(&members, earlier, &value, field)
90 .map_err(Error::pkix)?
91 {
92 return Err(Error::schema(
93 ErrorCode::AttributeOrder,
94 field,
95 value.span().start,
96 ));
97 }
98 previous = Some(value.as_bytes());
99 }
100 values
101 .try_push(value)
102 .map_err(|reason| Error::resource(reason, field, value.span().start))?;
103 }
104 if !inside.is_empty() {
105 return Err(Error::schema(
106 ErrorCode::TrailingData,
107 field,
108 inside.offset(),
109 ));
110 }
111 Ok(Self {
112 kind,
113 values: values.into_owned(),
114 element: *element,
115 parser: members.parser(),
116 depth: members.depth(),
117 encoding: members.encoding(),
118 })
119 }
120
121 #[must_use]
123 pub fn kind(&self) -> Oid<'a> {
124 self.kind
125 }
126
127 #[must_use]
129 pub fn values(&self) -> &[Element<'a>] {
130 &self.values
131 }
132
133 #[must_use]
135 pub fn span(&self) -> Span {
136 self.element.span()
137 }
138
139 #[must_use]
141 pub fn as_bytes(&self) -> &'a [u8] {
142 self.element.as_bytes()
143 }
144
145 pub fn value_reader(
151 &self,
152 index: usize,
153 execution: &Memory,
154 field: &'static str,
155 ) -> Result<Option<Reader<'a>>> {
156 let Some(value) = self.selected_value(index, execution, field)? else {
157 return Ok(None);
158 };
159 debug_assert!(self.depth > 0);
160 self.parser
161 .read_nested_in(
162 value.as_bytes(),
163 value.span().start,
164 self.encoding,
165 self.depth - 1,
166 execution,
167 )
168 .map(Some)
169 .map_err(|error| Error::encoding(error, field))
170 }
171
172 pub fn value_reader_in<'query>(
176 &self,
177 index: usize,
178 parent: &Reader<'query>,
179 field: &'static str,
180 ) -> Result<Option<Reader<'query>>>
181 where
182 'a: 'query,
183 {
184 if !core::ptr::eq(self.parser, parent.parser()) {
185 return Err(Error::pkix(structured_pkix::Error::new(
186 structured_pkix::ErrorCode::ForeignReader,
187 field,
188 self.element.span().start,
189 )));
190 }
191 let Some(value) = self.selected_value(index, &parent.execution(), field)? else {
192 return Ok(None);
193 };
194 debug_assert!(self.depth > 0);
195 self.parser
196 .read_nested_query_in(
197 parent,
198 value.as_bytes(),
199 value.span().start,
200 self.encoding,
201 self.depth - 1,
202 )
203 .map(Some)
204 .map_err(|error| Error::encoding(error, field))
205 }
206
207 fn selected_value<W: Work>(
208 &self,
209 index: usize,
210 execution: &W,
211 field: &'static str,
212 ) -> Result<Option<Element<'a>>> {
213 execution
214 .charge_work(1)
215 .map_err(|reason| Error::resource(reason, field, self.element.span().start))?;
216 Ok(self.values.get(index).copied())
217 }
218
219 pub fn single(&self, field: &'static str) -> Result<&Element<'a>> {
221 match &*self.values {
222 [value] => Ok(value),
223 _ => Err(Error::schema(
224 ErrorCode::AttributeCardinality,
225 field,
226 self.element.span().start,
227 )),
228 }
229 }
230}
231
232#[derive(Debug)]
234pub struct Attributes<'a> {
235 items: OwnedVec<Attribute<'a>>,
236 element: Element<'a>,
237 placement: Placement,
238 parser: &'a Parser,
239}
240
241#[derive(Debug)]
247#[must_use]
248pub struct SingletonReading<'s, 'a> {
249 attribute: Option<&'s Attribute<'a>>,
250 repeats: usize,
251}
252
253impl<'s, 'a> SingletonReading<'s, 'a> {
254 #[must_use]
256 pub fn attribute(&self) -> Option<&'s Attribute<'a>> {
257 self.attribute
258 }
259
260 #[must_use]
265 pub fn repeats(&self) -> usize {
266 self.repeats
267 }
268}
269
270impl<'a> Attributes<'a> {
271 pub fn read(parent: &Reader<'a>, element: &Element<'a>, placement: Placement) -> Result<Self> {
279 let reading = Self::read_inspection(parent, element, placement)?;
280 if let Some(fault) = reading.fault() {
281 return Err(fault);
282 }
283 Ok(reading)
284 }
285
286 pub fn read_inspection(
293 parent: &Reader<'a>,
294 element: &Element<'a>,
295 placement: Placement,
296 ) -> Result<Self> {
297 if element.tag() != placement.tag() {
298 return Err(Error::schema(
299 ErrorCode::UnexpectedTag,
300 placement.field(),
301 element.span().start,
302 ));
303 }
304 if placement == Placement::Signed {
305 let mut strict = parent
306 .reread(element, Encoding::Der)
307 .map_err(|error| Error::encoding(error, placement.field()))?;
308 let original = strict
309 .expect(placement.tag())
310 .map_err(|error| Error::encoding(error, placement.field()))?;
311 Self::read_set(&strict, &original, placement)
312 } else {
313 Self::read_set(parent, element, placement)
314 }
315 }
316
317 fn read_set(parent: &Reader<'a>, element: &Element<'a>, placement: Placement) -> Result<Self> {
318 let field = placement.field();
319 let mut inside = parent
320 .enter(element)
321 .map_err(|error| Error::encoding(error, field))?;
322 let execution = parent.execution();
323 let mut items = execution.vector();
324 let mut previous = None;
325 while let Some(member) = inside
326 .next_element()
327 .map_err(|error| Error::encoding(error, field))?
328 {
329 if inside.encoding().is_der() {
330 if let Some(earlier) = previous
331 && !structured_pkix::der::set_ordered(&inside, earlier, &member, field)
332 .map_err(Error::pkix)?
333 {
334 return Err(Error::schema(
335 ErrorCode::AttributeOrder,
336 field,
337 member.span().start,
338 ));
339 }
340 previous = Some(member.as_bytes());
341 }
342 let attribute = Attribute::read(&inside, &member, field)?;
343 items
344 .try_push(attribute)
345 .map_err(|reason| Error::resource(reason, field, member.span().start))?;
346 }
347 Ok(Self {
348 items: items.into_owned(),
349 element: *element,
350 placement,
351 parser: parent.parser(),
352 })
353 }
354
355 #[must_use]
360 pub fn fault(&self) -> Option<Error> {
361 if self.items.is_empty() {
362 return Some(Error::schema(
363 ErrorCode::EmptyAttributes,
364 self.placement.field(),
365 self.element.span().start,
366 ));
367 }
368 None
369 }
370
371 #[must_use]
373 pub fn items(&self) -> &[Attribute<'a>] {
374 &self.items
375 }
376
377 #[must_use]
379 pub fn element(&self) -> &Element<'a> {
380 &self.element
381 }
382
383 pub fn all<'s>(&'s self, kind: Oid<'s>, execution: &Memory) -> Matching<'s, 'a> {
388 Matching {
389 attributes: self,
390 kind,
391 execution: execution.clone(),
392 next: 0,
393 stopped: false,
394 }
395 }
396
397 pub fn all_in<'s>(
399 &'s self,
400 kind: Oid<'s>,
401 parent: &'s Reader<'_>,
402 ) -> Matching<'s, 'a, Execution<'s>> {
403 Matching {
404 attributes: self,
405 kind,
406 execution: parent.execution(),
407 next: 0,
408 stopped: false,
409 }
410 }
411
412 pub fn unique_in<'s>(
417 &'s self,
418 kind: Oid<'s>,
419 parent: &'s Reader<'_>,
420 ) -> Result<Option<&'s Attribute<'a>>> {
421 let mut found = None;
422 for result in self.all_in(kind, parent) {
423 let attribute = result?;
424 if found.is_some() {
425 return Err(Error::schema(
426 ErrorCode::DuplicateAttribute,
427 self.placement.field(),
428 attribute.span().start,
429 ));
430 }
431 found = Some(attribute);
432 }
433 Ok(found)
434 }
435
436 pub fn singleton_inspection_in<'s>(
448 &'s self,
449 kind: Oid<'_>,
450 parent: &Reader<'_>,
451 ) -> Result<SingletonReading<'s, 'a>> {
452 self.require_session(parent)?;
453 let mut first: Option<&Attribute<'a>> = None;
454 let mut repeats = 0;
455 let mut next = 0;
456 let mut stopped = false;
457 let execution = parent.execution();
458 while let Some(result) = self.next_matching(kind, &execution, &mut next, &mut stopped) {
459 let attribute = result?;
460 if let Some(original) = first {
461 if !same_encoding(
462 parent,
463 original.as_bytes(),
464 attribute.as_bytes(),
465 self.placement.field(),
466 attribute.span().start,
467 )? {
468 return Err(Error::schema(
469 ErrorCode::DuplicateAttribute,
470 self.placement.field(),
471 attribute.span().start,
472 ));
473 }
474 debug_assert!(repeats < self.items.len());
475 repeats += 1;
476 } else {
477 first = Some(attribute);
478 }
479 }
480 Ok(SingletonReading {
481 attribute: first,
482 repeats,
483 })
484 }
485
486 fn require_session(&self, parent: &Reader<'_>) -> Result<()> {
487 if !core::ptr::eq(self.parser, parent.parser()) {
488 return Err(Error::pkix(structured_pkix::Error::new(
489 structured_pkix::ErrorCode::ForeignReader,
490 self.placement.field(),
491 self.element.span().start,
492 )));
493 }
494 Ok(())
495 }
496
497 pub(crate) fn placement_faults_in(
498 &self,
499 parent: &Reader<'_>,
500 mut report: impl FnMut(Error) -> Result<()>,
501 ) -> Result<()> {
502 self.require_session(parent)?;
503 if self.items.is_empty() {
504 return Ok(());
505 }
506 if self.placement == Placement::Unsigned {
511 for kind in SIGNED_SINGLETONS {
512 for result in self.all_in(kind, parent) {
513 let attribute = result?;
514 report(Error::schema(
515 ErrorCode::AttributePlacement,
516 self.placement.field(),
517 attribute.span().start,
518 ))?;
519 }
520 }
521 } else {
522 for result in self.all_in(crate::oid::COUNTERSIGNATURE, parent) {
525 let attribute = result?;
526 report(Error::schema(
527 ErrorCode::AttributePlacement,
528 "signerInfo.signedAttrs.counterSignature",
529 attribute.span().start,
530 ))?;
531 }
532 }
533 Ok(())
534 }
535
536 pub(crate) fn inspect_registered<W: Work>(
537 &self,
538 parent: &Reader<'_>,
539 faults: &mut OwnedVec<Error, W>,
540 ) -> Result<()> {
541 self.placement_faults_in(parent, |fault| retain(faults, fault))?;
542 if self.placement != Placement::Signed || self.items.is_empty() {
543 return Ok(());
544 }
545 for kind in SIGNED_SINGLETONS {
550 let mut seen = false;
551 for result in self.all_in(kind, parent) {
552 let attribute = result?;
553 if !seen {
554 seen = true;
555 continue;
556 }
557 retain(
558 faults,
559 Error::schema(
560 ErrorCode::DuplicateAttribute,
561 self.placement.field(),
562 attribute.span().start,
563 ),
564 )?;
565 }
566 }
567 Ok(())
568 }
569
570 #[must_use]
575 pub fn signed_bytes(&self) -> Option<[&'a [u8]; 2]> {
576 if self.placement != Placement::Signed {
577 return None;
578 }
579 Some([&[0x31], &self.element.as_bytes()[1..]])
580 }
581}
582
583fn retain<W: Work>(faults: &mut OwnedVec<Error, W>, fault: Error) -> Result<()> {
584 let field = fault.field();
585 let at = fault.offset();
586 faults
587 .try_push(fault)
588 .map_err(|reason| Error::resource(reason, field, at))
589}
590
591pub(crate) fn same_encoding(
592 parent: &Reader<'_>,
593 left: &[u8],
594 right: &[u8],
595 field: &'static str,
596 at: u64,
597) -> Result<bool> {
598 let execution = parent.execution();
599 execution
600 .charge_work(1)
601 .map_err(|reason| Error::resource(reason, field, at))?;
602 if left.len() != right.len() {
603 return Ok(false);
604 }
605 execution
606 .charge_work(left.len() as u64)
607 .map_err(|reason| Error::resource(reason, field, at))?;
608 Ok(left == right)
609}
610
611pub struct Matching<'s, 'a, W: Work = Memory> {
613 attributes: &'s Attributes<'a>,
614 kind: Oid<'s>,
615 execution: W,
616 next: usize,
617 stopped: bool,
618}
619
620impl<'s, 'a, W: Work> Iterator for Matching<'s, 'a, W> {
621 type Item = Result<&'s Attribute<'a>>;
622
623 fn next(&mut self) -> Option<Self::Item> {
624 self.attributes.next_matching(
625 self.kind,
626 &self.execution,
627 &mut self.next,
628 &mut self.stopped,
629 )
630 }
631}
632
633impl<'a> Attributes<'a> {
634 pub(crate) fn next_matching<'s>(
635 &'s self,
636 kind: Oid<'_>,
637 execution: &impl Work,
638 next: &mut usize,
639 stopped: &mut bool,
640 ) -> Option<Result<&'s Attribute<'a>>> {
641 if *stopped {
642 return None;
643 }
644 let field = self.placement.field();
645 loop {
646 if let Err(reason) = execution.charge_work(1) {
647 *stopped = true;
648 let at = self
649 .items
650 .get(*next)
651 .map_or(self.element.span().start, |attribute| {
652 attribute.span().start
653 });
654 return Some(Err(Error::resource(reason, field, at)));
655 }
656 let Some(attribute) = self.items.get(*next) else {
657 *stopped = true;
658 return None;
659 };
660 *next += 1;
661 if attribute.kind.as_bytes().len() != kind.as_bytes().len() {
662 continue;
663 }
664 if let Err(reason) = execution.charge_work(attribute.kind.as_bytes().len() as u64) {
665 *stopped = true;
666 return Some(Err(Error::resource(reason, field, attribute.span().start)));
667 }
668 if attribute.kind == kind {
669 return Some(Ok(attribute));
670 }
671 }
672 }
673}
674
675impl<W: Work> core::iter::FusedIterator for Matching<'_, '_, W> {}
676
677#[cfg(test)]
678mod tests {
679 use super::*;
680 use alloc::{sync::Arc, vec};
681
682 #[test]
683 fn placement_kernel_preserves_collecting_strict_and_callback_refusal() {
684 let mut attribute = vec![0x30, 15, 6, 9];
687 attribute.extend(crate::oid::COUNTERSIGNATURE.as_bytes());
688 attribute.extend([0x31, 2, 5, 0]);
689 let mut bytes = vec![0xa0, 34];
690 bytes.extend(attribute.repeat(2));
691 let memory = Memory::new(Arc::new(structured_asn1::memory::MemoryAccount::new(
692 65536, 65536,
693 )));
694 let parser = Parser::ber(memory);
695 let mut parent = parser.read(&bytes, 700).unwrap();
696 let element = parent.next_element().unwrap().unwrap();
697 let attributes = Attributes::read(&parent, &element, Placement::Signed).unwrap();
698 let first = attributes.items()[0].span().start;
699 let mut count = 0;
700 attributes
701 .placement_faults_in(&parent, |fault| {
702 assert_eq!(fault.code(), ErrorCode::AttributePlacement);
703 assert_eq!(fault.offset(), attributes.items()[count].span().start);
704 count += 1;
705 Ok(())
706 })
707 .unwrap();
708 assert_eq!(count, 2);
709 let mut calls = 0;
710 let error = attributes
711 .placement_faults_in(&parent, |fault| {
712 calls += 1;
713 Err(fault)
714 })
715 .unwrap_err();
716 assert_eq!(calls, 1);
717 assert_eq!(error.code(), ErrorCode::AttributePlacement);
718 assert_eq!(error.offset(), first);
719 let error = attributes
720 .placement_faults_in(&parent, |_| {
721 Err(Error::resource(
722 structured_asn1::memory::MemoryError::WorkExceeded,
723 "report",
724 first,
725 ))
726 })
727 .unwrap_err();
728 assert!(error.is_resource());
729 assert_eq!(error.field(), "report");
730 assert_eq!(error.offset(), first);
731 }
732}