Skip to main content

structured_cms/
ess.rs

1//! Original ESS certificate bindings and signed validation-set restrictions.
2
3use 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/// The signed attribute's schema, not the CMS content digest algorithm.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum Version {
16    /// SHA-1 is mandatory in `ESSCertID` (RFC2634 §5.4.1).
17    V1,
18    /// `ESSCertIDv2` carries an algorithm or omits its SHA-256 default.
19    V2,
20}
21
22impl Version {
23    /// The attribute identifier that selects this schema.
24    #[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/// Optional issuerSerial is never silently discarded after a read failure.
40#[derive(Debug)]
41pub enum IssuerReading<'a> {
42    /// The schema field was not written.
43    Absent,
44    /// Original names and serial, including a separately reported profile fault.
45    Present(IssuerSerial<'a>),
46    /// The original field was written but could not be interpreted uniquely.
47    /// Its diagnostic is retained in the enclosing signing-certificate faults.
48    Unreadable(Element<'a>),
49}
50
51/// Agreement of the optional signed issuer/serial restriction alone.
52/// Hash agreement, retained faults and certificate trust remain separate.
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub enum IssuerAgreement {
55    /// No optional restriction was written; this says nothing about the hash.
56    Unstated,
57    /// A readable directoryName and serial identify this certificate's issuer.
58    Matches,
59    /// Readable written restrictions identify something else.
60    Differs,
61    /// The written restriction has no uniquely readable identity.
62    Unreadable,
63}
64
65/// Original certificate issuer names and serial, without normalization/copying.
66#[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    /// Every written issuer name, in its original order.
76    #[must_use]
77    pub fn names(&self) -> &[GeneralName<'a>] {
78        &self.names
79    }
80    /// Original serial-number contents, without re-encoding.
81    #[must_use]
82    pub fn serial(&self) -> Integer<'a> {
83        self.serial
84    }
85    /// Exact original `GeneralNames` element for independently retained evidence.
86    #[must_use]
87    pub fn names_element(&self) -> &Element<'a> {
88        &self.names_element
89    }
90    /// Original issuerSerial location.
91    #[must_use]
92    pub fn span(&self) -> Span {
93        self.element.span()
94    }
95}
96
97/// One readable certificate identifier; hash verification is a separate step.
98#[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    /// Original written identity or the exact schema-supplied identity.
109    #[must_use]
110    pub fn digest_algorithm(&self) -> DigestAlgorithm<'a> {
111        self.digest
112    }
113    /// Logical certHash octets over the complete original DER certificate.
114    #[must_use]
115    pub fn hashed(&self) -> &Octets<'a> {
116        &self.hashed
117    }
118    /// Absence, readable value and unreadable written field remain distinct.
119    #[must_use]
120    pub fn issuer_serial(&self) -> &IssuerReading<'a> {
121        &self.issuer
122    }
123    /// Original identifier element, without serialization.
124    #[must_use]
125    pub fn element(&self) -> &Element<'a> {
126        &self.element
127    }
128
129    /// Compares issuer/serial using the current producing query ceilings.
130    ///
131    /// The certificate can come from another retained source session; its
132    /// canonical issuer is prepared once for this query, without re-decoding
133    /// the certificate or creating a replacement Parser. Resource refusal is
134    /// separate from Differs, Unstated and Unreadable. This does not check the
135    /// certificate hash, signature, path, profile faults or trust.
136    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/// Later identifiers must remain in the signed restriction set even if unreadable.
197#[derive(Debug)]
198pub enum CertificateReading<'a> {
199    /// Index into [`SigningCertificate::identifiers`], without one allocation
200    /// per identifier or inflating every unreadable restriction's metadata.
201    Read(usize),
202    /// Original unreadable restriction; never treated as an absent restriction.
203    Unreadable(Element<'a>),
204}
205
206/// One signing-certificate value, preserving the whole signed validation set.
207/// V1 and V2 values are evaluated independently (RFC5035 §2).
208#[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/// Both independently evaluated ESS attributes, with placement/cardinality
219/// diagnostics separate from certificate/hash/path checking.
220#[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    /// Reads the recognized signed fields using original value provenance.
230    ///
231    /// RFC5035 §§3/5 require one instance and one value in signed attributes.
232    /// Byte-identical repeats retain one reading plus a cardinality fault;
233    /// conflicting values refuse selection. Unsigned instances are retained
234    /// as placement faults, never used as certificate bindings. No resolver,
235    /// hash state, signature or caller payload is accessed during this step.
236    /// <https://www.rfc-editor.org/rfc/rfc5035#section-3>
237    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            // RFC5035 §§1/2 retains mandatory V1 compatibility when SHA-1
266            // is used for certificate identification. V2 is independent, not
267            // a waiver of the companion attribute. This checks declared
268            // identities, without granting the selected provider permission
269            // to accept SHA-1 or bypassing parameter validation.
270            // https://www.rfc-editor.org/rfc/rfc5035#section-2
271            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    /// Whether any signed attributes existed, independently of ESS presence.
311    #[must_use]
312    pub fn signed_attributes_present(&self) -> bool {
313        self.signed_attributes_present
314    }
315    /// Original V1 signer/path restrictions, when written.
316    #[must_use]
317    pub fn v1(&self) -> Option<&SigningCertificate<'a>> {
318        self.v1.as_ref()
319    }
320    /// Independently evaluated original V2 signer/path restrictions.
321    #[must_use]
322    pub fn v2(&self) -> Option<&SigningCertificate<'a>> {
323        self.v2.as_ref()
324    }
325    /// Placement and identical-repetition diagnostics; nested schema faults
326    /// remain with each [`SigningCertificate::faults`] collection.
327    #[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    /// Reads the original value with inherited depth/local and aggregate work.
432    ///
433    /// The first identifier must be readable to name the signer. Later malformed
434    /// identifiers/policies remain original restrictions plus retained faults;
435    /// no resource failure becomes a readable fault or an omitted restriction.
436    /// This reading establishes neither certificate hash agreement nor trust.
437    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    /// Which independently evaluated attribute selected this value.
507    #[must_use]
508    pub fn version(&self) -> Version {
509        self.version
510    }
511    /// First signer identity and all subsequent signed restrictions in order.
512    #[must_use]
513    pub fn certificates(&self) -> &[CertificateReading<'a>] {
514        &self.certificates
515    }
516    /// Flat readable identities referenced by the original-order catalogue.
517    #[must_use]
518    pub fn identifiers(&self) -> &[CertificateId<'a>] {
519        &self.identifiers
520    }
521    /// The required first certificate identity, without a repeated lookup.
522    #[must_use]
523    pub fn signer(&self) -> &CertificateId<'a> {
524        // read() refuses an unreadable/missing first identifier before
525        // exposing this value; subsequent identities never move this slot.
526        &self.identifiers[0]
527    }
528    /// Original optional policy terms, including any separately reported fault.
529    #[must_use]
530    pub fn policies(&self) -> Option<&Element<'a>> {
531        self.policies.as_ref()
532    }
533    /// Readable schema/profile faults with original source locations.
534    #[must_use]
535    pub fn faults(&self) -> &[Error] {
536        &self.faults
537    }
538    /// Original source element.
539    #[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    // RFC2634 §5.4.1 mandates SHA-1 for V1. RFC5035 §4's ASN.1 DEFAULT
558    // mandates SHA-256 for omitted V2 hashAlgorithm, not SHA-1 (the original
559    // prose's SHA-1 description is corrected by erratum2364). These have no
560    // encoded AlgorithmIdentifier, so do not fabricate DER/NULL parameters.
561    // https://www.rfc-editor.org/rfc/rfc5035#section-4
562    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        // X.690 §11.5: DER omits only the exact ASN.1 default. Written
583        // SHA-256 with NULL is not this absent-parameter default value;
584        // selected-provider SHA-2 parameter rules remain a separate step.
585        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        // Recovery is not specified by ESS. The exact bare default OID has
602        // the same one SHA-256 reading either as a malformed identifier or
603        // extra data beside the default; any other bare OID is ambiguous.
604        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    // RFC5035 §4: public-key certificates require exactly their issuer in
684    // the directoryName choice. Other readable names are retained as faults,
685    // never collapsed into a different issuer or an absent optional field.
686    // https://www.rfc-editor.org/rfc/rfc5035#section-4
687    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}