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