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
97#[derive(Debug)]
99pub struct CertificateId<'a> {
100 digest: DigestAlgorithm<'a>,
101 hashed: Octets<'a>,
102 issuer: IssuerReading<'a>,
103 element: Element<'a>,
104 field: &'static str,
105}
106
107impl<'a> CertificateId<'a> {
108 #[must_use]
110 pub fn digest_algorithm(&self) -> DigestAlgorithm<'a> {
111 self.digest
112 }
113 #[must_use]
115 pub fn hashed(&self) -> &Octets<'a> {
116 &self.hashed
117 }
118 #[must_use]
120 pub fn issuer_serial(&self) -> &IssuerReading<'a> {
121 &self.issuer
122 }
123 #[must_use]
125 pub fn element(&self) -> &Element<'a> {
126 &self.element
127 }
128
129 pub fn matches_issuer(
137 &self,
138 certificate: &structured_pkix::Certificate<'_>,
139 parent: &Reader<'_>,
140 ) -> Result<IssuerAgreement> {
141 self.matches_issuer_with(certificate, parent, &mut None)
142 }
143
144 fn matches_issuer_with<'c, 'p>(
145 &self,
146 certificate: &structured_pkix::Certificate<'c>,
147 parent: &'p Reader<'_>,
148 prepared: &mut Option<structured_pkix::Ordered<'c, structured_asn1::memory::Execution<'p>>>,
149 ) -> Result<IssuerAgreement> {
150 let execution = parent.execution();
151 let field = self.field;
152 execution
153 .charge_work(1)
154 .map_err(|reason| Error::resource(reason, field, self.element.span().start))?;
155 let issuer = match &self.issuer {
156 IssuerReading::Absent => return Ok(IssuerAgreement::Unstated),
157 IssuerReading::Unreadable(_) => return Ok(IssuerAgreement::Unreadable),
158 IssuerReading::Present(issuer) => issuer,
159 };
160 let at = issuer.element.span().start;
161 let serial = issuer.serial.as_bytes();
162 let actual = certificate.tbs().serial().as_bytes();
163 execution
164 .charge_work(1 + serial.len().max(actual.len()) as u64)
165 .map_err(|reason| Error::resource(reason, field, at))?;
166 if serial != actual {
167 return Ok(IssuerAgreement::Differs);
168 }
169 for name in &issuer.names {
170 execution
171 .charge_work(1)
172 .map_err(|reason| Error::resource(reason, field, at))?;
173 if let GeneralName::Directory(name) = name {
174 let actual = match &*prepared {
175 Some(actual) => actual,
176 None => prepared.insert(
177 certificate
178 .tbs()
179 .issuer()
180 .ordered_in(parent)
181 .map_err(Error::pkix)?,
182 ),
183 };
184 let asked = name.ordered_in(parent).map_err(Error::pkix)?;
185 if asked.order(actual, &execution).map_err(Error::pkix)?
186 == core::cmp::Ordering::Equal
187 {
188 return Ok(IssuerAgreement::Matches);
189 }
190 }
191 }
192 Ok(IssuerAgreement::Differs)
193 }
194}
195
196#[derive(Debug)]
198pub enum CertificateReading<'a> {
199 Read(usize),
202 Unreadable(Element<'a>),
204}
205
206#[derive(Debug)]
209pub struct SigningCertificate<'a> {
210 version: Version,
211 certificates: OwnedVec<CertificateReading<'a>>,
212 identifiers: OwnedVec<CertificateId<'a>>,
213 policies: Option<Element<'a>>,
214 faults: OwnedVec<Error>,
215 element: Element<'a>,
216}
217
218#[derive(Debug)]
221pub struct SigningAttributes<'a> {
222 signed_attributes_present: bool,
223 v1: Option<SigningCertificate<'a>>,
224 v2: Option<SigningCertificate<'a>>,
225 faults: OwnedVec<Error>,
226}
227
228impl<'a> SigningAttributes<'a> {
229 pub fn read(signer: &SignerInfo<'a>, parent: &Reader<'a>) -> Result<Self> {
238 signer.require_session(parent, "signerInfo.signedAttrs")?;
239 let execution = parent.execution();
240 execution.charge_work(1).map_err(|reason| {
241 Error::resource(reason, "signerInfo.signedAttrs", signer.span().start)
242 })?;
243 let mut faults = execution.vector();
244 if let Some(unsigned) = signer.unsigned_attributes() {
245 for version in [Version::V1, Version::V2] {
246 for result in unsigned.all_in(version.identifier(), parent) {
247 let attribute = result?;
248 let field = match version {
249 Version::V1 => "signerInfo.unsignedAttrs.signingCertificate",
250 Version::V2 => "signerInfo.unsignedAttrs.signingCertificateV2",
251 };
252 record(
253 Error::schema(ErrorCode::AttributePlacement, field, attribute.span().start),
254 &mut faults,
255 field,
256 )?;
257 }
258 }
259 }
260 let v1 = read_attribute(signer, parent, Version::V1, &mut faults)?;
261 let v2 = read_attribute(signer, parent, Version::V2, &mut faults)?;
262 if v1.is_none()
263 && let Some(v2) = &v2
264 {
265 for identifier in v2.identifiers() {
272 execution.charge_work(1).map_err(|reason| {
273 Error::resource(reason, Version::V2.field(), identifier.element.span().start)
274 })?;
275 if let DigestAlgorithm::Written(algorithm) = identifier.digest {
276 execution
277 .charge_work(
278 algorithm
279 .algorithm()
280 .as_bytes()
281 .len()
282 .min(oid::SHA1.as_bytes().len()) as u64,
283 )
284 .map_err(|reason| {
285 Error::resource(reason, Version::V2.field(), algorithm.offset())
286 })?;
287 if algorithm.algorithm() == oid::SHA1 {
288 record(
289 Error::schema(
290 ErrorCode::MissingField,
291 Version::V1.field(),
292 identifier.element.span().start,
293 ),
294 &mut faults,
295 Version::V1.field(),
296 )?;
297 break;
298 }
299 }
300 }
301 }
302 Ok(Self {
303 signed_attributes_present: signer.signed_attributes().is_some(),
304 v1,
305 v2,
306 faults: faults.into_owned(),
307 })
308 }
309
310 #[must_use]
312 pub fn signed_attributes_present(&self) -> bool {
313 self.signed_attributes_present
314 }
315 #[must_use]
317 pub fn v1(&self) -> Option<&SigningCertificate<'a>> {
318 self.v1.as_ref()
319 }
320 #[must_use]
322 pub fn v2(&self) -> Option<&SigningCertificate<'a>> {
323 self.v2.as_ref()
324 }
325 #[must_use]
328 pub fn faults(&self) -> &[Error] {
329 &self.faults
330 }
331}
332
333fn read_attribute<'a, W: Work>(
334 signer: &SignerInfo<'a>,
335 parent: &Reader<'a>,
336 version: Version,
337 faults: &mut OwnedVec<Error, W>,
338) -> Result<Option<SigningCertificate<'a>>> {
339 let Some(attributes) = signer.signed_attributes() else {
340 return Ok(None);
341 };
342 let field = version.field();
343 let mut first: Option<&crate::attribute::Attribute<'a>> = None;
344 for result in attributes.all_in(version.identifier(), parent) {
345 let attribute = result?;
346 if let Some(earlier) = first {
347 if !same_encoding(
348 parent,
349 earlier.as_bytes(),
350 attribute.as_bytes(),
351 field,
352 attribute.span().start,
353 )? {
354 return Err(Error::schema(
355 ErrorCode::AttributeCardinality,
356 field,
357 attribute.span().start,
358 ));
359 }
360 record(
361 Error::schema(
362 ErrorCode::AttributeCardinality,
363 field,
364 attribute.span().start,
365 ),
366 faults,
367 field,
368 )?;
369 } else {
370 first = Some(attribute);
371 }
372 }
373 let Some(attribute) = first else {
374 return Ok(None);
375 };
376 let Some(value) = attribute.values().first() else {
377 return Err(Error::schema(
378 ErrorCode::AttributeCardinality,
379 field,
380 attribute.span().start,
381 ));
382 };
383 for extra in &attribute.values()[1..] {
384 if !same_encoding(
385 parent,
386 value.as_bytes(),
387 extra.as_bytes(),
388 field,
389 extra.span().start,
390 )? {
391 return Err(Error::schema(
392 ErrorCode::AttributeCardinality,
393 field,
394 extra.span().start,
395 ));
396 }
397 record(
398 Error::schema(ErrorCode::AttributeCardinality, field, extra.span().start),
399 faults,
400 field,
401 )?;
402 }
403 let mut reader = attribute
404 .value_reader_in(0, parent, field)?
405 .ok_or_else(|| Error::schema(ErrorCode::MissingField, field, attribute.span().start))?;
406 let original = required(&mut reader, field)?;
407 SigningCertificate::read(&reader, &original, version).map(Some)
408}
409
410fn same_encoding(
411 parent: &Reader<'_>,
412 left: &[u8],
413 right: &[u8],
414 field: &'static str,
415 at: u64,
416) -> Result<bool> {
417 let execution = parent.execution();
418 execution
419 .charge_work(1)
420 .map_err(|reason| Error::resource(reason, field, at))?;
421 if left.len() != right.len() {
422 return Ok(false);
423 }
424 execution
425 .charge_work(left.len() as u64)
426 .map_err(|reason| Error::resource(reason, field, at))?;
427 Ok(left == right)
428}
429
430impl<'a> SigningCertificate<'a> {
431 pub fn read(parent: &Reader<'a>, element: &Element<'a>, version: Version) -> Result<Self> {
438 let field = version.field();
439 require_sequence(element, field)?;
440 let mut outer = parent
441 .enter(element)
442 .map_err(|error| Error::encoding(error, field))?;
443 let certs = required(&mut outer, field)?;
444 require_sequence(&certs, field)?;
445 let mut list = outer
446 .enter(&certs)
447 .map_err(|error| Error::encoding(error, field))?;
448 let execution = parent.execution();
449 let mut faults = execution.vector();
450 let mut certificates = execution.vector();
451 let mut identifiers = execution.vector();
452 let first = required(&mut list, field)?;
453 let signer = read_identifier(&list, &first, version, &mut faults)?;
454 identifiers
455 .try_push(signer)
456 .map_err(|reason| Error::resource(reason, field, first.span().start))?;
457 certificates
458 .try_push(CertificateReading::Read(0))
459 .map_err(|reason| Error::resource(reason, field, first.span().start))?;
460 while let Some(entry) = list
461 .next_element()
462 .map_err(|error| Error::encoding(error, field))?
463 {
464 let reading = match read_identifier(&list, &entry, version, &mut faults) {
465 Ok(identifier) => {
466 let index = identifiers.len();
467 identifiers
468 .try_push(identifier)
469 .map_err(|reason| Error::resource(reason, field, entry.span().start))?;
470 CertificateReading::Read(index)
471 }
472 Err(error) => {
473 record(error, &mut faults, field)?;
474 CertificateReading::Unreadable(entry)
475 }
476 };
477 certificates
478 .try_push(reading)
479 .map_err(|reason| Error::resource(reason, field, entry.span().start))?;
480 }
481 let policies = outer
482 .next_element()
483 .map_err(|error| Error::encoding(error, field))?;
484 if let Some(policies) = &policies
485 && let Err(error) = validate_policies(&outer, policies, field)
486 {
487 record(error, &mut faults, field)?;
488 }
489 if !outer.is_empty() {
490 record(
491 Error::schema(ErrorCode::TrailingData, field, outer.offset()),
492 &mut faults,
493 field,
494 )?;
495 }
496 Ok(Self {
497 version,
498 certificates: certificates.into_owned(),
499 identifiers: identifiers.into_owned(),
500 policies,
501 faults: faults.into_owned(),
502 element: *element,
503 })
504 }
505
506 #[must_use]
508 pub fn version(&self) -> Version {
509 self.version
510 }
511 #[must_use]
513 pub fn certificates(&self) -> &[CertificateReading<'a>] {
514 &self.certificates
515 }
516 #[must_use]
518 pub fn identifiers(&self) -> &[CertificateId<'a>] {
519 &self.identifiers
520 }
521 #[must_use]
523 pub fn signer(&self) -> &CertificateId<'a> {
524 &self.identifiers[0]
527 }
528 #[must_use]
530 pub fn policies(&self) -> Option<&Element<'a>> {
531 self.policies.as_ref()
532 }
533 #[must_use]
535 pub fn faults(&self) -> &[Error] {
536 &self.faults
537 }
538 #[must_use]
540 pub fn element(&self) -> &Element<'a> {
541 &self.element
542 }
543}
544
545fn read_identifier<'a, W: Work>(
546 parent: &Reader<'a>,
547 element: &Element<'a>,
548 version: Version,
549 faults: &mut OwnedVec<Error, W>,
550) -> Result<CertificateId<'a>> {
551 let field = version.field();
552 require_sequence(element, field)?;
553 let mut inside = parent
554 .enter(element)
555 .map_err(|error| Error::encoding(error, field))?;
556 let mut next = required(&mut inside, field)?;
557 let mut digest = DigestAlgorithm::Implied {
563 algorithm: match version {
564 Version::V1 => ImpliedDigest::EssSha1,
565 Version::V2 => ImpliedDigest::EssV2Sha256,
566 },
567 field,
568 span: element.span(),
569 };
570 if version == Version::V2 && next.tag() == Tag::constructed(universal::SEQUENCE) {
571 let algorithm =
572 structured_pkix::algorithm::read(&inside, &next, field).map_err(Error::pkix)?;
573 inside
574 .charge(
575 1 + algorithm
576 .algorithm()
577 .as_bytes()
578 .len()
579 .max(oid::SHA256.as_bytes().len()) as u64,
580 )
581 .map_err(|error| Error::encoding(error, field))?;
582 if algorithm.algorithm() == oid::SHA256 && algorithm.parameters().is_none() {
586 record(
587 Error::schema(ErrorCode::DefaultWritten, field, next.span().start),
588 faults,
589 field,
590 )?;
591 }
592 digest = DigestAlgorithm::Written(algorithm);
593 next = required(&mut inside, field)?;
594 } else if version == Version::V2 && next.tag() == Tag::primitive(universal::OID) {
595 let kind = inside
596 .oid(&next)
597 .map_err(|error| Error::encoding(error, field))?;
598 inside
599 .charge(1 + kind.as_bytes().len().max(oid::SHA256.as_bytes().len()) as u64)
600 .map_err(|error| Error::encoding(error, field))?;
601 if kind != oid::SHA256 {
605 return Err(Error::schema(
606 ErrorCode::AttributeSyntax,
607 field,
608 next.span().start,
609 ));
610 }
611 record(
612 Error::schema(ErrorCode::AttributeSyntax, field, next.span().start),
613 faults,
614 field,
615 )?;
616 next = required(&mut inside, field)?;
617 }
618 let hashed = Octets::read(&inside, &next, field)?;
619 let issuer = match inside
620 .next_element()
621 .map_err(|error| Error::encoding(error, field))?
622 {
623 None => IssuerReading::Absent,
624 Some(issuer) => match read_issuer_serial(&inside, &issuer, field, faults) {
625 Ok(value) => IssuerReading::Present(value),
626 Err(error) => {
627 record(error, faults, field)?;
628 IssuerReading::Unreadable(issuer)
629 }
630 },
631 };
632 if !inside.is_empty() {
633 record(
634 Error::schema(ErrorCode::TrailingData, field, inside.offset()),
635 faults,
636 field,
637 )?;
638 }
639 Ok(CertificateId {
640 digest,
641 hashed,
642 issuer,
643 element: *element,
644 field,
645 })
646}
647
648fn read_issuer_serial<'a, W: Work>(
649 parent: &Reader<'a>,
650 element: &Element<'a>,
651 field: &'static str,
652 faults: &mut OwnedVec<Error, W>,
653) -> Result<IssuerSerial<'a>> {
654 require_sequence(element, field)?;
655 let mut inside = parent
656 .enter(element)
657 .map_err(|error| Error::encoding(error, field))?;
658 let names_element = required(&mut inside, field)?;
659 require_sequence(&names_element, field)?;
660 let serial = inside
661 .read_integer()
662 .map_err(|error| Error::encoding(error, field))?;
663 if !inside.is_empty() {
664 record(
665 Error::schema(ErrorCode::TrailingData, field, inside.offset()),
666 faults,
667 field,
668 )?;
669 }
670 let mut list = inside
671 .enter(&names_element)
672 .map_err(|error| Error::encoding(error, field))?;
673 let mut names = parent.execution().vector();
674 while let Some(name) = list
675 .next_element()
676 .map_err(|error| Error::encoding(error, field))?
677 {
678 let value = general_name::read(&list, &name, field).map_err(Error::pkix)?;
679 names
680 .try_push(value)
681 .map_err(|reason| Error::resource(reason, field, name.span().start))?;
682 }
683 if !matches!(&*names, [GeneralName::Directory(_)]) {
688 record(
689 Error::schema(
690 ErrorCode::AttributeSyntax,
691 field,
692 names_element.span().start,
693 ),
694 faults,
695 field,
696 )?;
697 }
698 Ok(IssuerSerial {
699 names: names.into_owned(),
700 serial,
701 names_element,
702 element: *element,
703 })
704}
705
706fn record<W: Work>(
707 error: Error,
708 faults: &mut OwnedVec<Error, W>,
709 field: &'static str,
710) -> Result<()> {
711 if error.is_terminal() {
712 return Err(error);
713 }
714 let at = error.offset();
715 faults
716 .try_push(error)
717 .map_err(|reason| Error::resource(reason, field, at))
718}
719
720fn require_sequence(element: &Element<'_>, field: &'static str) -> Result<()> {
721 if element.tag() != Tag::constructed(universal::SEQUENCE) {
722 return Err(Error::schema(
723 ErrorCode::UnexpectedTag,
724 field,
725 element.span().start,
726 ));
727 }
728 Ok(())
729}
730
731fn validate_policies(
732 parent: &Reader<'_>,
733 element: &Element<'_>,
734 field: &'static str,
735) -> Result<()> {
736 require_sequence(element, field)?;
737 let mut list = parent
738 .enter(element)
739 .map_err(|error| Error::encoding(error, field))?;
740 while let Some(policy) = list
741 .next_element()
742 .map_err(|error| Error::encoding(error, field))?
743 {
744 require_sequence(&policy, field)?;
745 let mut information = list
746 .enter(&policy)
747 .map_err(|error| Error::encoding(error, field))?;
748 information
749 .read_oid()
750 .map_err(|error| Error::encoding(error, field))?;
751 if let Some(qualifiers) = information
752 .next_element()
753 .map_err(|error| Error::encoding(error, field))?
754 {
755 require_sequence(&qualifiers, field)?;
756 let mut members = information
757 .enter(&qualifiers)
758 .map_err(|error| Error::encoding(error, field))?;
759 if members.is_empty() {
760 return Err(Error::schema(
761 ErrorCode::AttributeSyntax,
762 field,
763 qualifiers.span().start,
764 ));
765 }
766 while let Some(member) = members
767 .next_element()
768 .map_err(|error| Error::encoding(error, field))?
769 {
770 require_sequence(&member, field)?;
771 let mut pair = members
772 .enter(&member)
773 .map_err(|error| Error::encoding(error, field))?;
774 let kind = pair
775 .read_oid()
776 .map_err(|error| Error::encoding(error, field))?;
777 let qualifier = required(&mut pair, field)?;
778 let work = 2
779 + kind
780 .as_bytes()
781 .len()
782 .min(structured_pkix::oid::CPS_QUALIFIER.as_bytes().len())
783 as u64
784 + kind
785 .as_bytes()
786 .len()
787 .min(structured_pkix::oid::USER_NOTICE_QUALIFIER.as_bytes().len())
788 as u64;
789 pair.charge(work)
790 .map_err(|error| Error::encoding(error, field))?;
791 if (kind == structured_pkix::oid::CPS_QUALIFIER
792 || kind == structured_pkix::oid::USER_NOTICE_QUALIFIER)
793 && !structured_pkix::policy::qualifier_understood(&pair, kind, &qualifier)
794 .map_err(Error::pkix)?
795 {
796 return Err(Error::schema(
797 ErrorCode::AttributeSyntax,
798 field,
799 qualifier.span().start,
800 ));
801 }
802 if !pair.is_empty() {
803 return Err(Error::schema(ErrorCode::TrailingData, field, pair.offset()));
804 }
805 }
806 }
807 if !information.is_empty() {
808 return Err(Error::schema(
809 ErrorCode::TrailingData,
810 field,
811 information.offset(),
812 ));
813 }
814 }
815 Ok(())
816}