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;