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