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 parser: &'a structured_asn1::Parser,
317 signer: &'a [u8],
318 signer_start: u64,
319 signed_attributes_present: bool,
320 v1: Option<SigningCertificate<'a>>,
321 v2: Option<SigningCertificate<'a>>,
322 faults: OwnedVec<Error>,
323}
324
325impl<'a> SigningAttributes<'a> {
326 pub(crate) fn require_signer(
327 &self,
328 signer: &SignerInfo<'_>,
329 parent: &Reader<'_>,
330 ) -> Result<()> {
331 signer.require_session(parent, "signerInfo.signedAttrs")?;
332 if !core::ptr::eq(self.parser, parent.parser())
336 || self.signer_start != signer.span().start
337 || !core::ptr::eq(self.signer, signer.as_bytes())
338 {
339 return Err(Error::pkix(structured_pkix::Error::new(
340 structured_pkix::ErrorCode::ForeignReader,
341 "signerInfo.signedAttrs",
342 signer.span().start,
343 )));
344 }
345 Ok(())
346 }
347
348 pub fn read(signer: &SignerInfo<'a>, parent: &Reader<'a>) -> Result<Self> {
357 Self::read_with(signer, parent, false)
358 }
359
360 pub fn inspect(signer: &SignerInfo<'a>, parent: &Reader<'a>) -> Result<Self> {
369 Self::read_with(signer, parent, true)
370 }
371
372 fn read_with(signer: &SignerInfo<'a>, parent: &Reader<'a>, inspect: bool) -> Result<Self> {
373 signer.require_session(parent, "signerInfo.signedAttrs")?;
374 let execution = parent.execution();
375 execution.charge_work(1).map_err(|reason| {
376 Error::resource(reason, "signerInfo.signedAttrs", signer.span().start)
377 })?;
378 let mut faults = execution.vector();
379 if let Some(unsigned) = signer.unsigned_attributes() {
380 for version in [Version::V1, Version::V2] {
381 for result in unsigned.all_in(version.identifier(), parent) {
382 let attribute = result?;
383 let field = match version {
384 Version::V1 => "signerInfo.unsignedAttrs.signingCertificate",
385 Version::V2 => "signerInfo.unsignedAttrs.signingCertificateV2",
386 };
387 record(
388 Error::schema(ErrorCode::AttributePlacement, field, attribute.span().start),
389 &mut faults,
390 field,
391 )?;
392 }
393 }
394 }
395 let v1 = inspect_attribute(signer, parent, Version::V1, &mut faults, inspect)?;
396 let v2 = inspect_attribute(signer, parent, Version::V2, &mut faults, inspect)?;
397 if v1.is_none()
398 && let Some(v2) = &v2
399 {
400 for identifier in v2.identifiers() {
407 execution.charge_work(1).map_err(|reason| {
408 Error::resource(reason, Version::V2.field(), identifier.element.span().start)
409 })?;
410 if let DigestAlgorithm::Written(algorithm) = identifier.digest {
411 execution
412 .charge_work(
413 algorithm
414 .algorithm()
415 .as_bytes()
416 .len()
417 .min(oid::SHA1.as_bytes().len()) as u64,
418 )
419 .map_err(|reason| {
420 Error::resource(reason, Version::V2.field(), algorithm.offset())
421 })?;
422 if algorithm.algorithm() == oid::SHA1 {
423 record(
424 Error::schema(
425 ErrorCode::MissingField,
426 Version::V1.field(),
427 identifier.element.span().start,
428 ),
429 &mut faults,
430 Version::V1.field(),
431 )?;
432 break;
433 }
434 }
435 }
436 }
437 Ok(Self {
438 parser: parent.parser(),
439 signer: signer.as_bytes(),
440 signer_start: signer.span().start,
441 signed_attributes_present: signer.signed_attributes().is_some(),
442 v1,
443 v2,
444 faults: faults.into_owned(),
445 })
446 }
447
448 #[must_use]
450 pub fn signed_attributes_present(&self) -> bool {
451 self.signed_attributes_present
452 }
453 #[must_use]
455 pub fn v1(&self) -> Option<&SigningCertificate<'a>> {
456 self.v1.as_ref()
457 }
458 #[must_use]
460 pub fn v2(&self) -> Option<&SigningCertificate<'a>> {
461 self.v2.as_ref()
462 }
463 #[must_use]
466 pub fn faults(&self) -> &[Error] {
467 &self.faults
468 }
469}
470
471fn inspect_attribute<'a, W: Work>(
472 signer: &SignerInfo<'a>,
473 parent: &Reader<'a>,
474 version: Version,
475 faults: &mut OwnedVec<Error, W>,
476 inspect: bool,
477) -> Result<Option<SigningCertificate<'a>>> {
478 match read_attribute(signer, parent, version, faults) {
479 Err(cause) if inspect && !cause.is_terminal() => {
484 record(cause, faults, version.field())?;
485 Ok(None)
486 }
487 reading => reading,
488 }
489}
490
491fn read_attribute<'a, W: Work>(
492 signer: &SignerInfo<'a>,
493 parent: &Reader<'a>,
494 version: Version,
495 faults: &mut OwnedVec<Error, W>,
496) -> Result<Option<SigningCertificate<'a>>> {
497 let Some(attributes) = signer.signed_attributes() else {
498 return Ok(None);
499 };
500 let field = version.field();
501 let mut first: Option<&crate::attribute::Attribute<'a>> = None;
502 for result in attributes.all_in(version.identifier(), parent) {
503 let attribute = result?;
504 if let Some(earlier) = first {
505 if !same_encoding(
506 parent,
507 earlier.as_bytes(),
508 attribute.as_bytes(),
509 field,
510 attribute.span().start,
511 )? {
512 return Err(Error::schema(
513 ErrorCode::DuplicateAttribute,
514 field,
515 attribute.span().start,
516 ));
517 }
518 record(
519 Error::schema(ErrorCode::DuplicateAttribute, field, attribute.span().start),
520 faults,
521 field,
522 )?;
523 } else {
524 first = Some(attribute);
525 }
526 }
527 let Some(attribute) = first else {
528 return Ok(None);
529 };
530 let Some(value) = attribute.values().first() else {
531 return Err(Error::schema(
532 ErrorCode::AttributeCardinality,
533 field,
534 attribute.span().start,
535 ));
536 };
537 for extra in &attribute.values()[1..] {
538 if !same_encoding(
539 parent,
540 value.as_bytes(),
541 extra.as_bytes(),
542 field,
543 extra.span().start,
544 )? {
545 return Err(Error::schema(
546 ErrorCode::AttributeCardinality,
547 field,
548 extra.span().start,
549 ));
550 }
551 record(
552 Error::schema(ErrorCode::AttributeCardinality, field, extra.span().start),
553 faults,
554 field,
555 )?;
556 }
557 let mut reader = attribute
558 .value_reader_in(0, parent, field)?
559 .ok_or_else(|| Error::schema(ErrorCode::MissingField, field, attribute.span().start))?;
560 let original = required(&mut reader, field)?;
561 SigningCertificate::read(&reader, &original, version).map(Some)
562}
563
564impl<'a> SigningCertificate<'a> {
565 pub fn read(parent: &Reader<'a>, element: &Element<'a>, version: Version) -> Result<Self> {
572 let field = version.field();
573 require_sequence(element, field)?;
574 let mut outer = parent
575 .enter(element)
576 .map_err(|error| Error::encoding(error, field))?;
577 let certs = required(&mut outer, field)?;
578 require_sequence(&certs, field)?;
579 let mut list = outer
580 .enter(&certs)
581 .map_err(|error| Error::encoding(error, field))?;
582 let execution = parent.execution();
583 let mut faults = execution.vector();
584 let mut certificates = execution.vector();
585 let mut identifiers = execution.vector();
586 let first = required(&mut list, field)?;
587 let signer = read_identifier(&list, &first, version, &mut faults)?;
588 identifiers
589 .try_push(signer)
590 .map_err(|reason| Error::resource(reason, field, first.span().start))?;
591 certificates
592 .try_push(CertificateReading::Read(0))
593 .map_err(|reason| Error::resource(reason, field, first.span().start))?;
594 while let Some(entry) = list
595 .next_element()
596 .map_err(|error| Error::encoding(error, field))?
597 {
598 let reading = match read_identifier(&list, &entry, version, &mut faults) {
599 Ok(identifier) => {
600 let index = identifiers.len();
601 identifiers
602 .try_push(identifier)
603 .map_err(|reason| Error::resource(reason, field, entry.span().start))?;
604 CertificateReading::Read(index)
605 }
606 Err(error) => {
607 record(error, &mut faults, field)?;
608 CertificateReading::Unreadable(entry)
609 }
610 };
611 certificates
612 .try_push(reading)
613 .map_err(|reason| Error::resource(reason, field, entry.span().start))?;
614 }
615 let policies = outer
616 .next_element()
617 .map_err(|error| Error::encoding(error, field))?;
618 if let Some(policies) = &policies
619 && let Err(error) = validate_policies(&outer, policies, field)
620 {
621 record(error, &mut faults, field)?;
622 }
623 if !outer.is_empty() {
624 record(
625 Error::schema(ErrorCode::TrailingData, field, outer.offset()),
626 &mut faults,
627 field,
628 )?;
629 }
630 Ok(Self {
631 version,
632 certificates: certificates.into_owned(),
633 identifiers: identifiers.into_owned(),
634 policies,
635 faults: faults.into_owned(),
636 element: *element,
637 })
638 }
639
640 #[must_use]
642 pub fn version(&self) -> Version {
643 self.version
644 }
645 #[must_use]
647 pub fn certificates(&self) -> &[CertificateReading<'a>] {
648 &self.certificates
649 }
650 #[must_use]
652 pub fn identifiers(&self) -> &[CertificateId<'a>] {
653 &self.identifiers
654 }
655 #[must_use]
657 pub fn signer(&self) -> &CertificateId<'a> {
658 &self.identifiers[0]
661 }
662 #[must_use]
664 pub fn policies(&self) -> Option<&Element<'a>> {
665 self.policies.as_ref()
666 }
667 #[must_use]
669 pub fn faults(&self) -> &[Error] {
670 &self.faults
671 }
672 #[must_use]
674 pub fn element(&self) -> &Element<'a> {
675 &self.element
676 }
677}
678
679fn read_identifier<'a, W: Work>(
680 parent: &Reader<'a>,
681 element: &Element<'a>,
682 version: Version,
683 faults: &mut OwnedVec<Error, W>,
684) -> Result<CertificateId<'a>> {
685 let field = version.field();
686 require_sequence(element, field)?;
687 let mut inside = parent
688 .enter(element)
689 .map_err(|error| Error::encoding(error, field))?;
690 let mut next = required(&mut inside, field)?;
691 let mut digest = DigestAlgorithm::Implied {
697 algorithm: match version {
698 Version::V1 => ImpliedDigest::EssSha1,
699 Version::V2 => ImpliedDigest::EssV2Sha256,
700 },
701 field,
702 span: element.span(),
703 };
704 if version == Version::V2 && next.tag() == Tag::constructed(universal::SEQUENCE) {
705 let algorithm =
706 structured_pkix::algorithm::read(&inside, &next, field).map_err(Error::pkix)?;
707 inside
708 .charge(
709 1 + algorithm
710 .algorithm()
711 .as_bytes()
712 .len()
713 .max(oid::SHA256.as_bytes().len()) as u64,
714 )
715 .map_err(|error| Error::encoding(error, field))?;
716 if algorithm.algorithm() == oid::SHA256 && algorithm.parameters().is_none() {
720 record(
721 Error::schema(ErrorCode::DefaultWritten, field, next.span().start),
722 faults,
723 field,
724 )?;
725 }
726 digest = DigestAlgorithm::Written(algorithm);
727 next = required(&mut inside, field)?;
728 } else if version == Version::V2 && next.tag() == Tag::primitive(universal::OID) {
729 let kind = inside
730 .oid(&next)
731 .map_err(|error| Error::encoding(error, field))?;
732 inside
733 .charge(1 + kind.as_bytes().len().max(oid::SHA256.as_bytes().len()) as u64)
734 .map_err(|error| Error::encoding(error, field))?;
735 if kind != oid::SHA256 {
739 return Err(Error::schema(
740 ErrorCode::AttributeSyntax,
741 field,
742 next.span().start,
743 ));
744 }
745 record(
746 Error::schema(ErrorCode::AttributeSyntax, field, next.span().start),
747 faults,
748 field,
749 )?;
750 next = required(&mut inside, field)?;
751 }
752 let hashed = Octets::read(&inside, &next, field)?;
753 let issuer = match inside
754 .next_element()
755 .map_err(|error| Error::encoding(error, field))?
756 {
757 None => IssuerReading::Absent,
758 Some(issuer) => match read_issuer_serial(&inside, &issuer, field, faults) {
759 Ok(value) => IssuerReading::Present(value),
760 Err(error) => {
761 record(error, faults, field)?;
762 IssuerReading::Unreadable(issuer)
763 }
764 },
765 };
766 if !inside.is_empty() {
767 record(
768 Error::schema(ErrorCode::TrailingData, field, inside.offset()),
769 faults,
770 field,
771 )?;
772 }
773 Ok(CertificateId {
774 digest,
775 hashed,
776 issuer,
777 element: *element,
778 field,
779 })
780}
781
782fn read_issuer_serial<'a, W: Work>(
783 parent: &Reader<'a>,
784 element: &Element<'a>,
785 field: &'static str,
786 faults: &mut OwnedVec<Error, W>,
787) -> Result<IssuerSerial<'a>> {
788 require_sequence(element, field)?;
789 let mut inside = parent
790 .enter(element)
791 .map_err(|error| Error::encoding(error, field))?;
792 let names_element = required(&mut inside, field)?;
793 require_sequence(&names_element, field)?;
794 let serial = inside
795 .read_integer()
796 .map_err(|error| Error::encoding(error, field))?;
797 if !inside.is_empty() {
798 record(
799 Error::schema(ErrorCode::TrailingData, field, inside.offset()),
800 faults,
801 field,
802 )?;
803 }
804 let mut list = inside
805 .enter(&names_element)
806 .map_err(|error| Error::encoding(error, field))?;
807 let mut names = parent.execution().vector();
808 while let Some(name) = list
809 .next_element()
810 .map_err(|error| Error::encoding(error, field))?
811 {
812 let value = general_name::read(&list, &name, field).map_err(Error::pkix)?;
813 names
814 .try_push(value)
815 .map_err(|reason| Error::resource(reason, field, name.span().start))?;
816 }
817 if !matches!(&*names, [GeneralName::Directory(_)]) {
822 record(
823 Error::schema(
824 ErrorCode::AttributeSyntax,
825 field,
826 names_element.span().start,
827 ),
828 faults,
829 field,
830 )?;
831 }
832 Ok(IssuerSerial {
833 names: names.into_owned(),
834 serial,
835 names_element,
836 element: *element,
837 })
838}
839
840fn record<W: Work>(
841 error: Error,
842 faults: &mut OwnedVec<Error, W>,
843 field: &'static str,
844) -> Result<()> {
845 if error.is_terminal() {
846 return Err(error);
847 }
848 let at = error.offset();
849 faults
850 .try_push(error)
851 .map_err(|reason| Error::resource(reason, field, at))
852}
853
854fn require_sequence(element: &Element<'_>, field: &'static str) -> Result<()> {
855 if element.tag() != Tag::constructed(universal::SEQUENCE) {
856 return Err(Error::schema(
857 ErrorCode::UnexpectedTag,
858 field,
859 element.span().start,
860 ));
861 }
862 Ok(())
863}
864
865fn validate_policies(
866 parent: &Reader<'_>,
867 element: &Element<'_>,
868 field: &'static str,
869) -> Result<()> {
870 require_sequence(element, field)?;
871 let mut list = parent
872 .enter(element)
873 .map_err(|error| Error::encoding(error, field))?;
874 while let Some(policy) = list
875 .next_element()
876 .map_err(|error| Error::encoding(error, field))?
877 {
878 require_sequence(&policy, field)?;
879 let mut information = list
880 .enter(&policy)
881 .map_err(|error| Error::encoding(error, field))?;
882 information
883 .read_oid()
884 .map_err(|error| Error::encoding(error, field))?;
885 if let Some(qualifiers) = information
886 .next_element()
887 .map_err(|error| Error::encoding(error, field))?
888 {
889 require_sequence(&qualifiers, field)?;
890 let mut members = information
891 .enter(&qualifiers)
892 .map_err(|error| Error::encoding(error, field))?;
893 if members.is_empty() {
894 return Err(Error::schema(
895 ErrorCode::AttributeSyntax,
896 field,
897 qualifiers.span().start,
898 ));
899 }
900 while let Some(member) = members
901 .next_element()
902 .map_err(|error| Error::encoding(error, field))?
903 {
904 require_sequence(&member, field)?;
905 let mut pair = members
906 .enter(&member)
907 .map_err(|error| Error::encoding(error, field))?;
908 let kind = pair
909 .read_oid()
910 .map_err(|error| Error::encoding(error, field))?;
911 let qualifier = required(&mut pair, field)?;
912 let work = 2
913 + kind
914 .as_bytes()
915 .len()
916 .min(structured_pkix::oid::CPS_QUALIFIER.as_bytes().len())
917 as u64
918 + kind
919 .as_bytes()
920 .len()
921 .min(structured_pkix::oid::USER_NOTICE_QUALIFIER.as_bytes().len())
922 as u64;
923 pair.charge(work)
924 .map_err(|error| Error::encoding(error, field))?;
925 if (kind == structured_pkix::oid::CPS_QUALIFIER
926 || kind == structured_pkix::oid::USER_NOTICE_QUALIFIER)
927 && !structured_pkix::policy::qualifier_understood(&pair, kind, &qualifier)
928 .map_err(Error::pkix)?
929 {
930 return Err(Error::schema(
931 ErrorCode::AttributeSyntax,
932 field,
933 qualifier.span().start,
934 ));
935 }
936 if !pair.is_empty() {
937 return Err(Error::schema(ErrorCode::TrailingData, field, pair.offset()));
938 }
939 }
940 }
941 if !information.is_empty() {
942 return Err(Error::schema(
943 ErrorCode::TrailingData,
944 field,
945 information.offset(),
946 ));
947 }
948 }
949 Ok(())
950}