Skip to main content

structured_pkix/
extension.rs

1//! The extensions a certificate carries, kept whether or not they are
2//! understood.
3//!
4//! An extension marked critical says that a relying party which does not
5//! understand it must not use the certificate. That is a decision about a
6//! verdict, not about whether the bytes can be read, so an unknown critical
7//! extension is reported here rather than refused: the product has to be able
8//! to say what it found and why it stopped, and a parser that refused would
9//! leave nothing to say it with.
10//!
11//! Which identifiers count as understood is not fixed by this crate alone. A
12//! scheme knows extensions of its own, and says so by implementing
13//! [`Recognizer`]. What it supplies is a set of identifiers, never code and
14//! never a place to fetch anything from.
15
16use crate::access::{DistributionPoints, InfoAccess};
17use crate::constraints::{BasicConstraints, InhibitAnyPolicy, NameConstraints, PolicyConstraints};
18use crate::error::{CallbackError, CallbackResult, Error, ErrorCode, Located, Result, gate};
19use crate::general_name::{self, GeneralName};
20use crate::identifier::{AuthorityKeyIdentifier, SubjectKeyIdentifier};
21use crate::oid;
22use crate::policy::{CertificatePolicies, PolicyMappings};
23use crate::qualified::QcStatements;
24use crate::usage::{ExtendedKeyUsage, KeyUsage};
25use structured_asn1::memory::{Memory, MemoryError, OwnedVec, Work};
26use structured_asn1::{Element, Oid, Parser, Reader, Span, Tag, universal};
27
28mod entry;
29pub use entry::{ExtensionFields, ExtensionHeader, ExtensionValue, open, read_with};
30
31/// One extension: what it is, whether it must be understood, and its value.
32#[derive(Debug, Clone, Copy)]
33pub struct Extension<'a> {
34    kind: Oid<'a>,
35    critical: bool,
36    value: &'a [u8],
37    value_span: Span,
38    span: Span,
39    /// The parser the certificate was read with, kept so every later decode
40    /// of this value is charged to that one budget: a signature accepting an
41    /// unrelated parser would let repeated decodes reset the counters and
42    /// cost many times the caller's declared limit.
43    parser: &'a Parser,
44    /// Depth of the reader that produced extnValue; lazy decoding must not
45    /// reset the certificate's aggregate depth allowance.
46    outer: u32,
47}
48
49impl<'a> Extension<'a> {
50    /// Which extension this is.
51    #[must_use]
52    pub fn kind(self) -> Oid<'a> {
53        self.kind
54    }
55
56    /// Whether a relying party that does not understand this extension must
57    /// refuse the certificate.
58    #[must_use]
59    pub fn is_critical(self) -> bool {
60        self.critical
61    }
62
63    /// The value, still encoded: the contents of the octet string the
64    /// extension wraps it in, which is a structure of its own.
65    #[must_use]
66    pub fn value(self) -> &'a [u8] {
67        self.value
68    }
69
70    /// Where the extension sits in the document.
71    #[must_use]
72    pub fn span(self) -> Span {
73        self.span
74    }
75
76    /// A reader over the value using the current execution domain and the
77    /// original parser session's cumulative ceilings, offsets and depth.
78    ///
79    /// How a scheme reads an extension of its own. Sharing the budget is what
80    /// keeps a certificate carrying a hundred extensions from costing a
81    /// hundred times what the caller allowed, and the offsets a reader made
82    /// this way reports are offsets in the whole document. The wrapped value
83    /// sits below extnValue and retains the certificate's depth allowance.
84    pub fn reader(self, execution: &Memory) -> structured_asn1::Result<Reader<'a>> {
85        // Always DER: the value lives inside the certificate, which RFC 5280
86        // section 4.1 defines in DER, whatever encoding the envelope was
87        // read in. A caller that read a BER envelope must not have its
88        // leniency reach into the certificate's own structures.
89        self.parser.read_nested_in(
90            self.value,
91            self.value_span.start,
92            structured_asn1::Encoding::Der,
93            self.outer,
94            execution,
95        )
96    }
97
98    /// Original DER value under both origin and current query ceilings.
99    ///
100    /// The query may come from another source. Original parser identity,
101    /// offsets and inherited depth are preserved from creation; allocation,
102    /// traversal and scratch also obey the current operation's local budget
103    /// and aggregate account. Previously retained storage is not transferred.
104    pub fn reader_in<'work>(self, query: &Reader<'work>) -> structured_asn1::Result<Reader<'work>>
105    where
106        'a: 'work,
107    {
108        self.parser.read_nested_query_in(
109            query,
110            self.value,
111            self.value_span.start,
112            structured_asn1::Encoding::Der,
113            self.outer,
114        )
115    }
116
117    /// The parser the certificate was read with, whose budget every decode
118    /// of this extension shares.
119    #[must_use]
120    pub fn parser(self) -> &'a Parser {
121        self.parser
122    }
123}
124
125/// The extensions of one certificate, in the order it holds them.
126#[derive(Debug)]
127pub struct Extensions<'a> {
128    items: OwnedVec<Extension<'a>>,
129}
130
131impl<'a> Extensions<'a> {
132    /// Account retaining this collection's storage. Deferred decoding may
133    /// explicitly use a different current execution domain.
134    #[must_use]
135    pub fn memory(&self) -> &Memory {
136        self.items.memory()
137    }
138
139    pub(crate) fn empty(execution: &Memory) -> Self {
140        Self {
141            items: execution.vector(),
142        }
143    }
144    /// Every extension in order, funded by this query's current execution.
145    /// The constructor allocates/clones nothing. Each metadata step is paid
146    /// before advancing; a resource failure is yielded once, then traversal
147    /// stops. Empty/exhausted catalogues perform no additional charged work.
148    /// Recognition and payload parsing must fund their own data-dependent work.
149    pub fn iter<'r, 'e, W: Work + 'e>(
150        &'r self,
151        execution: &'e W,
152    ) -> impl Iterator<Item = Result<&'r Extension<'a>>> + 'e
153    where
154        'r: 'e,
155    {
156        let mut entries = self.items.iter();
157        let mut failed = false;
158        core::iter::from_fn(move || {
159            if failed || entries.as_slice().is_empty() {
160                return None;
161            }
162            if let Err(reason) = execution.charge_work(1) {
163                failed = true;
164                // Source metadata for the refusal; the traversal has not
165                // advanced or exposed this item as a successful reading.
166                let at = entries.as_slice()[0].span.start;
167                return Some(Err(Error::resource(reason, "extensions", at)));
168            }
169            entries.next().map(Ok)
170        })
171    }
172
173    /// How many there are.
174    #[must_use]
175    pub fn len(&self) -> usize {
176        self.items.len()
177    }
178
179    /// Whether there are none.
180    #[must_use]
181    pub fn is_empty(&self) -> bool {
182        self.items.is_empty()
183    }
184
185    /// One extension by identifier. There is at most one of each: a
186    /// certificate carrying two copies is refused when it is read, because
187    /// which of them applies would have no answer.
188    pub fn get<W: Work>(&self, kind: Oid<'_>, execution: &W) -> Result<Option<&Extension<'a>>> {
189        for item in &self.items {
190            let work = item.kind.as_bytes().len().max(kind.as_bytes().len()) as u64;
191            execution
192                .charge_work(1 + work)
193                .map_err(|reason| Error::resource(reason, "extensions", item.span.start))?;
194            if item.kind == kind {
195                return Ok(Some(item));
196            }
197        }
198        Ok(None)
199    }
200
201    /// The critical extensions this run did not understand: the ones nobody
202    /// knows, and the ones this crate knows by identifier but whose values do
203    /// not parse.
204    ///
205    /// A non-empty answer is what blocks a verdict. Knowing the identifier is
206    /// not understanding the extension: a critical key usage whose value
207    /// never parsed was never understood, and filtering it out by identifier
208    /// alone would leave a validator seeing no blocker for a demand the
209    /// certificate marked as one. Extensions a `recognizer` claims are that
210    /// scheme's to decode and are taken at its word.
211    ///
212    /// The answer is returned rather than acted on, because what to do about
213    /// it belongs to the policy layer and the report has to name them. An
214    /// error is a spent budget and only that: it says this run gave up before
215    /// the question was answered, which must not be reported as a demand
216    /// nobody understood.
217    pub fn unhandled_critical<'r, E>(
218        &'r self,
219        recognizer: &impl Recognizer<Error = E>,
220        execution: &Memory,
221    ) -> CallbackResult<OwnedVec<&'r Extension<'a>>, E> {
222        let mut unhandled = execution.vector();
223        for item in self.criticals(execution) {
224            let item = item?;
225            if !self.understands(item, recognizer, execution)? {
226                unhandled
227                    .try_push(item)
228                    .map_err(|reason| Error::resource(reason, "extensions", item.span().start))?;
229            }
230        }
231        Ok(unhandled)
232    }
233
234    /// The critical extensions, in the order the certificate wrote them and
235    /// without reading any of their values.
236    ///
237    /// Separate from [`Self::understands`] because working out whether one
238    /// was understood decodes its value, and how much that value holds is a
239    /// document's to decide. A caller holding a budget charges for an entry
240    /// and then asks: the two joined into one step would decode before the
241    /// charge could refuse it, since asking for the next entry is what would
242    /// do the decoding.
243    /// Each metadata entry is admitted before testing its critical flag,
244    /// including skipped entries and a complete miss. A resource error is
245    /// yielded once, then iteration permanently ends without further charges.
246    ///
247    /// # Examples
248    /// ```no_run
249    /// use structured_asn1::memory::Memory;
250    /// use structured_pkix::{Certificate, Result};
251    /// fn has_critical(certificate: &Certificate<'_>, execution: &Memory) -> Result<bool> {
252    ///     match certificate.tbs().extensions().criticals(execution).next() {
253    ///         Some(item) => { item?; Ok(true) }
254    ///         None => Ok(false),
255    ///     }
256    /// }
257    /// ```
258    pub fn criticals<'r, 'e>(
259        &'r self,
260        execution: &'e Memory,
261    ) -> impl Iterator<Item = Result<&'r Extension<'a>>> + 'e
262    where
263        'r: 'e,
264    {
265        let mut entries = self.iter(execution);
266        core::iter::from_fn(move || {
267            for item in entries.by_ref() {
268                let item = match item {
269                    Ok(item) => item,
270                    Err(error) => return Some(Err(error)),
271                };
272                if item.critical {
273                    return Some(Ok(item));
274                }
275            }
276            None
277        })
278    }
279
280    /// Whether this run understood one extension: this crate decodes it, or
281    /// a scheme claims it and it holds one complete value.
282    ///
283    /// Knowing the identifier is not understanding the extension: a critical
284    /// key usage whose value never parsed was never understood, and taking
285    /// it by identifier alone would leave a validator seeing no blocker for
286    /// a demand the certificate marked as one.
287    pub fn understands<E>(
288        &self,
289        item: &Extension<'a>,
290        recognizer: &impl Recognizer<Error = E>,
291        execution: &Memory,
292    ) -> CallbackResult<bool, E> {
293        let work = (item.kind.as_bytes().len() as u64)
294            .checked_mul(64)
295            .ok_or_else(|| {
296                Error::resource(MemoryError::WorkExceeded, "extensions", item.span.start)
297            })?;
298        execution
299            .charge_work(work)
300            .map_err(|reason| Error::resource(reason, "extensions", item.span.start))?;
301        if is_known(item.kind) {
302            return Self::decodes(item, recognizer, execution);
303        }
304        Ok(recognizer
305            .recognizes(item.kind, execution)
306            .map_err(CallbackError::Callback)?
307            && Self::holds_one_value(item, execution)?)
308    }
309
310    /// Whether the value of an extension this crate does not decode is one
311    /// complete DER value, all the way down.
312    ///
313    /// A scheme says which identifiers are its to decode. It never sees the
314    /// bytes, so its claim cannot be a statement about them, and "the
315    /// corresponding ASN.1 DER encoded structure is the value of the octet
316    /// string extnValue" (RFC 5280 4.1.2.9) is the one thing that can be
317    /// asked here: one structure, nothing after it, and every element under
318    /// it written the way the encoding writes it. Without this a critical
319    /// demand carrying bytes that are a value of no type would clear the
320    /// gate on an identifier alone.
321    fn holds_one_value(item: &Extension<'a>, execution: &Memory) -> Result<bool> {
322        const FIELD: &str = "extensions";
323        let read = || -> Result<()> {
324            let at = |code| Error::new(code, FIELD, item.value_span.start);
325            let mut reader = item.reader(execution).field(FIELD)?;
326            let element = reader
327                .next_element()
328                .field(FIELD)?
329                .ok_or_else(|| at(ErrorCode::MissingField))?;
330            crate::name::walk_der(&reader, &element, FIELD, crate::name::Strings::Checked)?;
331            if reader.is_empty() {
332                Ok(())
333            } else {
334                Err(at(ErrorCode::TrailingData))
335            }
336        };
337        Ok(gate(read())?.is_some())
338    }
339
340    /// Whether a known extension's value actually parses. An error is a spent
341    /// budget, never a malformed value.
342    fn decodes<E>(
343        item: &Extension<'a>,
344        recognizer: &impl Recognizer<Error = E>,
345        execution: &Memory,
346    ) -> CallbackResult<bool, E> {
347        let kind = item.kind;
348        Ok(if kind == oid::BASIC_CONSTRAINTS {
349            gate(BasicConstraints::read(item, execution))?.is_some()
350        } else if kind == oid::KEY_USAGE {
351            gate(KeyUsage::read(item, execution))?.is_some()
352        } else if kind == oid::EXT_KEY_USAGE {
353            gate(ExtendedKeyUsage::read(item, execution))?.is_some()
354        } else if kind == oid::SUBJECT_ALT_NAME || kind == oid::ISSUER_ALT_NAME {
355            // The names read for the report either way; understanding also
356            // asks that every other-name type be one somebody claims.
357            match gate(general_name::read_alternative(item, execution))? {
358                Some(names) => all(names.iter(), item, execution, |name| {
359                    other_name_known(name, recognizer, execution)
360                })?,
361                None => false,
362            }
363        } else if kind == oid::SUBJECT_KEY_IDENTIFIER {
364            gate(SubjectKeyIdentifier::read(item, execution))?.is_some()
365        } else if kind == oid::AUTHORITY_KEY_IDENTIFIER {
366            // The issuer names inside are the identity the extension points
367            // at, so they answer the same other-name question.
368            match gate(AuthorityKeyIdentifier::read(item, execution))? {
369                Some(identifier) => all(identifier.issuer().iter(), item, execution, |name| {
370                    other_name_known(name, recognizer, execution)
371                })?,
372                None => false,
373            }
374        } else if kind == oid::NAME_CONSTRAINTS {
375            match gate(NameConstraints::read(item, execution))? {
376                Some(constraints) => all(
377                    constraints.permitted().iter().chain(constraints.excluded()),
378                    item,
379                    execution,
380                    |subtree| {
381                        // A constraint is understood only where a
382                        // certificate's names can be matched against it. The
383                        // X.400 and EDI forms are kept as opaque encoded
384                        // bytes, and a registered identifier has no defined
385                        // constraint-matching rule either, so a critical
386                        // constraint built on any of them was not understood
387                        // even though its structure parsed.
388                        //
389                        // An other-name is the same question asked of a
390                        // scheme, and it is the constraint question and not
391                        // the reading one: knowing what a name of that type
392                        // says is not knowing which names sit inside a
393                        // subtree of it.
394                        Ok(match subtree.base() {
395                            GeneralName::X400(_)
396                            | GeneralName::EdiParty(_)
397                            | GeneralName::RegisteredId(_) => false,
398                            GeneralName::Other { type_id, .. } => recognizer
399                                .recognizes_name_constraint(*type_id, execution)
400                                .map_err(CallbackError::Callback)?,
401                            _ => true,
402                        })
403                    },
404                )?,
405                None => false,
406            }
407        } else if kind == oid::CERTIFICATE_POLICIES {
408            // The list parsing keeps qualifiers encoded; understanding a
409            // critical policy extension includes interpreting them.
410            match gate(CertificatePolicies::read(item, execution))? {
411                Some(policies) => policies.understood(item.parser, execution)?,
412                None => false,
413            }
414        } else if kind == oid::POLICY_MAPPINGS {
415            gate(PolicyMappings::read(item, execution))?.is_some()
416        } else if kind == oid::POLICY_CONSTRAINTS {
417            gate(PolicyConstraints::read(item, execution))?.is_some()
418        } else if kind == oid::INHIBIT_ANY_POLICY {
419            gate(InhibitAnyPolicy::read(item, execution))?.is_some()
420        } else if kind == oid::AUTHORITY_INFO_ACCESS || kind == oid::SUBJECT_INFO_ACCESS {
421            // A description's meaning is its method identifier, and a known
422            // method does not vouch for its location: an other-name there
423            // whose type nobody claims is a location this run never
424            // interpreted, and a form outside the ones the method names is
425            // an endpoint it cannot use. Either way the accessor still
426            // reports it.
427            match gate(InfoAccess::read(item, execution))? {
428                Some(access) => all(
429                    access.descriptions().iter(),
430                    item,
431                    execution,
432                    |description| {
433                        let method = description.method();
434                        // Each extension defines its own methods: OCSP and the
435                        // issuing certificates on the authority side (RFC 5280
436                        // 4.2.2.1), the repository and the time-stamping service
437                        // on the subject side (RFC 5280 4.2.2.2). A method
438                        // carried by the other extension has no defined meaning
439                        // there and was not understood.
440                        let named = if kind == oid::AUTHORITY_INFO_ACCESS {
441                            [oid::OCSP, oid::CA_ISSUERS].contains(&method)
442                        } else {
443                            [oid::TIME_STAMPING_ACCESS, oid::CA_REPOSITORY].contains(&method)
444                        };
445                        Ok((named
446                            || recognizer
447                                .recognizes_access_method(method, execution)
448                                .map_err(CallbackError::Callback)?)
449                            && other_name_known(description.location(), recognizer, execution)?
450                            && (!named || method_location_fits(method, description.location())))
451                    },
452                )?,
453                None => false,
454            }
455        } else if kind == oid::CRL_DISTRIBUTION_POINTS || kind == oid::FRESHEST_CRL {
456            // A point's names say where the revocation evidence is, and the
457            // issuer names who signs it: both answer the other-name question.
458            match gate(DistributionPoints::read(item, execution))? {
459                Some(points) => all(points.points().iter(), item, execution, |point| {
460                    all(
461                        point.full_name().iter().chain(point.issuer()),
462                        item,
463                        execution,
464                        |name| other_name_known(name, recognizer, execution),
465                    )
466                })?,
467                None => false,
468            }
469        } else if kind == oid::OCSP_NO_CHECK {
470            gate(crate::ocsp::read_no_check(item, execution))?.is_some()
471        } else if kind == oid::QC_STATEMENTS {
472            // The outer list parsing is not understanding: the statement
473            // payloads decode lazily, and a critical list whose statement
474            // carries garbage, or whose identifier nobody here knows, is a
475            // critical demand this run never understood, one level down from
476            // an unknown extension.
477            match gate(QcStatements::read(item, execution))? {
478                Some(statements) => statements.understood(recognizer, execution)?,
479                None => false,
480            }
481        } else {
482            // is_known and this list name the same identifiers; a mismatch is
483            // a bug, and claiming the value parsed would hide it.
484            false
485        })
486    }
487}
488
489/// Generates one typed accessor per extension: absent when the list does not
490/// carry the identifier, otherwise whatever the reader makes of the value.
491/// The table is the single place an accessor name, its identifier and its
492/// reader meet, so the three cannot drift apart.
493macro_rules! typed_accessors {
494    ($($(#[$doc:meta])* $name:ident, $oid:path => $reader:path, $result:ty;)+) => {
495        $(
496            $(#[$doc])*
497            pub fn $name(&self, execution: &Memory) -> Result<Option<$result>> {
498                match self.get($oid, execution)? {
499                    Some(item) => $reader(item, execution).map(Some),
500                    None => Ok(None),
501                }
502            }
503        )+
504    };
505}
506
507/// The extensions this crate reads into structures of their own.
508///
509/// Each is read when it is asked for rather than when the certificate is,
510/// because an extension that cannot be read is not a certificate that cannot
511/// be read. Lookup and decoding use the caller's current execution domain;
512/// the original parser's cumulative local ceilings still apply.
513impl<'a> Extensions<'a> {
514    /// Reads one original Extensions SEQUENCE with the certificate catalogue
515    /// invariants: nonempty, no duplicate OIDs, primitive extnValue, and the
516    /// producing encoding's DEFAULT rules. This does not recognize/trust values.
517    pub fn read_element(
518        parent: &Reader<'a>,
519        element: &Element<'a>,
520        field: &'static str,
521    ) -> Result<Self> {
522        read(parent, element, field)
523    }
524
525    /// Reads `[number] IMPLICIT Extensions` without changing original bytes.
526    /// The number is selected by the enclosing schema (RFC3161 §§2.4.1–2.4.2).
527    /// This strict catalogue is suitable for requests, not `TSTInfo` inspection
528    /// recovery; use [`read_with`] there before deciding duplicate/fault policy.
529    /// Original source/depth and producing local/current aggregate work survive.
530    /// <https://www.rfc-editor.org/rfc/rfc3161#section-2.4.1>
531    pub fn read_implicit(
532        parent: &Reader<'a>,
533        element: &Element<'a>,
534        number: u32,
535        field: &'static str,
536    ) -> Result<Self> {
537        read_tagged(parent, element, Tag::context(true, number), field)
538    }
539
540    typed_accessors! {
541        /// Whether this is a certification authority, and how deep a path
542        /// below it may go.
543        basic_constraints, oid::BASIC_CONSTRAINTS => BasicConstraints::read, BasicConstraints;
544        /// What the key may be used for.
545        key_usage, oid::KEY_USAGE => KeyUsage::read, KeyUsage<'a>;
546        /// The further purposes the key is named for.
547        extended_key_usage, oid::EXT_KEY_USAGE => ExtendedKeyUsage::read, ExtendedKeyUsage<'a>;
548        /// The further names for the subject.
549        subject_alt_name, oid::SUBJECT_ALT_NAME => general_name::read_alternative, OwnedVec<GeneralName<'a>>;
550        /// The further names for the issuer.
551        issuer_alt_name, oid::ISSUER_ALT_NAME => general_name::read_alternative, OwnedVec<GeneralName<'a>>;
552        /// The identifier for the key this certificate carries.
553        subject_key_identifier, oid::SUBJECT_KEY_IDENTIFIER => SubjectKeyIdentifier::read, SubjectKeyIdentifier<'a>;
554        /// The identifier for the key that signed it.
555        authority_key_identifier, oid::AUTHORITY_KEY_IDENTIFIER => AuthorityKeyIdentifier::read, AuthorityKeyIdentifier<'a>;
556        /// The name space this authority may certify within.
557        name_constraints, oid::NAME_CONSTRAINTS => NameConstraints::read, NameConstraints<'a>;
558        /// The policies the certificate was issued under.
559        certificate_policies, oid::CERTIFICATE_POLICIES => CertificatePolicies::read, CertificatePolicies<'a>;
560        /// The policies of one domain treated as equivalent to another's.
561        policy_mappings, oid::POLICY_MAPPINGS => PolicyMappings::read, PolicyMappings<'a>;
562        /// The limits on policy processing below this certificate.
563        policy_constraints, oid::POLICY_CONSTRAINTS => PolicyConstraints::read, PolicyConstraints;
564        /// After how many certificates the identifier standing for any policy
565        /// stops being accepted.
566        inhibit_any_policy, oid::INHIBIT_ANY_POLICY => InhibitAnyPolicy::read, InhibitAnyPolicy;
567        /// Where the issuer's certificate and status service are published.
568        authority_info_access, oid::AUTHORITY_INFO_ACCESS => InfoAccess::read, InfoAccess<'a>;
569        /// Where services belonging to the subject are published.
570        subject_info_access, oid::SUBJECT_INFO_ACCESS => InfoAccess::read, InfoAccess<'a>;
571        /// Where revocation lists covering this certificate are published.
572        crl_distribution_points, oid::CRL_DISTRIBUTION_POINTS => DistributionPoints::read, DistributionPoints<'a>;
573        /// Where the delta revocation list is published.
574        freshest_crl, oid::FRESHEST_CRL => DistributionPoints::read, DistributionPoints<'a>;
575        /// What the issuer claims about this being a qualified certificate.
576        qc_statements, oid::QC_STATEMENTS => QcStatements::read, QcStatements<'a>;
577    }
578}
579
580/// Whether a name is not an other-name, or is one whose type identifier a
581/// scheme claims. An other-name's value means what its type says, this crate
582/// names no such types itself, and a critical name extension carrying one
583/// nobody claims was not understood.
584/// Whether a location takes a form its access method names (RFC 5280
585/// 4.2.2.1 and 4.2.2.2): the status responder is reached by a URI; the
586/// issuing certificates and the repository publish over transfer protocols,
587/// a URI, or the directory, a directory name, and a mailbox names no
588/// publication location for them; the timestamping service adds the mailbox,
589/// host and address forms. A method a recognizer claims keeps its own forms.
590fn method_location_fits(method: Oid<'_>, location: &GeneralName<'_>) -> bool {
591    if method == oid::OCSP {
592        matches!(location, GeneralName::Uri(_))
593    } else if method == oid::CA_ISSUERS || method == oid::CA_REPOSITORY {
594        matches!(location, GeneralName::Uri(_) | GeneralName::Directory(_))
595    } else if method == oid::TIME_STAMPING_ACCESS {
596        matches!(
597            location,
598            GeneralName::Uri(_)
599                | GeneralName::Email(_)
600                | GeneralName::Dns(_)
601                | GeneralName::IpAddress(_)
602        )
603    } else {
604        true
605    }
606}
607
608pub(crate) fn other_name_known<E>(
609    name: &GeneralName<'_>,
610    recognizer: &impl Recognizer<Error = E>,
611    execution: &Memory,
612) -> CallbackResult<bool, E> {
613    match name {
614        GeneralName::Other { type_id, .. } => recognizer
615            .recognizes_other_name(*type_id, execution)
616            .map_err(CallbackError::Callback),
617        _ => Ok(true),
618    }
619}
620
621fn all<T, E>(
622    values: impl Iterator<Item = T>,
623    item: &Extension<'_>,
624    execution: &Memory,
625    mut understood: impl FnMut(T) -> CallbackResult<bool, E>,
626) -> CallbackResult<bool, E> {
627    for value in values {
628        execution
629            .charge_work(1)
630            .map_err(|reason| Error::resource(reason, "extensions", item.span.start))?;
631        if !understood(value)? {
632            return Ok(false);
633        }
634    }
635    Ok(true)
636}
637
638/// The identifiers a scheme understands, answered by the role an identifier
639/// plays: claiming an extension says nothing about interpreting an
640/// other-name or an access method that reuses the same identifier.
641///
642/// Data, not behaviour: an implementation answers whether an identifier is one
643/// it knows. It cannot decode anything, and nothing here gives it a way to
644/// reach the network. Each role defaults to no, the direction that blocks
645/// rather than vouches.
646pub trait Recognizer {
647    /// The original policy, provider or resource error of this implementation.
648    type Error;
649
650    /// Whether this scheme understands the extension.
651    fn recognizes(
652        &self,
653        kind: Oid<'_>,
654        execution: &Memory,
655    ) -> core::result::Result<bool, Self::Error>;
656
657    /// Whether this scheme can interpret an other-name of this type.
658    fn recognizes_other_name(
659        &self,
660        _type_id: Oid<'_>,
661        _execution: &Memory,
662    ) -> core::result::Result<bool, Self::Error> {
663        Ok(false)
664    }
665
666    /// Whether this scheme enforces a name constraint written over an
667    /// other-name of this type.
668    ///
669    /// A different question from reading one. Reading asks what a name of
670    /// this type says; a constraint asks whether a certificate's names fall
671    /// inside a subtree of it, which needs a containment rule the type's
672    /// reader never states. A scheme that reads the type and has no such
673    /// rule leaves the constraint enforced by nobody, so this role is
674    /// answered separately and defaults to no.
675    fn recognizes_name_constraint(
676        &self,
677        _type_id: Oid<'_>,
678        _execution: &Memory,
679    ) -> core::result::Result<bool, Self::Error> {
680        Ok(false)
681    }
682
683    /// Whether this scheme understands an information-access method, its
684    /// location forms included.
685    fn recognizes_access_method(
686        &self,
687        _method: Oid<'_>,
688        _execution: &Memory,
689    ) -> core::result::Result<bool, Self::Error> {
690        Ok(false)
691    }
692
693    /// Whether this scheme can interpret a qualified statement of this kind:
694    /// a national statement is knowledge a scheme carries, not this crate.
695    fn recognizes_statement(
696        &self,
697        _kind: Oid<'_>,
698        _execution: &Memory,
699    ) -> core::result::Result<bool, Self::Error> {
700        Ok(false)
701    }
702}
703
704/// Nothing beyond what this crate itself understands.
705impl Recognizer for () {
706    type Error = core::convert::Infallible;
707    fn recognizes(
708        &self,
709        _kind: Oid<'_>,
710        _execution: &Memory,
711    ) -> core::result::Result<bool, Self::Error> {
712        Ok(false)
713    }
714}
715
716impl Recognizer for [Oid<'_>] {
717    type Error = MemoryError;
718    fn recognizes(
719        &self,
720        kind: Oid<'_>,
721        execution: &Memory,
722    ) -> core::result::Result<bool, Self::Error> {
723        for candidate in self {
724            execution
725                .charge_work(1 + candidate.as_bytes().len().max(kind.as_bytes().len()) as u64)?;
726            if *candidate == kind {
727                return Ok(true);
728            }
729        }
730        Ok(false)
731    }
732}
733
734/// A scheme reached by reference answers exactly as it does directly.
735///
736/// Every role of the trait is forwarded, and a new role must be added here
737/// too: each default answers no, so a role left behind silently drops the
738/// scheme's knowledge for callers holding it behind a reference, which is
739/// how a generic wrapper and a `&dyn Recognizer` both arrive.
740impl<T: Recognizer + ?Sized> Recognizer for &T {
741    type Error = T::Error;
742    fn recognizes(
743        &self,
744        kind: Oid<'_>,
745        execution: &Memory,
746    ) -> core::result::Result<bool, Self::Error> {
747        (*self).recognizes(kind, execution)
748    }
749
750    fn recognizes_other_name(
751        &self,
752        type_id: Oid<'_>,
753        execution: &Memory,
754    ) -> core::result::Result<bool, Self::Error> {
755        (*self).recognizes_other_name(type_id, execution)
756    }
757
758    fn recognizes_name_constraint(
759        &self,
760        type_id: Oid<'_>,
761        execution: &Memory,
762    ) -> core::result::Result<bool, Self::Error> {
763        (*self).recognizes_name_constraint(type_id, execution)
764    }
765
766    fn recognizes_access_method(
767        &self,
768        method: Oid<'_>,
769        execution: &Memory,
770    ) -> core::result::Result<bool, Self::Error> {
771        (*self).recognizes_access_method(method, execution)
772    }
773
774    fn recognizes_statement(
775        &self,
776        kind: Oid<'_>,
777        execution: &Memory,
778    ) -> core::result::Result<bool, Self::Error> {
779        (*self).recognizes_statement(kind, execution)
780    }
781}
782
783/// Whether this crate reads the extension into a structure of its own.
784#[must_use]
785pub fn is_known(kind: Oid<'_>) -> bool {
786    [
787        oid::BASIC_CONSTRAINTS,
788        oid::KEY_USAGE,
789        oid::EXT_KEY_USAGE,
790        oid::SUBJECT_ALT_NAME,
791        oid::ISSUER_ALT_NAME,
792        oid::SUBJECT_KEY_IDENTIFIER,
793        oid::AUTHORITY_KEY_IDENTIFIER,
794        oid::NAME_CONSTRAINTS,
795        oid::CERTIFICATE_POLICIES,
796        oid::POLICY_MAPPINGS,
797        oid::POLICY_CONSTRAINTS,
798        oid::INHIBIT_ANY_POLICY,
799        oid::AUTHORITY_INFO_ACCESS,
800        oid::SUBJECT_INFO_ACCESS,
801        oid::CRL_DISTRIBUTION_POINTS,
802        oid::FRESHEST_CRL,
803        oid::QC_STATEMENTS,
804        oid::OCSP_NO_CHECK,
805    ]
806    .contains(&kind)
807}
808
809/// A reader over the members of the one sequence an extension's value holds,
810/// which is the shape of most of them.
811pub(crate) fn sequence<'a>(
812    extension: &Extension<'a>,
813    field: &'static str,
814    execution: &Memory,
815) -> Result<Reader<'a>> {
816    sequence_reader(
817        extension.reader(execution).field(field)?,
818        field,
819        extension.span().start,
820    )
821}
822
823pub(crate) fn sequence_reader<'a>(
824    mut reader: Reader<'a>,
825    field: &'static str,
826    at: u64,
827) -> Result<Reader<'a>> {
828    let fail = |code| Error::new(code, field, at);
829    let element = reader
830        .next_element()
831        .field(field)?
832        .ok_or_else(|| fail(ErrorCode::MissingField))?;
833    if element.tag() != Tag::constructed(universal::SEQUENCE) {
834        return Err(fail(ErrorCode::Encoding(
835            structured_asn1::ErrorCode::UnexpectedTag,
836        )));
837    }
838    // A value holding a second structure after the first is two answers to
839    // what the extension says.
840    if !reader.is_empty() {
841        return Err(fail(ErrorCode::TrailingData));
842    }
843
844    reader.enter(&element).field(field)
845}
846
847/// The number and construction of a context-specific tag, and `None` for a
848/// tag of any other class.
849///
850/// The fields these schemas tag by position are context-specific, and a match
851/// on number and construction alone would read an APPLICATION or PRIVATE tag
852/// with the same number as the field it is not.
853pub(crate) fn context_of(tag: Tag) -> Option<(u32, bool)> {
854    // A number this reader does not name is not a field any schema wrote.
855    (tag.class() == structured_asn1::Class::ContextSpecific)
856        .then(|| tag.number().map(|number| (number, tag.is_constructed())))
857        .flatten()
858}
859
860/// Reads the extensions from the element the schema wraps them in. The
861/// parent reader's parser is kept with each extension, so every later decode
862/// of its value is charged to the budget the certificate was read with, and
863/// no other parser can be handed in beside the reader.
864pub(crate) fn read<'a>(
865    parent: &Reader<'a>,
866    element: &Element<'a>,
867    field: &'static str,
868) -> Result<Extensions<'a>> {
869    read_tagged(
870        parent,
871        element,
872        Tag::constructed(universal::SEQUENCE),
873        field,
874    )
875}
876
877fn read_tagged<'a>(
878    parent: &Reader<'a>,
879    element: &Element<'a>,
880    expected: Tag,
881    field: &'static str,
882) -> Result<Extensions<'a>> {
883    let parser = parent.parser();
884    let fail = |code| Error::new(code, field, element.span().start);
885
886    if element.tag() != expected {
887        return Err(fail(ErrorCode::Encoding(
888            structured_asn1::ErrorCode::UnexpectedTag,
889        )));
890    }
891
892    let mut sequence = parent.enter(element).field(field)?;
893    let mut items = parent.execution().vector();
894    // A set rather than a scan of what came before: a certificate can carry
895    // tens of thousands of extensions within the parse budget, and a per-item
896    // scan of the list would be quadratic work the budget never sees.
897    let mut kinds = parent.execution().map::<Oid<'a>, ()>();
898
899    while let Some(entry) = sequence.next_element().field(field)? {
900        let at = |code| Error::new(code, field, entry.span().start);
901
902        let fields = open(&sequence, &entry, field)?;
903        if fields.header().default_written() && fields.reader().encoding().is_der() {
904            let at = fields
905                .header()
906                .critical_span()
907                .expect("written flag has a span")
908                .start;
909            return Err(Error::new(ErrorCode::MalformedValue, field, at));
910        }
911        let decoded = fields
912            .read_with(|_header, inside, value| {
913                // RFC5280 §4.1 / X.690 §11.5: the strict certificate profile
914                // keeps its primitive-value and DER-default invariants. TSP
915                // inspection can instead retain the common structural metadata.
916                // https://www.rfc-editor.org/rfc/rfc5280#section-4.1
917                if value.tag() != Tag::primitive(universal::OCTET_STRING) {
918                    return Err(Error::new(
919                        ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
920                        field,
921                        value.span().start,
922                    ));
923                }
924                if !inside.is_empty() {
925                    return Err(at(ErrorCode::TrailingData));
926                }
927                Ok((value.contents(), value.contents_span(), inside.depth()))
928            })
929            .map_err(|error| match error {
930                CallbackError::Processing(error) | CallbackError::Callback(error) => error,
931            })?;
932        let header = decoded.header();
933        let kind = header.kind();
934        let critical = header.is_critical();
935        let (value, value_span, outer) = decoded.into_value();
936
937        // Two copies of one extension leave no answer to which applies, and a
938        // reader that took the first would disagree with one that took the
939        // last about what the certificate says.
940        if kinds
941            .try_insert(kind, ())
942            .map_err(|reason| Error::resource(reason, field, entry.span().start))?
943            .is_some()
944        {
945            return Err(at(ErrorCode::DuplicateExtension));
946        }
947
948        items
949            .try_push(Extension {
950                kind,
951                critical,
952                value,
953                value_span,
954                span: entry.span(),
955                parser,
956                outer,
957            })
958            .map_err(|reason| Error::resource(reason, field, entry.span().start))?;
959    }
960
961    // The schema requires at least one, and an empty sequence is a structure
962    // that says nothing while claiming to.
963    if items.is_empty() {
964        return Err(fail(ErrorCode::EmptySequence));
965    }
966
967    Ok(Extensions {
968        items: items.into_owned(),
969    })
970}
971
972#[cfg(test)]
973mod tests;