1use crate::{Error, ErrorCode, Result};
4use structured_asn1::memory::{Execution, Memory, OwnedVec, Work};
5use structured_asn1::{Element, Encoding, Oid, Parser, Reader, ScopedReader, 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 pub(crate) fn query_in<'operation, W: Work>(&self, work: &'operation W) -> Execution<'operation>
55 where
56 'a: 'operation,
57 {
58 work.execution_for(self.parser)
59 }
60
61 pub fn read(parent: &Reader<'a>, element: &Element<'a>, field: &'static str) -> Result<Self> {
65 if element.tag() != Tag::constructed(universal::SEQUENCE) {
66 return Err(Error::schema(
67 ErrorCode::UnexpectedTag,
68 field,
69 element.span().start,
70 ));
71 }
72 let mut inside = parent
73 .enter(element)
74 .map_err(|error| Error::encoding(error, field))?;
75 let kind_element = inside
76 .expect(Tag::primitive(universal::OID))
77 .map_err(|error| Error::encoding(error, field))?;
78 let kind = inside
79 .oid(&kind_element)
80 .map_err(|error| Error::encoding(error, field))?;
81 let set = inside
82 .expect(Tag::constructed(universal::SET))
83 .map_err(|error| Error::encoding(error, field))?;
84 let mut members = inside
85 .enter(&set)
86 .map_err(|error| Error::encoding(error, field))?;
87 let execution = parent.execution();
88 let mut values = execution.vector();
89 let mut previous = None;
90 while let Some(value) = members
97 .next_element()
98 .map_err(|error| Error::encoding(error, field))?
99 {
100 if members.encoding().is_der() {
101 structured_pkix::der::conforms(&members, &value, field).map_err(Error::pkix)?;
102 if let Some(earlier) = previous
103 && !structured_pkix::der::set_ordered(&members, earlier, &value, field)
104 .map_err(Error::pkix)?
105 {
106 return Err(Error::schema(
107 ErrorCode::AttributeOrder,
108 field,
109 value.span().start,
110 ));
111 }
112 previous = Some(value.as_bytes());
113 }
114 values
115 .try_push(value)
116 .map_err(|reason| Error::resource(reason, field, value.span().start))?;
117 }
118 if !inside.is_empty() {
119 return Err(Error::schema(
120 ErrorCode::TrailingData,
121 field,
122 inside.offset(),
123 ));
124 }
125 Ok(Self {
126 kind,
127 kind_element,
128 values: values.into_owned(),
129 element: *element,
130 parser: members.parser(),
131 depth: members.depth(),
132 encoding: members.encoding(),
133 })
134 }
135
136 #[must_use]
138 pub fn kind(&self) -> Oid<'a> {
139 self.kind
140 }
141
142 #[must_use]
144 pub fn kind_encoding(&self) -> &'a [u8] {
145 self.kind_element.as_bytes()
146 }
147
148 #[must_use]
150 pub fn values(&self) -> &[Element<'a>] {
151 &self.values
152 }
153
154 #[must_use]
156 pub fn span(&self) -> Span {
157 self.element.span()
158 }
159
160 #[must_use]
162 pub fn as_bytes(&self) -> &'a [u8] {
163 self.element.as_bytes()
164 }
165
166 #[must_use]
170 pub fn element(&self) -> &Element<'a> {
171 &self.element
172 }
173
174 pub fn value_reader(
180 &self,
181 index: usize,
182 execution: &Memory,
183 field: &'static str,
184 ) -> Result<Option<Reader<'a>>> {
185 let Some(value) = self.selected_value(index, execution, field)? else {
186 return Ok(None);
187 };
188 debug_assert!(self.depth > 0);
189 self.parser
190 .read_nested_in(
191 value.as_bytes(),
192 value.span().start,
193 self.encoding,
194 self.depth - 1,
195 execution,
196 )
197 .map(Some)
198 .map_err(|error| Error::encoding(error, field))
199 }
200
201 pub fn value_reader_scoped<'operation, W: Work>(
207 &self,
208 index: usize,
209 work: &'operation W,
210 field: &'static str,
211 ) -> Result<Option<ScopedReader<'a, 'operation>>>
212 where
213 'a: 'operation,
214 {
215 let execution = work.execution_for(self.parser);
216 let Some(value) = self.selected_value(index, &execution, field)? else {
217 return Ok(None);
218 };
219 debug_assert!(self.depth > 0);
220 work.read_scoped_nested(
221 self.parser,
222 value.as_bytes(),
223 value.span().start,
224 self.encoding,
225 self.depth - 1,
226 )
227 .map(Some)
228 .map_err(|error| Error::encoding(error, field))
229 }
230
231 pub fn value_reader_in<'query>(
235 &self,
236 index: usize,
237 parent: &Reader<'query>,
238 field: &'static str,
239 ) -> Result<Option<Reader<'query>>>
240 where
241 'a: 'query,
242 {
243 if !core::ptr::eq(self.parser, parent.parser()) {
244 return Err(Error::pkix(structured_pkix::Error::new(
245 structured_pkix::ErrorCode::ForeignReader,
246 field,
247 self.element.span().start,
248 )));
249 }
250 let Some(value) = self.selected_value(index, &parent.execution(), field)? else {
251 return Ok(None);
252 };
253 debug_assert!(self.depth > 0);
254 self.parser
255 .read_nested_query_in(
256 parent,
257 value.as_bytes(),
258 value.span().start,
259 self.encoding,
260 self.depth - 1,
261 )
262 .map(Some)
263 .map_err(|error| Error::encoding(error, field))
264 }
265
266 fn selected_value<W: Work>(
267 &self,
268 index: usize,
269 execution: &W,
270 field: &'static str,
271 ) -> Result<Option<Element<'a>>> {
272 execution
273 .charge_work(1)
274 .map_err(|reason| Error::resource(reason, field, self.element.span().start))?;
275 Ok(self.values.get(index).copied())
276 }
277
278 pub fn single(&self, field: &'static str) -> Result<&Element<'a>> {
280 match &*self.values {
281 [value] => Ok(value),
282 _ => Err(Error::schema(
283 ErrorCode::AttributeCardinality,
284 field,
285 self.element.span().start,
286 )),
287 }
288 }
289}
290
291#[derive(Debug)]
293pub struct Attributes<'a> {
294 items: OwnedVec<Attribute<'a>>,
295 element: Element<'a>,
296 placement: Placement,
297 parser: &'a Parser,
298}
299
300#[derive(Debug)]
306#[must_use]
307pub struct SingletonReading<'s, 'a> {
308 attribute: Option<&'s Attribute<'a>>,
309 repeats: usize,
310}
311
312impl<'s, 'a> SingletonReading<'s, 'a> {
313 #[must_use]
315 pub fn attribute(&self) -> Option<&'s Attribute<'a>> {
316 self.attribute
317 }
318
319 #[must_use]
324 pub fn repeats(&self) -> usize {
325 self.repeats
326 }
327}
328
329impl<'a> Attributes<'a> {
330 pub fn read(parent: &Reader<'a>, element: &Element<'a>, placement: Placement) -> Result<Self> {
338 let reading = Self::read_inspection(parent, element, placement)?;
339 if let Some(fault) = reading.fault() {
340 return Err(fault);
341 }
342 Ok(reading)
343 }
344
345 pub fn read_inspection(
352 parent: &Reader<'a>,
353 element: &Element<'a>,
354 placement: Placement,
355 ) -> Result<Self> {
356 if element.tag() != placement.tag() {
357 return Err(Error::schema(
358 ErrorCode::UnexpectedTag,
359 placement.field(),
360 element.span().start,
361 ));
362 }
363 if placement == Placement::Signed {
364 let mut strict = parent
365 .reread(element, Encoding::Der)
366 .map_err(|error| Error::encoding(error, placement.field()))?;
367 let original = strict
368 .expect(placement.tag())
369 .map_err(|error| Error::encoding(error, placement.field()))?;
370 Self::read_set(&strict, &original, placement)
371 } else {
372 Self::read_set(parent, element, placement)
373 }
374 }
375
376 fn read_set(parent: &Reader<'a>, element: &Element<'a>, placement: Placement) -> Result<Self> {
377 let field = placement.field();
378 let mut inside = parent
379 .enter(element)
380 .map_err(|error| Error::encoding(error, field))?;
381 let execution = parent.execution();
382 let mut items = execution.vector();
383 let mut previous = None;
384 while let Some(member) = inside
385 .next_element()
386 .map_err(|error| Error::encoding(error, field))?
387 {
388 if inside.encoding().is_der() {
389 if let Some(earlier) = previous
390 && !structured_pkix::der::set_ordered(&inside, earlier, &member, field)
391 .map_err(Error::pkix)?
392 {
393 return Err(Error::schema(
394 ErrorCode::AttributeOrder,
395 field,
396 member.span().start,
397 ));
398 }
399 previous = Some(member.as_bytes());
400 }
401 let attribute = Attribute::read(&inside, &member, field)?;
402 items
403 .try_push(attribute)
404 .map_err(|reason| Error::resource(reason, field, member.span().start))?;
405 }
406 Ok(Self {
407 items: items.into_owned(),
408 element: *element,
409 placement,
410 parser: parent.parser(),
411 })
412 }
413
414 #[must_use]
419 pub fn fault(&self) -> Option<Error> {
420 if self.items.is_empty() {
421 return Some(Error::schema(
422 ErrorCode::EmptyAttributes,
423 self.placement.field(),
424 self.element.span().start,
425 ));
426 }
427 None
428 }
429
430 #[must_use]
432 pub fn items(&self) -> &[Attribute<'a>] {
433 &self.items
434 }
435
436 #[must_use]
438 pub fn element(&self) -> &Element<'a> {
439 &self.element
440 }
441
442 pub fn all<'s>(&'s self, kind: Oid<'s>, execution: &Memory) -> Matching<'s, 'a> {
447 Matching {
448 attributes: self,
449 kind,
450 execution: execution.clone(),
451 next: 0,
452 stopped: false,
453 }
454 }
455
456 pub fn all_in<'s>(
458 &'s self,
459 kind: Oid<'s>,
460 parent: &'s Reader<'_>,
461 ) -> Matching<'s, 'a, Execution<'s>> {
462 Matching {
463 attributes: self,
464 kind,
465 execution: parent.execution(),
466 next: 0,
467 stopped: false,
468 }
469 }
470
471 pub fn unique_in<'s>(
476 &'s self,
477 kind: Oid<'s>,
478 parent: &'s Reader<'_>,
479 ) -> Result<Option<&'s Attribute<'a>>> {
480 let mut found = None;
481 for result in self.all_in(kind, parent) {
482 let attribute = result?;
483 if found.is_some() {
484 return Err(Error::schema(
485 ErrorCode::DuplicateAttribute,
486 self.placement.field(),
487 attribute.span().start,
488 ));
489 }
490 found = Some(attribute);
491 }
492 Ok(found)
493 }
494
495 pub fn singleton_inspection_in<'s>(
507 &'s self,
508 kind: Oid<'_>,
509 parent: &Reader<'_>,
510 ) -> Result<SingletonReading<'s, 'a>> {
511 self.require_session(parent)?;
512 let mut first: Option<&Attribute<'a>> = None;
513 let mut repeats = 0;
514 let mut next = 0;
515 let mut stopped = false;
516 let execution = parent.execution();
517 while let Some(result) = self.next_matching(kind, &execution, &mut next, &mut stopped) {
518 let attribute = result?;
519 if let Some(original) = first {
520 if !same_encoding(
521 parent,
522 original.as_bytes(),
523 attribute.as_bytes(),
524 self.placement.field(),
525 attribute.span().start,
526 )? {
527 return Err(Error::schema(
528 ErrorCode::DuplicateAttribute,
529 self.placement.field(),
530 attribute.span().start,
531 ));
532 }
533 debug_assert!(repeats < self.items.len());
534 repeats += 1;
535 } else {
536 first = Some(attribute);
537 }
538 }
539 Ok(SingletonReading {
540 attribute: first,
541 repeats,
542 })
543 }
544
545 fn require_session(&self, parent: &Reader<'_>) -> Result<()> {
546 if !core::ptr::eq(self.parser, parent.parser()) {
547 return Err(Error::pkix(structured_pkix::Error::new(
548 structured_pkix::ErrorCode::ForeignReader,
549 self.placement.field(),
550 self.element.span().start,
551 )));
552 }
553 Ok(())
554 }
555
556 pub(crate) fn placement_faults_in(
557 &self,
558 parent: &Reader<'_>,
559 mut report: impl FnMut(Error) -> Result<()>,
560 ) -> Result<()> {
561 self.require_session(parent)?;
562 if self.items.is_empty() {
563 return Ok(());
564 }
565 if self.placement == Placement::Unsigned {
570 for kind in SIGNED_SINGLETONS {
571 for result in self.all_in(kind, parent) {
572 let attribute = result?;
573 report(Error::schema(
574 ErrorCode::AttributePlacement,
575 self.placement.field(),
576 attribute.span().start,
577 ))?;
578 }
579 }
580 } else {
581 for result in self.all_in(crate::oid::COUNTERSIGNATURE, parent) {
584 let attribute = result?;
585 report(Error::schema(
586 ErrorCode::AttributePlacement,
587 "signerInfo.signedAttrs.counterSignature",
588 attribute.span().start,
589 ))?;
590 }
591 }
592 Ok(())
593 }
594
595 pub(crate) fn inspect_registered<W: Work>(
596 &self,
597 parent: &Reader<'_>,
598 faults: &mut OwnedVec<Error, W>,
599 ) -> Result<()> {
600 self.placement_faults_in(parent, |fault| retain(faults, fault))?;
601 if self.placement != Placement::Signed || self.items.is_empty() {
602 return Ok(());
603 }
604 for kind in SIGNED_SINGLETONS {
609 let mut seen = false;
610 for result in self.all_in(kind, parent) {
611 let attribute = result?;
612 if !seen {
613 seen = true;
614 continue;
615 }
616 retain(
617 faults,
618 Error::schema(
619 ErrorCode::DuplicateAttribute,
620 self.placement.field(),
621 attribute.span().start,
622 ),
623 )?;
624 }
625 }
626 Ok(())
627 }
628
629 #[must_use]
634 pub fn signed_bytes(&self) -> Option<[&'a [u8]; 2]> {
635 if self.placement != Placement::Signed {
636 return None;
637 }
638 Some([&[0x31], &self.element.as_bytes()[1..]])
639 }
640}
641
642fn retain<W: Work>(faults: &mut OwnedVec<Error, W>, fault: Error) -> Result<()> {
643 let field = fault.field();
644 let at = fault.offset();
645 faults
646 .try_push(fault)
647 .map_err(|reason| Error::resource(reason, field, at))
648}
649
650pub(crate) fn same_encoding(
651 parent: &Reader<'_>,
652 left: &[u8],
653 right: &[u8],
654 field: &'static str,
655 at: u64,
656) -> Result<bool> {
657 let execution = parent.execution();
658 execution
659 .charge_work(1)
660 .map_err(|reason| Error::resource(reason, field, at))?;
661 if left.len() != right.len() {
662 return Ok(false);
663 }
664 execution
665 .charge_work(left.len() as u64)
666 .map_err(|reason| Error::resource(reason, field, at))?;
667 Ok(left == right)
668}
669
670pub struct Matching<'s, 'a, W: Work = Memory> {
672 attributes: &'s Attributes<'a>,
673 kind: Oid<'s>,
674 execution: W,
675 next: usize,
676 stopped: bool,
677}
678
679impl<'s, 'a, W: Work> Iterator for Matching<'s, 'a, W> {
680 type Item = Result<&'s Attribute<'a>>;
681
682 fn next(&mut self) -> Option<Self::Item> {
683 self.attributes.next_matching(
684 self.kind,
685 &self.execution,
686 &mut self.next,
687 &mut self.stopped,
688 )
689 }
690}
691
692impl<'a> Attributes<'a> {
693 pub(crate) fn next_matching<'s>(
694 &'s self,
695 kind: Oid<'_>,
696 execution: &impl Work,
697 next: &mut usize,
698 stopped: &mut bool,
699 ) -> Option<Result<&'s Attribute<'a>>> {
700 if *stopped {
701 return None;
702 }
703 let field = self.placement.field();
704 loop {
705 if let Err(reason) = execution.charge_work(1) {
706 *stopped = true;
707 let at = self
708 .items
709 .get(*next)
710 .map_or(self.element.span().start, |attribute| {
711 attribute.span().start
712 });
713 return Some(Err(Error::resource(reason, field, at)));
714 }
715 let Some(attribute) = self.items.get(*next) else {
716 *stopped = true;
717 return None;
718 };
719 *next += 1;
720 if attribute.kind.as_bytes().len() != kind.as_bytes().len() {
721 continue;
722 }
723 if let Err(reason) = execution.charge_work(attribute.kind.as_bytes().len() as u64) {
724 *stopped = true;
725 return Some(Err(Error::resource(reason, field, attribute.span().start)));
726 }
727 if attribute.kind == kind {
728 return Some(Ok(attribute));
729 }
730 }
731 }
732}
733
734impl<W: Work> core::iter::FusedIterator for Matching<'_, '_, W> {}
735
736#[cfg(test)]
737mod tests;