1use crate::attribute::same_encoding;
4use crate::provider::{DigestAlgorithm, ImpliedDigest};
5use crate::signer::{SignerInfo, required};
6use crate::{Error, ErrorCode, Octets, Result, oid};
7use structured_asn1::memory::{OwnedVec, Work};
8use structured_asn1::{Element, Integer, Reader, Span, Tag, universal};
9use structured_pkix::general_name::{self, GeneralName};
10
11mod check;
12pub use check::{Binding, BindingError, Bindings};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum Version {
17 V1,
19 V2,
21}
22
23impl Version {
24 #[must_use]
26 pub fn identifier(self) -> structured_asn1::Oid<'static> {
27 match self {
28 Self::V1 => oid::SIGNING_CERTIFICATE,
29 Self::V2 => oid::SIGNING_CERTIFICATE_V2,
30 }
31 }
32 fn field(self) -> &'static str {
33 match self {
34 Self::V1 => "signerInfo.signedAttrs.signingCertificate",
35 Self::V2 => "signerInfo.signedAttrs.signingCertificateV2",
36 }
37 }
38}
39
40#[derive(Debug)]
42pub enum IssuerReading<'a> {
43 Absent,
45 Present(IssuerSerial<'a>),
47 Unreadable(Element<'a>),
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum IssuerAgreement {
56 Unstated,
58 Matches,
60 Differs,
62 Unreadable,
64}
65
66#[derive(Debug)]
68pub struct IssuerSerial<'a> {
69 names: OwnedVec<GeneralName<'a>>,
70 serial: Integer<'a>,
71 names_element: Element<'a>,
72 element: Element<'a>,
73}
74
75impl<'a> IssuerSerial<'a> {
76 #[must_use]
78 pub fn names(&self) -> &[GeneralName<'a>] {
79 &self.names
80 }
81 #[must_use]
83 pub fn serial(&self) -> Integer<'a> {
84 self.serial
85 }
86 #[must_use]
88 pub fn names_element(&self) -> &Element<'a> {
89 &self.names_element
90 }
91 #[must_use]
93 pub fn span(&self) -> Span {
94 self.element.span()
95 }
96
97 fn matches_with<'c, 'p>(
98 &self,
99 certificate: &structured_pkix::Certificate<'c>,
100 parent: &'p Reader<'_>,
101 prepared: &mut Option<structured_pkix::Ordered<'c, structured_asn1::memory::Execution<'p>>>,
102 field: &'static str,
103 metadata_at: u64,
104 ) -> Result<IssuerAgreement> {
105 let execution = parent.execution();
106 execution
107 .charge_work(1)
108 .map_err(|reason| Error::resource(reason, field, metadata_at))?;
109 let at = self.element.span().start;
110 let serial = self.serial.as_bytes();
111 let actual = certificate.tbs().serial().as_bytes();
112 execution
113 .charge_work(1 + serial.len().max(actual.len()) as u64)
114 .map_err(|reason| Error::resource(reason, field, at))?;
115 if serial != actual {
116 return Ok(IssuerAgreement::Differs);
117 }
118 for name in &self.names {
119 execution
120 .charge_work(1)
121 .map_err(|reason| Error::resource(reason, field, at))?;
122 if let GeneralName::Directory(name) = name {
123 let actual = match &*prepared {
124 Some(actual) => actual,
125 None => prepared.insert(
126 certificate
127 .tbs()
128 .issuer()
129 .ordered_in(parent)
130 .map_err(Error::pkix)?,
131 ),
132 };
133 let asked = name.ordered_in(parent).map_err(Error::pkix)?;
134 if asked.order(actual, &execution).map_err(Error::pkix)?
135 == core::cmp::Ordering::Equal
136 {
137 return Ok(IssuerAgreement::Matches);
138 }
139 }
140 }
141 Ok(IssuerAgreement::Differs)
142 }
143}
144
145#[derive(Debug)]
153pub struct IssuerSerialReading<'a> {
154 field: &'static str,
155 value: IssuerSerial<'a>,
156 faults: OwnedVec<Error>,
157}
158
159impl<'a> IssuerSerialReading<'a> {
160 pub fn read(parent: &Reader<'a>, element: &Element<'a>, field: &'static str) -> Result<Self> {
168 let mut faults = parent.execution().vector();
169 let value = read_issuer_serial(parent, element, field, &mut faults)?;
170 Ok(Self {
171 field,
172 value,
173 faults: faults.into_owned(),
174 })
175 }
176
177 #[must_use]
179 pub fn value(&self) -> &IssuerSerial<'a> {
180 &self.value
181 }
182
183 #[must_use]
185 pub fn faults(&self) -> &[Error] {
186 &self.faults
187 }
188
189 pub fn matches_certificate(
194 &self,
195 certificate: &structured_pkix::Certificate<'_>,
196 parent: &Reader<'_>,
197 ) -> Result<IssuerAgreement> {
198 self.value.matches_with(
199 certificate,
200 parent,
201 &mut None,
202 self.field,
203 self.value.element.span().start,
204 )
205 }
206
207 #[must_use]
212 pub fn into_parts(self) -> (IssuerSerial<'a>, OwnedVec<Error>) {
213 (self.value, self.faults)
214 }
215}
216
217#[derive(Debug)]
219pub struct CertificateId<'a> {
220 digest: DigestAlgorithm<'a>,
221 hashed: Octets<'a>,
222 issuer: IssuerReading<'a>,
223 element: Element<'a>,
224 field: &'static str,
225}
226
227impl<'a> CertificateId<'a> {
228 #[must_use]
230 pub fn digest_algorithm(&self) -> DigestAlgorithm<'a> {
231 self.digest
232 }
233 #[must_use]
235 pub fn hashed(&self) -> &Octets<'a> {
236 &self.hashed
237 }
238 #[must_use]
240 pub fn issuer_serial(&self) -> &IssuerReading<'a> {
241 &self.issuer
242 }
243 #[must_use]
245 pub fn element(&self) -> &Element<'a> {
246 &self.element
247 }
248
249 pub fn matches_issuer(
257 &self,
258 certificate: &structured_pkix::Certificate<'_>,
259 parent: &Reader<'_>,
260 ) -> Result<IssuerAgreement> {
261 self.matches_issuer_with(certificate, parent, &mut None)
262 }
263
264 fn matches_issuer_with<'c, 'p>(
265 &self,
266 certificate: &structured_pkix::Certificate<'c>,
267 parent: &'p Reader<'_>,
268 prepared: &mut Option<structured_pkix::Ordered<'c, structured_asn1::memory::Execution<'p>>>,
269 ) -> Result<IssuerAgreement> {
270 if let IssuerReading::Present(issuer) = &self.issuer {
271 return issuer.matches_with(
272 certificate,
273 parent,
274 prepared,
275 self.field,
276 self.element.span().start,
277 );
278 }
279 parent
280 .execution()
281 .charge_work(1)
282 .map_err(|reason| Error::resource(reason, self.field, self.element.span().start))?;
283 Ok(match self.issuer {
284 IssuerReading::Absent => IssuerAgreement::Unstated,
285 _ => IssuerAgreement::Unreadable,
286 })
287 }
288}
289
290#[derive(Debug)]
292pub enum CertificateReading<'a> {
293 Read(usize),
296 Unreadable(Element<'a>),
298}
299
300#[derive(Debug)]
303pub struct SigningCertificate<'a> {
304 version: Version,
305 certificates: OwnedVec<CertificateReading<'a>>,
306 identifiers: OwnedVec<CertificateId<'a>>,
307 policies: Option<Element<'a>>,
308 faults: OwnedVec<Error>,
309 element: Element<'a>,
310}
311
312#[derive(Debug)]
315pub struct SigningAttributes<'a> {
316 signed_attributes_present: bool,
317 v1: Option<SigningCertificate<'a>>,
318 v2: Option<SigningCertificate<'a>>,
319 faults: OwnedVec<Error>,
320}
321
322impl<'a> SigningAttributes<'a> {
323 pub fn read(signer: &SignerInfo<'a>, parent: &Reader<'a>) -> Result<Self> {
332 signer.require_session(parent, "signerInfo.signedAttrs")?;
333 let execution = parent.execution();
334 execution.charge_work(1).map_err(|reason| {
335 Error::resource(reason, "signerInfo.signedAttrs", signer.span().start)
336 })?;
337 let mut faults = execution.vector();
338 if let Some(unsigned) = signer.unsigned_attributes() {
339 for version in [Version::V1, Version::V2] {
340 for result in unsigned.all_in(version.identifier(), parent) {
341 let attribute = result?;
342 let field = match version {
343 Version::V1 => "signerInfo.unsignedAttrs.signingCertificate",
344 Version::V2 => "signerInfo.unsignedAttrs.signingCertificateV2",
345 };
346 record(
347 Error::schema(ErrorCode::AttributePlacement, field, attribute.span().start),
348 &mut faults,
349 field,
350 )?;
351 }
352 }
353 }
354 let v1 = read_attribute(signer, parent, Version::V1, &mut faults)?;
355 let v2 = read_attribute(signer, parent, Version::V2, &mut faults)?;
356 if v1.is_none()
357 && let Some(v2) = &v2
358 {
359 for identifier in v2.identifiers() {
366 execution.charge_work(1).map_err(|reason| {
367 Error::resource(reason, Version::V2.field(), identifier.element.span().start)
368 })?;
369 if let DigestAlgorithm::Written(algorithm) = identifier.digest {
370 execution
371 .charge_work(
372 algorithm
373 .algorithm()
374 .as_bytes()
375 .len()
376 .min(oid::SHA1.as_bytes().len()) as u64,
377 )
378 .map_err(|reason| {
379 Error::resource(reason, Version::V2.field(), algorithm.offset())
380 })?;
381 if algorithm.algorithm() == oid::SHA1 {
382 record(
383 Error::schema(
384 ErrorCode::MissingField,
385 Version::V1.field(),
386 identifier.element.span().start,
387 ),
388 &mut faults,
389 Version::V1.field(),
390 )?;
391 break;
392 }
393 }
394 }
395 }
396 Ok(Self {
397 signed_attributes_present: signer.signed_attributes().is_some(),
398 v1,
399 v2,
400 faults: faults.into_owned(),
401 })
402 }
403
404 #[must_use]
406 pub fn signed_attributes_present(&self) -> bool {
407 self.signed_attributes_present
408 }
409 #[must_use]
411 pub fn v1(&self) -> Option<&SigningCertificate<'a>> {
412 self.v1.as_ref()
413 }
414 #[must_use]
416 pub fn v2(&self) -> Option<&SigningCertificate<'a>> {
417 self.v2.as_ref()
418 }
419 #[must_use]
422 pub fn faults(&self) -> &[Error] {
423 &self.faults
424 }
425}
426
427fn read_attribute<'a, W: Work>(
428 signer: &SignerInfo<'a>,
429 parent: &Reader<'a>,
430 version: Version,
431 faults: &mut OwnedVec<Error, W>,
432) -> Result<Option<SigningCertificate<'a>>> {
433 let Some(attributes) = signer.signed_attributes() else {
434 return Ok(None);
435 };
436 let field = version.field();
437 let mut first: Option<&crate::attribute::Attribute<'a>> = None;
438 for result in attributes.all_in(version.identifier(), parent) {
439 let attribute = result?;
440 if let Some(earlier) = first {
441 if !same_encoding(
442 parent,
443 earlier.as_bytes(),
444 attribute.as_bytes(),
445 field,
446 attribute.span().start,
447 )? {
448 return Err(Error::schema(
449 ErrorCode::DuplicateAttribute,
450 field,
451 attribute.span().start,
452 ));
453 }
454 record(
455 Error::schema(ErrorCode::DuplicateAttribute, field, attribute.span().start),
456 faults,
457 field,
458 )?;
459 } else {
460 first = Some(attribute);
461 }
462 }
463 let Some(attribute) = first else {
464 return Ok(None);
465 };
466 let Some(value) = attribute.values().first() else {
467 return Err(Error::schema(
468 ErrorCode::AttributeCardinality,
469 field,
470 attribute.span().start,
471 ));
472 };
473 for extra in &attribute.values()[1..] {
474 if !same_encoding(
475 parent,
476 value.as_bytes(),
477 extra.as_bytes(),
478 field,
479 extra.span().start,
480 )? {
481 return Err(Error::schema(
482 ErrorCode::AttributeCardinality,
483 field,
484 extra.span().start,
485 ));
486 }
487 record(
488 Error::schema(ErrorCode::AttributeCardinality, field, extra.span().start),
489 faults,
490 field,
491 )?;
492 }
493 let mut reader = attribute
494 .value_reader_in(0, parent, field)?
495 .ok_or_else(|| Error::schema(ErrorCode::MissingField, field, attribute.span().start))?;
496 let original = required(&mut reader, field)?;
497 SigningCertificate::read(&reader, &original, version).map(Some)
498}
499
500impl<'a> SigningCertificate<'a> {
501 pub fn read(parent: &Reader<'a>, element: &Element<'a>, version: Version) -> Result<Self> {
508 let field = version.field();
509 require_sequence(element, field)?;
510 let mut outer = parent
511 .enter(element)
512 .map_err(|error| Error::encoding(error, field))?;
513 let certs = required(&mut outer, field)?;
514 require_sequence(&certs, field)?;
515 let mut list = outer
516 .enter(&certs)
517 .map_err(|error| Error::encoding(error, field))?;
518 let execution = parent.execution();
519 let mut faults = execution.vector();
520 let mut certificates = execution.vector();
521 let mut identifiers = execution.vector();
522 let first = required(&mut list, field)?;
523 let signer = read_identifier(&list, &first, version, &mut faults)?;
524 identifiers
525 .try_push(signer)
526 .map_err(|reason| Error::resource(reason, field, first.span().start))?;
527 certificates
528 .try_push(CertificateReading::Read(0))
529 .map_err(|reason| Error::resource(reason, field, first.span().start))?;
530 while let Some(entry) = list
531 .next_element()
532 .map_err(|error| Error::encoding(error, field))?
533 {
534 let reading = match read_identifier(&list, &entry, version, &mut faults) {
535 Ok(identifier) => {
536 let index = identifiers.len();
537 identifiers
538 .try_push(identifier)
539 .map_err(|reason| Error::resource(reason, field, entry.span().start))?;
540 CertificateReading::Read(index)
541 }
542 Err(error) => {
543 record(error, &mut faults, field)?;
544 CertificateReading::Unreadable(entry)
545 }
546 };
547 certificates
548 .try_push(reading)
549 .map_err(|reason| Error::resource(reason, field, entry.span().start))?;
550 }
551 let policies = outer
552 .next_element()
553 .map_err(|error| Error::encoding(error, field))?;
554 if let Some(policies) = &policies
555 && let Err(error) = validate_policies(&outer, policies, field)
556 {
557 record(error, &mut faults, field)?;
558 }
559 if !outer.is_empty() {
560 record(
561 Error::schema(ErrorCode::TrailingData, field, outer.offset()),
562 &mut faults,
563 field,
564 )?;
565 }
566 Ok(Self {
567 version,
568 certificates: certificates.into_owned(),
569 identifiers: identifiers.into_owned(),
570 policies,
571 faults: faults.into_owned(),
572 element: *element,
573 })
574 }
575
576 #[must_use]
578 pub fn version(&self) -> Version {
579 self.version
580 }
581 #[must_use]
583 pub fn certificates(&self) -> &[CertificateReading<'a>] {
584 &self.certificates
585 }
586 #[must_use]
588 pub fn identifiers(&self) -> &[CertificateId<'a>] {
589 &self.identifiers
590 }
591 #[must_use]
593 pub fn signer(&self) -> &CertificateId<'a> {
594 &self.identifiers[0]
597 }
598 #[must_use]
600 pub fn policies(&self) -> Option<&Element<'a>> {
601 self.policies.as_ref()
602 }
603 #[must_use]
605 pub fn faults(&self) -> &[Error] {
606 &self.faults
607 }
608 #[must_use]
610 pub fn element(&self) -> &Element<'a> {
611 &self.element
612 }
613}
614
615fn read_identifier<'a, W: Work>(
616 parent: &Reader<'a>,
617 element: &Element<'a>,
618 version: Version,
619 faults: &mut OwnedVec<Error, W>,
620) -> Result<CertificateId<'a>> {
621 let field = version.field();
622 require_sequence(element, field)?;
623 let mut inside = parent
624 .enter(element)
625 .map_err(|error| Error::encoding(error, field))?;
626 let mut next = required(&mut inside, field)?;
627 let mut digest = DigestAlgorithm::Implied {
633 algorithm: match version {
634 Version::V1 => ImpliedDigest::EssSha1,
635 Version::V2 => ImpliedDigest::EssV2Sha256,
636 },
637 field,
638 span: element.span(),
639 };
640 if version == Version::V2 && next.tag() == Tag::constructed(universal::SEQUENCE) {
641 let algorithm =
642 structured_pkix::algorithm::read(&inside, &next, field).map_err(Error::pkix)?;
643 inside
644 .charge(
645 1 + algorithm
646 .algorithm()
647 .as_bytes()
648 .len()
649 .max(oid::SHA256.as_bytes().len()) as u64,
650 )
651 .map_err(|error| Error::encoding(error, field))?;
652 if algorithm.algorithm() == oid::SHA256 && algorithm.parameters().is_none() {
656 record(
657 Error::schema(ErrorCode::DefaultWritten, field, next.span().start),
658 faults,
659 field,
660 )?;
661 }
662 digest = DigestAlgorithm::Written(algorithm);
663 next = required(&mut inside, field)?;
664 } else if version == Version::V2 && next.tag() == Tag::primitive(universal::OID) {
665 let kind = inside
666 .oid(&next)
667 .map_err(|error| Error::encoding(error, field))?;
668 inside
669 .charge(1 + kind.as_bytes().len().max(oid::SHA256.as_bytes().len()) as u64)
670 .map_err(|error| Error::encoding(error, field))?;
671 if kind != oid::SHA256 {
675 return Err(Error::schema(
676 ErrorCode::AttributeSyntax,
677 field,
678 next.span().start,
679 ));
680 }
681 record(
682 Error::schema(ErrorCode::AttributeSyntax, field, next.span().start),
683 faults,
684 field,
685 )?;
686 next = required(&mut inside, field)?;
687 }
688 let hashed = Octets::read(&inside, &next, field)?;
689 let issuer = match inside
690 .next_element()
691 .map_err(|error| Error::encoding(error, field))?
692 {
693 None => IssuerReading::Absent,
694 Some(issuer) => match read_issuer_serial(&inside, &issuer, field, faults) {
695 Ok(value) => IssuerReading::Present(value),
696 Err(error) => {
697 record(error, faults, field)?;
698 IssuerReading::Unreadable(issuer)
699 }
700 },
701 };
702 if !inside.is_empty() {
703 record(
704 Error::schema(ErrorCode::TrailingData, field, inside.offset()),
705 faults,
706 field,
707 )?;
708 }
709 Ok(CertificateId {
710 digest,
711 hashed,
712 issuer,
713 element: *element,
714 field,
715 })
716}
717
718fn read_issuer_serial<'a, W: Work>(
719 parent: &Reader<'a>,
720 element: &Element<'a>,
721 field: &'static str,
722 faults: &mut OwnedVec<Error, W>,
723) -> Result<IssuerSerial<'a>> {
724 require_sequence(element, field)?;
725 let mut inside = parent
726 .enter(element)
727 .map_err(|error| Error::encoding(error, field))?;
728 let names_element = required(&mut inside, field)?;
729 require_sequence(&names_element, field)?;
730 let serial = inside
731 .read_integer()
732 .map_err(|error| Error::encoding(error, field))?;
733 if !inside.is_empty() {
734 record(
735 Error::schema(ErrorCode::TrailingData, field, inside.offset()),
736 faults,
737 field,
738 )?;
739 }
740 let mut list = inside
741 .enter(&names_element)
742 .map_err(|error| Error::encoding(error, field))?;
743 let mut names = parent.execution().vector();
744 while let Some(name) = list
745 .next_element()
746 .map_err(|error| Error::encoding(error, field))?
747 {
748 let value = general_name::read(&list, &name, field).map_err(Error::pkix)?;
749 names
750 .try_push(value)
751 .map_err(|reason| Error::resource(reason, field, name.span().start))?;
752 }
753 if !matches!(&*names, [GeneralName::Directory(_)]) {
758 record(
759 Error::schema(
760 ErrorCode::AttributeSyntax,
761 field,
762 names_element.span().start,
763 ),
764 faults,
765 field,
766 )?;
767 }
768 Ok(IssuerSerial {
769 names: names.into_owned(),
770 serial,
771 names_element,
772 element: *element,
773 })
774}
775
776fn record<W: Work>(
777 error: Error,
778 faults: &mut OwnedVec<Error, W>,
779 field: &'static str,
780) -> Result<()> {
781 if error.is_terminal() {
782 return Err(error);
783 }
784 let at = error.offset();
785 faults
786 .try_push(error)
787 .map_err(|reason| Error::resource(reason, field, at))
788}
789
790fn require_sequence(element: &Element<'_>, field: &'static str) -> Result<()> {
791 if element.tag() != Tag::constructed(universal::SEQUENCE) {
792 return Err(Error::schema(
793 ErrorCode::UnexpectedTag,
794 field,
795 element.span().start,
796 ));
797 }
798 Ok(())
799}
800
801fn validate_policies(
802 parent: &Reader<'_>,
803 element: &Element<'_>,
804 field: &'static str,
805) -> Result<()> {
806 require_sequence(element, field)?;
807 let mut list = parent
808 .enter(element)
809 .map_err(|error| Error::encoding(error, field))?;
810 while let Some(policy) = list
811 .next_element()
812 .map_err(|error| Error::encoding(error, field))?
813 {
814 require_sequence(&policy, field)?;
815 let mut information = list
816 .enter(&policy)
817 .map_err(|error| Error::encoding(error, field))?;
818 information
819 .read_oid()
820 .map_err(|error| Error::encoding(error, field))?;
821 if let Some(qualifiers) = information
822 .next_element()
823 .map_err(|error| Error::encoding(error, field))?
824 {
825 require_sequence(&qualifiers, field)?;
826 let mut members = information
827 .enter(&qualifiers)
828 .map_err(|error| Error::encoding(error, field))?;
829 if members.is_empty() {
830 return Err(Error::schema(
831 ErrorCode::AttributeSyntax,
832 field,
833 qualifiers.span().start,
834 ));
835 }
836 while let Some(member) = members
837 .next_element()
838 .map_err(|error| Error::encoding(error, field))?
839 {
840 require_sequence(&member, field)?;
841 let mut pair = members
842 .enter(&member)
843 .map_err(|error| Error::encoding(error, field))?;
844 let kind = pair
845 .read_oid()
846 .map_err(|error| Error::encoding(error, field))?;
847 let qualifier = required(&mut pair, field)?;
848 let work = 2
849 + kind
850 .as_bytes()
851 .len()
852 .min(structured_pkix::oid::CPS_QUALIFIER.as_bytes().len())
853 as u64
854 + kind
855 .as_bytes()
856 .len()
857 .min(structured_pkix::oid::USER_NOTICE_QUALIFIER.as_bytes().len())
858 as u64;
859 pair.charge(work)
860 .map_err(|error| Error::encoding(error, field))?;
861 if (kind == structured_pkix::oid::CPS_QUALIFIER
862 || kind == structured_pkix::oid::USER_NOTICE_QUALIFIER)
863 && !structured_pkix::policy::qualifier_understood(&pair, kind, &qualifier)
864 .map_err(Error::pkix)?
865 {
866 return Err(Error::schema(
867 ErrorCode::AttributeSyntax,
868 field,
869 qualifier.span().start,
870 ));
871 }
872 if !pair.is_empty() {
873 return Err(Error::schema(ErrorCode::TrailingData, field, pair.offset()));
874 }
875 }
876 }
877 if !information.is_empty() {
878 return Err(Error::schema(
879 ErrorCode::TrailingData,
880 field,
881 information.offset(),
882 ));
883 }
884 }
885 Ok(())
886}