Skip to main content

structured_pkix/
name.rs

1//! Distinguished names, kept as they were encoded.
2//!
3//! A name has two jobs here and they pull in opposite directions. One is
4//! identity: an issuer name in one certificate has to be recognized as the
5//! subject name of another, or no path is ever built. The other is
6//! explanation: somebody has to read who this is.
7//!
8//! They are kept apart. Identity is the bytes, and the comparison below is the
9//! profile's rule over the encoded values. Explanation is [`Attribute::text`],
10//! which decodes for a person to read and is never what two names are compared
11//! on. A parser that folded the two would let a name that renders identically
12//! stand in for the one it imitates.
13
14use crate::error::{Error, ErrorCode, Located, Result};
15use crate::oid;
16#[cfg(test)]
17use alloc::vec::Vec;
18use structured_asn1::memory::{Memory, OwnedString, OwnedVec};
19use structured_asn1::{Class, Element, Oid, Reader, Tag, universal};
20use unicode_bidi::BidiClass;
21
22mod fold;
23mod normalize;
24mod prepared;
25mod render;
26pub(crate) mod segments;
27mod selector;
28pub use selector::Selector;
29mod unassigned;
30
31/// A distinguished name, as the sequence of parts the certificate holds.
32#[derive(Debug)]
33pub struct Name<'a> {
34    der: &'a [u8],
35    parts: OwnedVec<RelativeName<'a>>,
36    offset: u64,
37    field: &'static str,
38}
39
40/// One part of a name: usually one attribute, occasionally several that are
41/// unordered among themselves.
42#[derive(Debug)]
43pub struct RelativeName<'a> {
44    attributes: OwnedVec<Attribute<'a>>,
45}
46
47/// One attribute of a name: what kind of thing it is, and the value.
48#[derive(Debug, Clone, Copy)]
49pub struct Attribute<'a> {
50    kind: Oid<'a>,
51    value: AttributeValue<'a>,
52}
53
54/// The value of an attribute, as it was encoded.
55#[derive(Debug, Clone, Copy)]
56pub struct AttributeValue<'a> {
57    tag: Tag,
58    contents: &'a [u8],
59    der: &'a [u8],
60    offset: u64,
61}
62
63/// Which string encoding a value was written in, where it is a string at all.
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65#[non_exhaustive]
66pub enum Encoding {
67    /// `UTF8String`.
68    Utf8,
69    /// `PrintableString`, a restricted set of ASCII.
70    Printable,
71    /// `IA5String`, ASCII.
72    Ia5,
73    /// `VisibleString`, printable ASCII.
74    Visible,
75    /// `NumericString`, digits and spaces.
76    Numeric,
77    /// `TeletexString`, from before the others, and read here as an
78    /// approximation.
79    Teletex,
80    /// `BMPString`, sixteen bits a character.
81    Bmp,
82    /// `UniversalString`, thirty-two bits a character.
83    Universal,
84    /// Not a string type this crate reads as text.
85    Other,
86}
87
88impl<'a> Name<'a> {
89    /// The name exactly as it was encoded, which is what identity is.
90    #[must_use]
91    pub fn as_bytes(&self) -> &'a [u8] {
92        self.der
93    }
94
95    /// The parts, outermost first, as the certificate wrote them.
96    #[must_use]
97    pub fn parts(&self) -> &[RelativeName<'a>] {
98        &self.parts
99    }
100
101    /// Whether the name has no parts at all, which a certificate is allowed to
102    /// do when the subject is named somewhere else instead.
103    #[must_use]
104    pub fn is_empty(&self) -> bool {
105        self.parts.is_empty()
106    }
107
108    /// Copies descriptors into the current domain; document bytes remain borrowed.
109    ///
110    /// # Errors
111    /// Returns a located resource error before unfunded copying or allocation.
112    pub fn try_copy(&self, execution: &Memory) -> Result<Self> {
113        let mut parts = execution.vector();
114        for part in &self.parts {
115            execution
116                .charge_work(1)
117                .map_err(|reason| Error::resource(reason, self.field, self.offset))?;
118            parts
119                .try_push(part.try_copy(execution)?)
120                .map_err(|reason| Error::resource(reason, self.field, self.offset))?;
121        }
122        Ok(Self {
123            der: self.der,
124            parts,
125            offset: self.offset,
126            field: self.field,
127        })
128    }
129
130    /// Every attribute, in the order the name holds them.
131    /// The caller admits its own traversal of this borrowed view.
132    pub fn attributes(&self) -> impl Iterator<Item = &Attribute<'a>> {
133        self.parts.iter().flat_map(RelativeName::attributes)
134    }
135
136    /// The attributes of one kind, in order. Several is not an error: a name
137    /// can carry more than one organizational unit, and which one matters is
138    /// not this layer's decision.
139    /// Each search step is admitted in the current execution domain. A refusal
140    /// is yielded once, after which repeated `next()` calls do no further work.
141    /// Returned references borrow the name, independently of the budget borrow.
142    pub fn attributes_of<'n, 'q>(
143        &'n self,
144        kind: Oid<'q>,
145        execution: &'q Memory,
146    ) -> impl Iterator<Item = Result<&'n Attribute<'a>>> + 'q
147    where
148        'n: 'q,
149    {
150        let mut attributes = self.attributes();
151        let mut failed = false;
152        core::iter::from_fn(move || {
153            if failed {
154                return None;
155            }
156            for attribute in attributes.by_ref() {
157                let work = 1 + attribute.kind.as_bytes().len().max(kind.as_bytes().len()) as u64;
158                if let Err(reason) = execution.charge_work(work) {
159                    failed = true;
160                    return Some(Err(self.resource(reason)));
161                }
162                if attribute.kind == kind {
163                    return Some(Ok(attribute));
164                }
165            }
166            None
167        })
168    }
169
170    /// The first attribute of one kind.
171    pub fn attribute(&self, kind: Oid<'_>, execution: &Memory) -> Result<Option<&Attribute<'a>>> {
172        self.attributes_of(kind, execution).next().transpose()
173    }
174
175    /// The common name, which describes the subject and does not identify it.
176    pub fn common_name(&self, execution: &Memory) -> Result<Option<&Attribute<'a>>> {
177        self.attribute(oid::COMMON_NAME, execution)
178    }
179
180    /// The organization identifier, which is how a legal entity is identified
181    /// rather than described, and is the attribute an attribution decision may
182    /// rest on where the common name is not.
183    pub fn organization_identifier(&self, execution: &Memory) -> Result<Option<&Attribute<'a>>> {
184        self.attribute(oid::ORGANIZATION_IDENTIFIER, execution)
185    }
186
187    /// Whether two names are the same name, by the profile's rule: the same
188    /// parts in the same order, each holding the same attributes, with strings
189    /// compared under their declared equality rule.
190    ///
191    /// Directory strings are compared after the preparation the profile requires
192    /// (RFC 5280 7.1, over RFC 4518): the characters that carry no meaning
193    /// are dropped, case is folded in full, the value is normalized to form
194    /// KC, and runs of space count as one between words and none at the
195    /// edges. Unsupported types and nonconforming stored values retain their
196    /// encoded identity; that preservation does not validate an LDAP assertion.
197    /// Valid supported values use the schema's size bounds and the current
198    /// work/storage budget, independently of display truncation.
199    /// IA5 emailAddress and domainComponent values instead use their exact
200    /// ASCII case-insensitive rules without whitespace compression; the DN
201    /// emailAddress rule covers the whole value, unlike rfc822Name mailboxes.
202    /// Pseudonym uses caseExactMatch (RFC2985 §5.2.9): the same preparation
203    /// and insignificant-space handling, with case preserved.
204    ///
205    /// # Errors
206    /// Returns a located resource error before unfunded comparison work.
207    pub fn matches(&self, other: &Name<'_>, execution: &Memory) -> Result<bool> {
208        if self.parts.len() != other.parts.len() {
209            return Ok(false);
210        }
211        // Identical original encodings have the same retained wire identity.
212        // This fast path does not validate a nonconforming stored value.
213        if self.der.len() == other.der.len() {
214            execution
215                .charge_work(self.der.len() as u64)
216                .map_err(|reason| self.resource(reason))?;
217            if self.der == other.der {
218                return Ok(true);
219            }
220        }
221        Ok(self.order(other, execution)? == core::cmp::Ordering::Equal)
222    }
223
224    pub(crate) fn resource(&self, reason: structured_asn1::memory::MemoryError) -> Error {
225        Error::resource(reason, self.field, self.offset)
226    }
227
228    /// A total order over names that calls two of them equal exactly when
229    /// [`Name::matches`] does.
230    ///
231    /// It exists so that a set of names can be searched rather than walked. A
232    /// caller holding many certificates and asking which one a name belongs to
233    /// otherwise compares against every one of them, and comparing names is
234    /// where the profile's folding lives; ordering them once turns that into a
235    /// search. Answering the same question two ways is only safe because this
236    /// is the same comparison: it is built from the ordering the multiset
237    /// matching already uses, not from a second reading of what identity is.
238    ///
239    /// Preparation and comparison use the current execution domain. Unicode
240    /// scratch storage is released when this comparison returns.
241    ///
242    /// # Errors
243    /// Returns a located resource error before unfunded preparation or comparison.
244    pub fn order(&self, other: &Name<'_>, execution: &Memory) -> Result<core::cmp::Ordering> {
245        let order = self.parts.len().cmp(&other.parts.len());
246        if order != core::cmp::Ordering::Equal {
247            return Ok(order);
248        }
249        // Stop at the first distinguishing RDN: unrelated tail values must
250        // not pay for normalization or scratch storage that cannot affect order.
251        for (left, right) in self.parts.iter().zip(&other.parts) {
252            execution
253                .charge_work(1)
254                .map_err(|reason| Error::resource(reason, self.field, self.offset))?;
255            let order = prepared::compare_parts(left, right, execution)?;
256            if order != core::cmp::Ordering::Equal {
257                return Ok(order);
258            }
259        }
260        Ok(core::cmp::Ordering::Equal)
261    }
262
263    /// Prepares this name once for repeated comparisons.
264    ///
265    /// Encoded values remain borrowed. Sorted descriptors and any Unicode
266    /// canonical text retain their storage charge until this result is dropped.
267    /// Comparisons subsequently use the execution domain passed to them.
268    ///
269    /// # Errors
270    /// Returns a located resource error if preparation cannot be financed.
271    pub fn ordered(&self, execution: &Memory) -> Result<Ordered<'a>> {
272        Ok(Ordered {
273            prepared: prepared::PreparedName::of(&self.parts, execution)?,
274            offset: self.offset,
275        })
276    }
277
278    /// Whether this name sits below another one: the parts of the other, in
279    /// order, from the top down, and anything at all after them.
280    ///
281    /// This is the containment a name-constraint subtree asks about, where
282    /// the base "specifies a subtree of the X.500 directory tree" and a name
283    /// is within it when it begins with the base (RFC 5280 4.2.1.10). A base
284    /// of no parts is the root of the tree and holds every name. Parts are
285    /// compared by the rule identity uses, so a name sits below itself.
286    ///
287    /// # Errors
288    /// Returns a located resource error before unfunded prefix preparation.
289    pub fn starts_with(&self, base: &Name<'_>, execution: &Memory) -> Result<bool> {
290        if base.parts.len() > self.parts.len() {
291            return Ok(false);
292        }
293        for (left, right) in self.parts.iter().zip(&base.parts) {
294            execution
295                .charge_work(1)
296                .map_err(|reason| self.resource(reason))?;
297            let order = prepared::compare_parts(left, right, execution)?;
298            if order != core::cmp::Ordering::Equal {
299                return Ok(false);
300            }
301        }
302        Ok(true)
303    }
304}
305
306/// A prepared name with independently accounted descriptors and canonical text.
307///
308/// Encoded values borrow the source document. Storage charges survive the
309/// parser; every comparison is paid by its explicit current execution domain.
310#[derive(Debug)]
311pub struct Ordered<'a> {
312    prepared: prepared::PreparedName<'a>,
313    offset: u64,
314}
315
316impl Ordered<'_> {
317    /// The same order [`Name::order`] gives, using already prepared values.
318    ///
319    /// # Errors
320    /// Returns a located resource error before unfunded comparison work.
321    pub fn order(&self, other: &Ordered<'_>, execution: &Memory) -> Result<core::cmp::Ordering> {
322        self.prepared
323            .order(&other.prepared, execution)
324            .map_err(|reason| Error::resource(reason, "name", self.offset))
325    }
326}
327
328impl<'a> RelativeName<'a> {
329    /// The attributes of this part.
330    #[must_use]
331    pub fn attributes(&self) -> &[Attribute<'a>] {
332        &self.attributes
333    }
334
335    /// Copies borrowed descriptors into independently accounted storage.
336    ///
337    /// # Errors
338    /// Returns a located resource error before unfunded copying or allocation.
339    pub fn try_copy(&self, execution: &Memory) -> Result<Self> {
340        let mut attributes = execution.vector();
341        attributes
342            .try_extend_from_slice(&self.attributes)
343            .map_err(|reason| {
344                Error::resource(reason, "name.relative", self.attributes[0].value.offset)
345            })?;
346        Ok(Self { attributes })
347    }
348
349    /// Whether two parts hold the same attributes. They are a set, so order
350    /// within a part is not part of what they say, and the correspondence is
351    /// one to one: a part written with a duplicate does not match a part
352    /// without one.
353    ///
354    /// Both sides are ordered by a total order that agrees with attribute
355    /// equality, then compared in step. Ordering is streamed: nothing is
356    /// materialized, so a part holding a value the element limit permits, up
357    /// to four gibibytes, costs a list of references and not a copy of the
358    /// value. The alternative, one canonical key per attribute, is a copy the
359    /// size of the name; scanning one list per attribute of the other is work
360    /// proportional to the square of a count the parse budget never sees.
361    #[must_use]
362    #[cfg(test)]
363    fn matches(&self, other: &RelativeName<'_>) -> bool {
364        if self.attributes.len() != other.attributes.len() {
365            return false;
366        }
367        // One attribute is the common case, and it needs no ordering at all.
368        if let ([left], [right]) = (&self.attributes[..], &other.attributes[..]) {
369            return left.matches(right);
370        }
371        let mut ours: Vec<&Attribute<'a>> = self.attributes.iter().collect();
372        let mut theirs: Vec<&Attribute<'_>> = other.attributes.iter().collect();
373        ours.sort_unstable_by(|left, right| left.order(right));
374        theirs.sort_unstable_by(|left, right| left.order(right));
375        ours.iter()
376            .zip(&theirs)
377            .all(|(left, right)| left.matches(right))
378    }
379
380    /// A total order over parts that calls two of them equal exactly when
381    /// [`RelativeName::matches`] does, built the same way: both sides ordered
382    /// by the attribute order, then compared in step.
383    #[cfg(test)]
384    fn order(&self, other: &RelativeName<'_>) -> core::cmp::Ordering {
385        self.attributes
386            .len()
387            .cmp(&other.attributes.len())
388            .then_with(|| {
389                if let ([left], [right]) = (&self.attributes[..], &other.attributes[..]) {
390                    return left.order(right);
391                }
392                let mut ours: Vec<&Attribute<'a>> = self.attributes.iter().collect();
393                let mut theirs: Vec<&Attribute<'_>> = other.attributes.iter().collect();
394                ours.sort_unstable_by(|left, right| left.order(right));
395                theirs.sort_unstable_by(|left, right| left.order(right));
396                ours.iter()
397                    .zip(&theirs)
398                    .map(|(left, right)| left.order(right))
399                    .find(|ordering| ordering.is_ne())
400                    .unwrap_or(core::cmp::Ordering::Equal)
401            })
402    }
403}
404
405/// The value syntax of an attribute type this crate names, or `None` for a
406/// kind it does not.
407fn syntax_of(kind: Oid<'_>) -> Option<Syntax> {
408    // The X.520 attributes whose value is a DirectoryString.
409    const DIRECTORY: &[Oid<'static>] = &[
410        oid::COMMON_NAME,
411        oid::SURNAME,
412        oid::LOCALITY,
413        oid::STATE_OR_PROVINCE,
414        oid::STREET_ADDRESS,
415        oid::ORGANIZATION,
416        oid::ORGANIZATIONAL_UNIT,
417        oid::TITLE,
418        oid::GIVEN_NAME,
419        oid::INITIALS,
420        oid::GENERATION_QUALIFIER,
421        oid::PSEUDONYM,
422        oid::ORGANIZATION_IDENTIFIER,
423        oid::USER_ID,
424    ];
425    if DIRECTORY.contains(&kind) {
426        Some(Syntax::Directory)
427    } else if kind == oid::COUNTRY || kind == oid::SERIAL_NUMBER || kind == oid::DN_QUALIFIER {
428        // X.520 gives these a PrintableString.
429        Some(Syntax::Printable)
430    } else if kind == oid::EMAIL_ADDRESS || kind == oid::DOMAIN_COMPONENT {
431        // And these an IA5String.
432        Some(Syntax::Ia5)
433    } else {
434        None
435    }
436}
437
438/// The value syntaxes the named attribute types take.
439#[derive(Clone, Copy)]
440enum Syntax {
441    /// The `DirectoryString` choice of X.520.
442    Directory,
443    /// A `PrintableString`.
444    Printable,
445    /// An `IA5String`.
446    Ia5,
447}
448
449impl Syntax {
450    fn permits(self, encoding: Encoding) -> bool {
451        match self {
452            Self::Directory => matches!(
453                encoding,
454                Encoding::Utf8
455                    | Encoding::Printable
456                    | Encoding::Teletex
457                    | Encoding::Bmp
458                    | Encoding::Universal
459            ),
460            Self::Printable => encoding == Encoding::Printable,
461            Self::Ia5 => encoding == Encoding::Ia5,
462        }
463    }
464}
465
466/// Whether an attribute type's schema permits folding a value in one string
467/// encoding. A value outside its type's choices takes part in identity as
468/// bytes only: text folded out of an encoding the type does not have would
469/// let a malformed value match a genuine one it never equals. And a kind
470/// this crate does not name may define case-sensitive equality, so folding
471/// under a rule the type may not have would match names that differ: its
472/// values too equal themselves and nothing else.
473fn permits(kind: Oid<'_>, encoding: Encoding) -> bool {
474    syntax_of(kind).is_some_and(|syntax| syntax.permits(encoding))
475}
476
477/// The size an attribute kind's schema puts on its value, in characters:
478/// the country is exactly two, and the rest follow the upper bounds of
479/// RFC 5280 appendix A. A kind the appendix does not bound stays unbounded.
480fn size_bounds(kind: Oid<'_>) -> (usize, usize) {
481    if kind == oid::COUNTRY {
482        (2, 2)
483    } else if kind == oid::COMMON_NAME
484        || kind == oid::ORGANIZATION
485        || kind == oid::ORGANIZATIONAL_UNIT
486        || kind == oid::TITLE
487        || kind == oid::SERIAL_NUMBER
488    {
489        (1, 64)
490    } else if kind == oid::LOCALITY || kind == oid::STATE_OR_PROVINCE {
491        (1, 128)
492    } else if kind == oid::EMAIL_ADDRESS {
493        (1, 255)
494    } else if kind == oid::PSEUDONYM {
495        (1, 128)
496    } else if kind == oid::STREET_ADDRESS {
497        // ub-street-address (X.520).
498        (1, 128)
499    } else if kind == oid::SURNAME
500        || kind == oid::GIVEN_NAME
501        || kind == oid::INITIALS
502        || kind == oid::GENERATION_QUALIFIER
503    {
504        // The name components share ub-name, 32768.
505        (1, 32768)
506    } else {
507        (1, usize::MAX)
508    }
509}
510
511/// Whether an attribute of a kind this crate names is written inside that
512/// kind's syntax: the encoding is one its type permits, the value decodes
513/// under it, and the decoded text fits the size the schema gives the kind.
514/// An unknown kind answers yes, having no schema here to hold it to; where
515/// an identity must have been read entirely, this is the question each
516/// attribute is asked.
517pub(crate) fn well_formed(attribute: &Attribute<'_>) -> bool {
518    inside_syntax(attribute, Asking::Shape, |_| true)
519}
520
521/// Schema validation of retained string bytes, admitted before scanning.
522pub(crate) fn well_formed_in(
523    attribute: &Attribute<'_>,
524    parent: &Reader<'_>,
525    field: &'static str,
526) -> Result<bool> {
527    let work = (attribute.kind.as_bytes().len() as u64)
528        .checked_mul(64)
529        .and_then(|kinds| {
530            (attribute.value.contents.len() as u64)
531                .checked_mul(2)
532                .and_then(|contents| kinds.checked_add(contents))
533        })
534        .and_then(|work| work.checked_add(1))
535        .ok_or_else(|| {
536            Error::resource(
537                structured_asn1::memory::MemoryError::WorkExceeded,
538                field,
539                attribute.value.offset,
540            )
541        })?;
542    parent.charge(work).field(field)?;
543    Ok(well_formed(attribute))
544}
545
546/// Display text may truncate at this bound. Identity preparation instead uses
547/// the schema bound and the operation's admitted work/storage: RFC5280 §7.1
548/// requires `StringPrep` for valid `UTF8String`/`PrintableString` values.
549/// A display limit must never silently substitute binary equality.
550/// <https://www.rfc-editor.org/rfc/rfc5280.html#section-7.1>
551const DISPLAY_CEILING: usize = 32_768;
552
553/// Whether the preparation can run on a value at all.
554///
555/// Unsupported encodings, malformed stored values and prohibited code points
556/// retain only their encoded identity. That preservation does not validate
557/// an LDAP assertion. Valid values have no display-derived preparation limit.
558#[cfg(test)]
559fn preparable(attribute: &Attribute<'_>) -> bool {
560    if !inside_syntax(attribute, Asking::Folding, |c| !prohibited(c)) {
561        return false;
562    }
563    // The direction step reads the value the normalizing step leaves, which
564    // is the order the profile puts them in (RFC 4518 2, steps 3 then 5).
565    // The order decides the answer: a compatibility form can expand into
566    // letters of a direction the character it replaces did not have, U+2121
567    // into TEL, so a value read before normalizing can look right-to-left
568    // and be mixed once prepared. The walk is bounded by the step above,
569    // which already held the value to the size its schema gives it.
570    let mut direction = Direction::default();
571    for c in normalized(attribute.value.decoded_chars()) {
572        direction.see(c);
573    }
574    direction.settled()
575}
576
577/// The direction step of the preparation (RFC 4518 2.5, over RFC 3454 6),
578/// read as the value is scanned.
579///
580/// A value holding a right-to-left letter may hold no left-to-right one, and
581/// must begin and end with a right-to-left one. Failing either leaves the
582/// value unprepared, which here means compared as bytes.
583///
584/// The edges are decided on the characters that are still there when the
585/// preparation ends. The step that drops the spaces at the edges is part of
586/// the same preparation and comes after this one, so holding a value to an
587/// edge its own preparation deletes would refuse it over its spacing rather
588/// than over its direction.
589///
590/// The steps before this one decide what it sees, so it reads the value as
591/// they leave it: mapped and normalized. The mapping sends a set of
592/// characters to nothing, and the direction marks are among them: a value is
593/// written right to left because of its letters, not because it carries a
594/// mark saying so, and counting a mark the preparation deletes would refuse
595/// a name over a character that is not there by the time anything compares
596/// it. Normalizing matters here too, and in the other direction: a
597/// compatibility form can expand into letters that carry a direction the
598/// character it replaces did not have, U+2121 into TEL, so a value read
599/// before that step can look settled and be mixed after it.
600#[derive(Default)]
601struct Direction {
602    /// The first character that is not a space, and whether it is
603    /// right-to-left.
604    first: Option<bool>,
605    /// The same for the last one seen so far.
606    last: bool,
607    any_right: bool,
608    any_left: bool,
609}
610
611impl Direction {
612    fn see(&mut self, c: char) {
613        if mapped_to_nothing(c) || c.is_whitespace() {
614            return;
615        }
616        let class = unicode_bidi::bidi_class(c);
617        let right = matches!(class, BidiClass::R | BidiClass::AL);
618        if self.first.is_none() {
619            self.first = Some(right);
620        }
621        self.last = right;
622        self.any_right |= right;
623        self.any_left |= class == BidiClass::L;
624    }
625
626    fn settled(&self) -> bool {
627        !self.any_right || (!self.any_left && self.first == Some(true) && self.last)
628    }
629}
630
631/// Whether the profile prohibits a code point (RFC 4518 2.4).
632///
633/// Private use, the non-characters, and the replacement character a decoder
634/// writes when it could not read something: nobody agrees what any of them
635/// says, so nothing downstream can be defined over them. None of the three
636/// is touched by the mapping or the normalization, so asking about them
637/// before those steps is asking about the same characters they ask about.
638/// Surrogates are prohibited too and cannot arrive: nothing here produces
639/// one, because a character is a scalar value.
640///
641/// The step also prohibits the deprecated code points and the ones that
642/// change display properties, and none of those can reach it. The mapping
643/// sends the display controls to nothing two steps earlier, and the
644/// normalization takes the two deprecated tone marks to the ordinary marks
645/// they are equivalent to. Testing for them here would refuse a value the
646/// profile prepares, which is a name that stops matching itself.
647///
648/// The step's table of code points unassigned in Unicode 3.2 is applied,
649/// which costs the folded comparison for a character assigned since. That is
650/// the direction to lose in. The preparation is defined over one repertoire,
651/// and every step after this one is a table this crate reaches at its
652/// current version: a character the profile never saw carries a case folding
653/// and a compatibility decomposition today, so folding one makes two names
654/// equal by a rule the profile does not contain. Refusing it leaves the two
655/// compared as bytes, which reports a path as unproven; folding it can
656/// report an issuer as a subject it is not.
657fn prohibited(c: char) -> bool {
658    let point = u32::from(c);
659    unassigned::in_unicode_3_2(c)
660        || matches!(c,
661        // Private use (RFC 3454 C.3).
662        '\u{e000}'..='\u{f8ff}' | '\u{f0000}'..='\u{ffffd}' | '\u{100000}'..='\u{10fffd}'
663        // The non-characters of the arabic presentation forms (C.4).
664        | '\u{fdd0}'..='\u{fdef}'
665        // The replacement character.
666        | '\u{fffd}')
667        // The last two code points of every plane, which are the rest of C.4.
668        || point & 0xfffe == 0xfffe
669}
670
671/// Which of the two questions about a value is being asked.
672///
673/// They differ where a value can be kept without being read. A value whose
674/// shape its schema names is not refused, and it is what the two callers of
675/// this share; whether the preparation can then run on it is a narrower
676/// question, and answering no to it costs a folded comparison rather than a
677/// certificate.
678#[derive(Clone, Copy, PartialEq, Eq)]
679enum Asking {
680    /// Whether the value is written inside its kind's syntax at all. A no
681    /// here refuses the value where an identity must have been read whole.
682    Shape,
683    /// Whether the preparation the comparison runs can run on this value.
684    /// A no here leaves it compared as bytes.
685    Folding,
686}
687
688/// The shared reading of an attribute against its kind's schema, with a
689/// further test on each character the caller supplies.
690fn inside_syntax(
691    attribute: &Attribute<'_>,
692    asking: Asking,
693    mut keep: impl FnMut(char) -> bool,
694) -> bool {
695    match syntax_of(attribute.kind) {
696        Some(syntax) => {
697            let (least, schema) = size_bounds(attribute.kind);
698            let most = schema;
699            // The ceiling is checked on the encoded bytes first: no encoding
700            // here spends fewer than one byte per character or more than
701            // four, so a value whose bytes exceed four times the character
702            // bound can never fit it. The saturation is deliberate: an
703            // unbounded kind saturates the ceiling to the type's maximum,
704            // and the streaming scan below still touches it one character
705            // at a time without materializing a copy the size of the value.
706            if attribute.value.contents().len() > most.saturating_mul(4) {
707                return false;
708            }
709            if !syntax.permits(attribute.value.encoding()) {
710                return false;
711            }
712            // TeletexString is T.61, and its repertoire is a negotiation this
713            // crate does not implement: the bytes being there and inside the
714            // size the schema gives the kind is what is checkable. Asking it
715            // to decode as anything would call a legacy value malformed, and
716            // where a name must be written inside its syntax that refuses a
717            // certificate over an encoding the schema names. It is counted
718            // in bytes here and not folded at all, which is the other half
719            // of the same answer: a value nobody has agreed how to read
720            // takes part in identity as its bytes.
721            if attribute.value.encoding() == Encoding::Teletex && asking == Asking::Shape {
722                return (least..=most).contains(&attribute.value.contents().len());
723            }
724            let country = attribute.kind == oid::COUNTRY;
725            attribute
726                .value
727                // The country is a two-letter ISO 3166 code: digits and
728                // punctuation fit the printable repertoire and the size
729                // without naming any country. Case is left to folding.
730                .validated_count(|c| (!country || c.is_ascii_alphabetic()) && keep(c))
731                .is_some_and(|count| (least..=most).contains(&count))
732        }
733        None => true,
734    }
735}
736
737/// Whether the preparation this comparison runs sends a character to nothing.
738///
739/// The Map step of the string preparation the profile requires (RFC 5280 7.1,
740/// which requires RFC 4518) sends soft hyphen, the grapheme joiner, the
741/// variation selectors, the object replacement character, the zero width
742/// space and "all other control code (e.g., Cc) points or code points with a
743/// control function (e.g., Cf)" to nothing. The list below is the one that
744/// section writes out. What it does NOT contain is tab, line feed, vertical
745/// tab, form feed, carriage return and next line: those are mapped to SPACE,
746/// which is why the whitespace fold beside this covers them.
747fn mapped_to_nothing(c: char) -> bool {
748    matches!(
749        c,
750        '\u{00ad}'
751            | '\u{1806}'
752            | '\u{034f}'
753            | '\u{180b}'..='\u{180d}'
754            | '\u{fe00}'..='\u{fe0f}'
755            | '\u{fffc}'
756            | '\u{0000}'..='\u{0008}'
757            | '\u{000e}'..='\u{001f}'
758            | '\u{007f}'..='\u{0084}'
759            | '\u{0086}'..='\u{009f}'
760            | '\u{06dd}'
761            | '\u{070f}'
762            | '\u{180e}'
763            | '\u{200b}'..='\u{200f}'
764            | '\u{202a}'..='\u{202e}'
765            | '\u{2060}'..='\u{2063}'
766            | '\u{206a}'..='\u{206f}'
767            | '\u{feff}'
768            | '\u{fff9}'..='\u{fffb}'
769            | '\u{1d173}'..='\u{1d17a}'
770            | '\u{e0001}'
771            | '\u{e0020}'..='\u{e007f}'
772    )
773}
774
775/// Streams the canonical form of a character stream: the preparation's steps
776/// in the order it gives them, each one an adapter over the one before, so
777/// that no step ever holds the value.
778///
779/// Map (RFC 4518 2.2), then Normalize (2.3), then the insignificant space
780/// handling (2.6.1). The order is the profile's and it is not free to
781/// change: normalization can produce a space of its own, out of a character
782/// whose compatibility form begins with one, and a space it produces has to
783/// reach the step that decides which spaces count.
784///
785/// The mapping runs on both sides of the normalization, which is what makes
786/// it the profile's mapping rather than a case fold. The table the profile
787/// names is B.2 of RFC 3454, a fold that carries the compatibility mappings
788/// with it: `2102; 0063; Additional folding` takes the double-struck
789/// capital C straight to a lowercase c. This crate's fold is the published
790/// case folding, which leaves that character alone, and the normalization
791/// after it produces a capital. Folding what the normalization produces
792/// arrives where the profile's table does, and costs a second walk of a
793/// stream already bounded.
794///
795/// What bounds the work is upstream of here: only an attribute type this
796/// crate names is folded at all, and only inside the size its schema gives
797/// it, so the longest stream this sees is a few tens of thousands of
798/// characters rather than a document's worth.
799#[cfg(test)]
800type Canonical<I> = Spaced<Mapped<Recomposed<Mapped<I>>>>;
801
802/// What the normalization step hands on, named so the pipeline above reads
803/// as the steps it is.
804#[cfg(test)]
805type Recomposed<I> = unicode_normalization::Recompositions<I>;
806
807/// Assembles the pipeline over one decoded value.
808#[cfg(test)]
809fn canonical<I: Iterator<Item = char>>(inner: I) -> Canonical<I> {
810    Spaced::over(Mapped::over(normalized(inner)))
811}
812
813/// The value as the two steps before the direction one leave it: mapped
814/// (RFC 4518 2.2), then normalized to form KC (2.3).
815///
816/// The steps that read a value rather than produce one, Prohibit and the
817/// direction check, come after these two (2.4 and 2.5), so this is the
818/// stream they are defined over.
819#[cfg(test)]
820fn normalized<I: Iterator<Item = char>>(inner: I) -> Recomposed<Mapped<I>> {
821    use unicode_normalization::UnicodeNormalization;
822    Mapped::over(inner).nfkc()
823}
824
825/// The Map step: what the preparation sends to nothing is dropped, what it
826/// sends to SPACE becomes one, and case is folded. One held expansion is the
827/// whole state.
828///
829/// The characters mapped to a space are exactly the ones RFC 4518 names: tab,
830/// line feed, vertical tab, form feed, carriage return and next line, plus
831/// the separator code points, which is what `is_whitespace` names.
832struct Mapped<I, const FOLD_CASE: bool = true> {
833    inner: I,
834    /// What one folded character expands to, which is at most a few.
835    folded: Option<Folded>,
836}
837
838/// The tail of one character's fold, after its first character has been
839/// handed out.
840enum Folded {
841    Mapped(core::str::Chars<'static>),
842    Lowered(core::char::ToLowercase),
843}
844
845impl Iterator for Folded {
846    type Item = char;
847
848    fn next(&mut self) -> Option<char> {
849        match self {
850            Self::Mapped(rest) => rest.next(),
851            Self::Lowered(rest) => rest.next(),
852        }
853    }
854}
855
856impl<I: Iterator<Item = char>, const FOLD_CASE: bool> Mapped<I, FOLD_CASE> {
857    fn over(inner: I) -> Self {
858        Self {
859            inner,
860            folded: None,
861        }
862    }
863
864    /// Folds one character's case and hands back its first output, keeping
865    /// the rest for the next call.
866    ///
867    /// The fold is the one the preparation names (RFC 4518 2.2 folds case by
868    /// the table of RFC 3454 B.2): a letter may fold to a different letter
869    /// or to more than one, and an issuer written in one case is the same
870    /// name as the subject written in another. See [`fold`] for what the map
871    /// is and what it still leaves out.
872    fn fold(&mut self, c: char) -> Option<char> {
873        match fold::of(c) {
874            fold::Fold::Mapped(mapped) => {
875                let mut rest = mapped.chars();
876                let first = rest.next();
877                self.folded = Some(Folded::Mapped(rest));
878                first
879            }
880            fold::Fold::One(one) => {
881                self.folded = None;
882                Some(one)
883            }
884            fold::Fold::Lowercase => {
885                let mut lowered = c.to_lowercase();
886                let first = lowered.next();
887                self.folded = Some(Folded::Lowered(lowered));
888                first
889            }
890        }
891    }
892}
893
894impl<I: Iterator<Item = char>, const FOLD_CASE: bool> Iterator for Mapped<I, FOLD_CASE> {
895    type Item = char;
896
897    fn next(&mut self) -> Option<char> {
898        if let Some(rest) = self.folded.as_mut()
899            && let Some(c) = rest.next()
900        {
901            return Some(c);
902        }
903        self.folded = None;
904        for c in self.inner.by_ref() {
905            // Mapped to nothing, so it takes no part in what the value says
906            // and does not separate words either.
907            if mapped_to_nothing(c) {
908                continue;
909            }
910            if c.is_whitespace() {
911                return Some(' ');
912            }
913            return if FOLD_CASE { self.fold(c) } else { Some(c) };
914        }
915        None
916    }
917}
918
919/// The insignificant space handling: a run of spaces between words counts as
920/// one and the runs at either end count as none.
921///
922/// The profile writes the same rule as padding rather than trimming, one
923/// space at each end and two between words (RFC 4518 2.6.1), which is what
924/// makes a substring assertion's edges line up. For deciding whether two
925/// whole values are equal the two forms put exactly the same values
926/// together, and this one holds one character of state instead of emitting
927/// an edge the value does not have.
928struct Spaced<I> {
929    inner: I,
930    held: Option<char>,
931    gap: bool,
932    started: bool,
933}
934
935impl<I: Iterator<Item = char>> Spaced<I> {
936    fn over(inner: I) -> Self {
937        Self {
938            inner,
939            held: None,
940            gap: false,
941            started: false,
942        }
943    }
944}
945
946impl<I: Iterator<Item = char>> Iterator for Spaced<I> {
947    type Item = char;
948
949    fn next(&mut self) -> Option<char> {
950        if let Some(c) = self.held.take() {
951            return Some(c);
952        }
953        for c in self.inner.by_ref() {
954            if c == ' ' {
955                // A gap counts only between words: a leading run has no word
956                // before it, and a trailing run meets the end instead.
957                self.gap = self.started;
958                continue;
959            }
960            self.started = true;
961            if self.gap {
962                self.gap = false;
963                self.held = Some(c);
964                return Some(' ');
965            }
966            return Some(c);
967        }
968        None
969    }
970}
971
972impl<'a> Attribute<'a> {
973    /// What kind of attribute this is.
974    #[must_use]
975    pub fn kind(self) -> Oid<'a> {
976        self.kind
977    }
978
979    /// The value, as encoded.
980    #[must_use]
981    pub fn value(self) -> AttributeValue<'a> {
982        self.value
983    }
984
985    /// The value as text for a person to read, where it is text at all.
986    ///
987    /// For display. Never for deciding that two names are the same one: see
988    /// [`Name::matches`].
989    ///
990    /// # Errors
991    /// Returns a located resource error if the execution or storage budget is spent.
992    pub fn text(self, execution: &Memory) -> Result<Option<OwnedString>> {
993        self.value.text(execution)
994    }
995
996    #[cfg(test)]
997    fn matches(self, other: &Attribute<'_>) -> bool {
998        if self.kind != other.kind {
999            return false;
1000        }
1001        if self.value.der == other.value.der {
1002            return true;
1003        }
1004        // Both are strings the type permits and that decode: the profile
1005        // compares what they say, ignoring case and the width of the gaps.
1006        // Streamed, so two long differently encoded values cost no copy.
1007        // Anything else is compared as it was encoded, because this layer has
1008        // no rule for what it means, and such bytes only ever equal
1009        // themselves.
1010        match (self.folding_chars(), other.folding_chars()) {
1011            (Some(left), Some(right)) => canonical(left).eq(canonical(right)),
1012            _ => false,
1013        }
1014    }
1015
1016    /// A total order over attributes that calls two of them equal exactly
1017    /// when [`Attribute::matches`] does, so ordering both sides of a part and
1018    /// walking them in step answers the multiset question.
1019    ///
1020    /// Kind first, then whether the value folds, then the values themselves:
1021    /// folded ones by their canonical characters, the rest by their bytes. A
1022    /// value that folds can never share its encoding with one that does not,
1023    /// the two questions being asked of the same kind and bytes, so no pair
1024    /// this separates is a pair `matches` would join.
1025    #[cfg(test)]
1026    fn order(&self, other: &Attribute<'_>) -> core::cmp::Ordering {
1027        self.kind
1028            .as_bytes()
1029            .cmp(other.kind.as_bytes())
1030            .then_with(|| match (self.folding_chars(), other.folding_chars()) {
1031                (Some(left), Some(right)) => canonical(left).cmp(canonical(right)),
1032                (None, None) => self.value.der.cmp(other.value.der),
1033                (Some(_), None) => core::cmp::Ordering::Less,
1034                (None, Some(_)) => core::cmp::Ordering::Greater,
1035            })
1036    }
1037
1038    /// Whether this value takes part in the preparation the profile describes,
1039    /// or is compared only as the bytes it was written in.
1040    ///
1041    /// A caller explaining why a name did not match needs the same answer this
1042    /// comparison uses, not a guess at it: a value can be excluded for its
1043    /// encoding, for a code point the type prohibits, or for failing the
1044    /// direction step, and only one of those is visible from the outside.
1045    ///
1046    /// # Errors
1047    /// Returns a located resource error if preparation cannot be financed.
1048    pub fn folds(self, execution: &Memory) -> Result<bool> {
1049        prepared::folds(self, execution)
1050    }
1051
1052    /// The decoded characters of a value that takes part in folding: the
1053    /// type's schema permits the encoding it was written in, and it sits
1054    /// inside the schema's size bounds. A known attribute outside them is not
1055    /// a value the schema names, and folding one would let a malformed issuer
1056    /// match a genuine subject; it stays byte-only equality.
1057    #[cfg(test)]
1058    fn folding_chars(self) -> Option<DecodedChars<'a>> {
1059        (permits(self.kind, self.value.encoding()) && preparable(&self))
1060            .then(|| self.value.decoded_chars())
1061    }
1062}
1063
1064impl<'a> AttributeValue<'a> {
1065    /// The value exactly as it was encoded, tag included.
1066    #[must_use]
1067    pub fn as_bytes(self) -> &'a [u8] {
1068        self.der
1069    }
1070
1071    /// The contents, without the tag and length.
1072    #[must_use]
1073    pub fn contents(self) -> &'a [u8] {
1074        self.contents
1075    }
1076
1077    /// Which string encoding this was written in.
1078    #[must_use]
1079    pub fn encoding(self) -> Encoding {
1080        if self.tag.class() != Class::Universal || self.tag.is_constructed() {
1081            return Encoding::Other;
1082        }
1083        match self.tag.number() {
1084            Some(universal::UTF8_STRING) => Encoding::Utf8,
1085            Some(universal::PRINTABLE_STRING) => Encoding::Printable,
1086            Some(universal::IA5_STRING) => Encoding::Ia5,
1087            Some(NUMERIC_STRING) => Encoding::Numeric,
1088            Some(TELETEX_STRING) => Encoding::Teletex,
1089            Some(VISIBLE_STRING) => Encoding::Visible,
1090            Some(BMP_STRING) => Encoding::Bmp,
1091            Some(UNIVERSAL_STRING) => Encoding::Universal,
1092            _ => Encoding::Other,
1093        }
1094    }
1095
1096    /// The value as text for a person to read, where it is text at all.
1097    ///
1098    /// Bounded, because this is the public reading path and a value may be
1099    /// as wide as the element limit permits while several attribute types
1100    /// have no ceiling in the schema. What is shown is as much of the value
1101    /// as the widest name component the profile names, and a mark saying the
1102    /// rest is there. Identity is the bytes and is never this.
1103    ///
1104    /// The returned string retains its storage charge independently of the parser.
1105    /// # Errors
1106    /// Returns a located resource error before unfunded decoding or allocation.
1107    pub fn text(self, execution: &Memory) -> Result<Option<OwnedString>> {
1108        let fail = |reason| Error::resource(reason, "name.attribute", self.offset);
1109        let width = match self.encoding() {
1110            Encoding::Other => return Ok(None),
1111            Encoding::Bmp => Some(2),
1112            Encoding::Universal => Some(4),
1113            _ => None,
1114        };
1115        // UTF-8 validation and subsequent decoding each visit the input at most
1116        // once. Admit both before entering either scan.
1117        execution
1118            .charge_work((self.contents.len() as u64) * 2)
1119            .map_err(fail)?;
1120        match width {
1121            Some(width) => {
1122                if !self.contents.len().is_multiple_of(width) {
1123                    return Ok(None);
1124                }
1125                let bound = ((DISPLAY_CEILING + 1) * width).min(self.contents.len());
1126                display_text(wide_chars(&self.contents[..bound], width), execution).map_err(fail)
1127            }
1128            // Every remaining type is a subset of ASCII by its definition, and
1129            // an issuer writing outside it has written something. Where those
1130            // bytes are UTF-8 they are read as UTF-8, which is what the issuer
1131            // meant; where they are not, they are read as one byte a
1132            // character. Both are approximations for a person to read, and
1133            // neither is what two names are compared on.
1134            None => match core::str::from_utf8(self.contents) {
1135                Ok(text) => display_text(text.chars().map(Some), execution).map_err(fail),
1136                Err(_) => display_text(
1137                    self.contents.iter().map(|byte| Some(char::from(*byte))),
1138                    execution,
1139                )
1140                .map_err(fail),
1141            },
1142        }
1143    }
1144
1145    /// Streams the value's characters through its declared alphabet and
1146    /// `keep`, counting them, without materializing the text: a value can be
1147    /// as long as the element limit permits, and validating one must not
1148    /// allocate a copy its size. `None` is a value that does not decode or a
1149    /// character either test refuses.
1150    fn validated_count(self, mut keep: impl FnMut(char) -> bool) -> Option<usize> {
1151        let encoding = self.encoding();
1152        let mut count = 0usize;
1153        match encoding {
1154            Encoding::Other => return None,
1155            Encoding::Bmp | Encoding::Universal => {
1156                let width = if encoding == Encoding::Bmp { 2 } else { 4 };
1157                if !self.contents.len().is_multiple_of(width) {
1158                    return None;
1159                }
1160                for c in wide_chars(self.contents, width) {
1161                    if !keep(c?) {
1162                        return None;
1163                    }
1164                    count += 1;
1165                }
1166            }
1167            _ => {
1168                let text = core::str::from_utf8(self.contents).ok()?;
1169                for c in text.chars() {
1170                    if !in_alphabet(encoding, c) || !keep(c) {
1171                        return None;
1172                    }
1173                    count += 1;
1174                }
1175            }
1176        }
1177        Some(count)
1178    }
1179
1180    /// The decoded characters of a value [`preparable`] has already
1181    /// validated: total and allocation free, for folding without a copy.
1182    fn decoded_chars(self) -> DecodedChars<'a> {
1183        match self.encoding() {
1184            Encoding::Bmp => DecodedChars::Wide {
1185                contents: self.contents,
1186                width: 2,
1187            },
1188            Encoding::Universal => DecodedChars::Wide {
1189                contents: self.contents,
1190                width: 4,
1191            },
1192            _ => DecodedChars::Narrow(
1193                core::str::from_utf8(self.contents)
1194                    .expect("the value was decoded before this iterator was built")
1195                    .chars(),
1196            ),
1197        }
1198    }
1199}
1200
1201/// Whether a character sits inside the alphabet a narrow string type
1202/// declares. IA5 is ASCII by definition. The teletex repertoire is a
1203/// negotiation this crate does not implement; its invariant subset is ASCII,
1204/// and only that subset takes part in matching.
1205fn in_alphabet(encoding: Encoding, c: char) -> bool {
1206    match encoding {
1207        Encoding::Printable => is_printable_string(c),
1208        Encoding::Numeric => c.is_ascii_digit() || c == ' ',
1209        Encoding::Visible => matches!(c, '\x20'..='\x7e'),
1210        Encoding::Ia5 | Encoding::Teletex => c.is_ascii(),
1211        _ => true,
1212    }
1213}
1214
1215/// The decoded characters of a wide string, one unit at a time: a unit that
1216/// is not a character, a surrogate included, is `None` (X.680, 41.16 puts
1217/// `BMPString` in the basic plane, and `char::from_u32` refuses surrogates).
1218fn wide_chars(contents: &[u8], width: usize) -> impl Iterator<Item = Option<char>> + '_ {
1219    contents.chunks_exact(width).map(|chunk| {
1220        char::from_u32(
1221            chunk
1222                .iter()
1223                .fold(0u32, |value, byte| (value << 8) | u32::from(*byte)),
1224        )
1225    })
1226}
1227
1228/// The characters of an already validated value, streamed without an
1229/// allocation.
1230enum DecodedChars<'a> {
1231    Narrow(core::str::Chars<'a>),
1232    Wide { contents: &'a [u8], width: usize },
1233}
1234
1235impl Iterator for DecodedChars<'_> {
1236    type Item = char;
1237
1238    fn next(&mut self) -> Option<char> {
1239        match self {
1240            Self::Narrow(chars) => chars.next(),
1241            Self::Wide { contents, width } => {
1242                if contents.len() < *width {
1243                    return None;
1244                }
1245                let (unit, rest) = contents.split_at(*width);
1246                *contents = rest;
1247                // A substitute character here would make two values that do
1248                // not decode compare equal, which is the forged match this
1249                // module exists to prevent.
1250                Some(
1251                    char::from_u32(
1252                        unit.iter()
1253                            .fold(0u32, |value, byte| (value << 8) | u32::from(*byte)),
1254                    )
1255                    .expect("the value was decoded before this iterator was built"),
1256                )
1257            }
1258        }
1259    }
1260}
1261
1262/// Tag numbers X.680 gives the types this crate reads past the ones
1263/// `sig-asn1` names, which are the ones nothing below the schema needs.
1264const REAL: u32 = 9;
1265const ENUMERATED: u32 = 10;
1266const RELATIVE_OID: u32 = 13;
1267const NUMERIC_STRING: u32 = 18;
1268const TELETEX_STRING: u32 = 20;
1269const VISIBLE_STRING: u32 = 26;
1270const UNIVERSAL_STRING: u32 = 28;
1271const BMP_STRING: u32 = 30;
1272const EXTERNAL: u32 = 8;
1273const EMBEDDED_PDV: u32 = 11;
1274const OBJECT_DESCRIPTOR: u32 = 7;
1275const TIME: u32 = 14;
1276const DATE: u32 = 31;
1277const TIME_OF_DAY: u32 = 32;
1278const DATE_TIME: u32 = 33;
1279const DURATION: u32 = 34;
1280const OID_IRI: u32 = 35;
1281const RELATIVE_OID_IRI: u32 = 36;
1282
1283/// Whether contents are the value notation of an identifier written as a
1284/// resource name: the arcs in UTF-8, no arc empty and none carrying white
1285/// space, the object form opening with the separator and the relative one
1286/// not (X.680 34.3 and 35.3, X.690 8.21.2 and 8.22.2).
1287///
1288/// What an arc may say beyond that is a registry's business, so nothing here
1289/// reads one: this is the shape of the value, which is what deciding it is a
1290/// value of the type asks for.
1291fn iri_fits(contents: &[u8], rooted: bool) -> bool {
1292    let Ok(text) = core::str::from_utf8(contents) else {
1293        return false;
1294    };
1295    let arcs = match text.strip_prefix('/') {
1296        Some(rest) if rooted => rest,
1297        None if !rooted => text,
1298        _ => return false,
1299    };
1300    !arcs.is_empty() && arcs.split('/').all(arc_fits)
1301}
1302
1303/// Whether one arc is a Unicode label: either the digits of an arc's own
1304/// number, or a name written from the characters X.660 7.5.2 lists.
1305///
1306/// The number opens with a zero only where it is that one digit (7.3). The
1307/// name holds at least one character that is not a digit, which is what
1308/// tells the two apart (7.5.1), carries no hyphen at either end and no pair
1309/// of them in the third and fourth places, where a normalized form would
1310/// read them as a prefix (7.5.4).
1311///
1312/// What is not applied is 7.5.3, which excludes the positions ISO/IEC 10646
1313/// marks as not to be used: that marking is not stable across editions, and
1314/// the clause's own note tells a reader to be tolerant of it. Everything
1315/// else here is the label as the standard writes it.
1316fn arc_fits(arc: &str) -> bool {
1317    if arc.is_empty() {
1318        return false;
1319    }
1320    if arc.bytes().all(|byte| byte.is_ascii_digit()) {
1321        return arc == "0" || !arc.starts_with('0');
1322    }
1323    if arc.starts_with('-') || arc.ends_with('-') {
1324        return false;
1325    }
1326    let hyphenated = arc
1327        .chars()
1328        .nth(2)
1329        .zip(arc.chars().nth(3))
1330        .is_some_and(|(third, fourth)| third == '-' && fourth == '-');
1331    !hyphenated && arc.chars().all(label_character)
1332}
1333
1334/// Whether a character is one a Unicode label is written from (X.660 7.5.2).
1335fn label_character(c: char) -> bool {
1336    matches!(c, '-' | '.' | '_' | '~' | '0'..='9' | 'A'..='Z' | 'a'..='z')
1337        || matches!(u32::from(c),
1338            0xa0..=0xdffe
1339            | 0xf900..=0xfdcf
1340            | 0xfdf0..=0xffef
1341            | 0x1_0000..=0x1_fffd
1342            | 0x2_0000..=0x2_fffd
1343            | 0x3_0000..=0x3_fffd
1344            | 0x4_0000..=0x4_fffd
1345            | 0x5_0000..=0x5_fffd
1346            | 0x6_0000..=0x6_fffd
1347            | 0x7_0000..=0x7_fffd
1348            | 0x8_0000..=0x8_fffd
1349            | 0x9_0000..=0x9_fffd
1350            | 0xa_0000..=0xa_fffd
1351            | 0xb_0000..=0xb_fffd
1352            | 0xc_0000..=0xc_fffd
1353            | 0xd_0000..=0xd_fffd
1354            | 0xe_1000..=0xe_fffd)
1355}
1356
1357/// Whether a universal type is one DER writes constructed, so finding it that
1358/// way is the type rather than a second spelling of a primitive one.
1359///
1360/// The containers, and the three types whose definition is an associated
1361/// sequence: external and instance-of under tag 8 (X.690 8.16.1, 8.18.1),
1362/// embedded-pdv under 11 (8.17.1), and the unrestricted character string
1363/// under 29 (8.24.1). Everything else universal is primitive here (10.2).
1364pub(crate) fn constructed_universal_type(number: u32) -> bool {
1365    matches!(
1366        number,
1367        universal::SEQUENCE | universal::SET | 8 | 11 | CHARACTER_STRING
1368    )
1369}
1370
1371/// `CHARACTER STRING`, the unrestricted one, which this crate names itself
1372/// because nothing below the schema needs it.
1373const CHARACTER_STRING: u32 = 29;
1374
1375/// Whether the members of one of the three types whose encoding is a
1376/// sequence defined for it are the components that definition names.
1377///
1378/// The external type is a sequence of three optional members, an identifier,
1379/// a reference and a descriptor, and then the encoding it carries, which is
1380/// one of three choices and is not optional (X.690 8.18.1). The embedded-pdv
1381/// type and the unrestricted character string are the same shape as each
1382/// other: how the value is identified, then the value, both required and
1383/// tagged in order, with the descriptor between them absent by the
1384/// definition's own constraint (X.680 36.5 and 44.5).
1385///
1386/// What each member says is somebody else's business, and nothing here reads
1387/// one. This is the shape, which is what deciding it is a value of the type
1388/// asks for. The walk that follows holds each member to its own rules.
1389fn associated_sequence_fits<'a>(
1390    parent: &Reader<'a>,
1391    element: &Element<'a>,
1392    field: &'static str,
1393    number: u32,
1394) -> Result<bool> {
1395    let mut inside = parent.enter(element).field(field)?;
1396    if number == EXTERNAL {
1397        // The optional members come in this order and each appears once.
1398        let mut left: &[u32] = &[universal::OID, universal::INTEGER, OBJECT_DESCRIPTOR];
1399        while let Some(member) = inside.next_element().field(field)? {
1400            let tag = member.tag();
1401            if tag.class() == Class::ContextSpecific {
1402                // The encoding closes the sequence, and each of its three
1403                // ways says what its contents are: one whole value carried
1404                // inside the tag, a value in octets, which any bytes are, or
1405                // a value in bits, which opens with the count of the unused
1406                // ones.
1407                let carried = match tag.number() {
1408                    Some(0) => {
1409                        let mut held = inside.enter(&member).field(field)?;
1410                        held.next_element().field(field)?.is_some() && held.is_empty()
1411                    }
1412                    Some(1) => segments::implicit(&inside, &member, field, false)?,
1413                    Some(2) => segments::implicit(&inside, &member, field, true)?,
1414                    _ => false,
1415                };
1416                return Ok(carried && inside.is_empty());
1417            }
1418            let Some(at) = tag
1419                .number()
1420                .filter(|_| tag.class() == Class::Universal)
1421                .and_then(|number| left.iter().position(|kind| *kind == number))
1422            else {
1423                return Ok(false);
1424            };
1425            left = &left[at + 1..];
1426        }
1427        // Nothing carried, which is the one member the definition requires.
1428        return Ok(false);
1429    }
1430
1431    // How the value is identified: a choice, so its member wears an explicit
1432    // tag over whichever of the six alternatives was written.
1433    let Some(identification) = inside.next_element().field(field)? else {
1434        return Ok(false);
1435    };
1436    if identification.tag() != Tag::context(true, 0) {
1437        return Ok(false);
1438    }
1439    let mut chosen = inside.enter(&identification).field(field)?;
1440    let Some(alternative) = chosen.next_element().field(field)? else {
1441        return Ok(false);
1442    };
1443    if alternative.tag().class() != Class::ContextSpecific
1444        || !chosen.is_empty()
1445        || !identification_fits(&chosen, &alternative, field)?
1446    {
1447        return Ok(false);
1448    }
1449    // Then the value itself, which is the third component of the definition
1450    // and keeps that number whether or not the second one is written. It is
1451    // an octet string under its tag, and the distinguished rules write a
1452    // string in one piece (X.690 10.2), so the segmented form is a second
1453    // spelling of it there. The basic rules have both, and a document read
1454    // under them keeps what it was written with.
1455    let Some(value) = inside.next_element().field(field)? else {
1456        return Ok(false);
1457    };
1458    Ok(value.tag().class() == Class::ContextSpecific
1459        && value.tag().number() == Some(2)
1460        && segments::implicit(&inside, &value, field, false)?
1461        && inside.is_empty())
1462}
1463
1464/// Whether a member read as the type it is, with a spent budget kept as
1465/// what it is.
1466///
1467/// A value that is not the type is an answer about the document, and this
1468/// says no. A budget that ran out is this run giving up, and it says
1469/// nothing about the document, so it travels on rather than being folded
1470/// into the no beside it: a report must not blame a certificate for a
1471/// device that stopped.
1472fn reads<T>(outcome: structured_asn1::Result<T>, field: &'static str) -> Result<bool> {
1473    match outcome.field(field) {
1474        Ok(_) => Ok(true),
1475        Err(error) if error.is_resource() => Err(error),
1476        Err(_) => Ok(false),
1477    }
1478}
1479
1480/// Whether one alternative of the identification choice is the type that
1481/// alternative is (X.680 36.5, and 44.5 for the same choice again).
1482///
1483/// The alternatives are tagged over their types rather than beside them, so
1484/// what arrives is the type's contents under a context tag, and the contents
1485/// are the type's: the pair of identifiers, one identifier, a context named
1486/// by a number, that number with an identifier beside it, the transfer
1487/// syntax as an identifier, and the fixed alternative, which is nothing at
1488/// all. A tag with the wrong contents under it is the same defect as a
1489/// container with the wrong members, one level down.
1490fn identification_fits<'a>(
1491    parent: &Reader<'a>,
1492    alternative: &Element<'a>,
1493    field: &'static str,
1494) -> Result<bool> {
1495    /// The two members of the alternatives that hold a pair, as the types
1496    /// they are: the syntaxes are two identifiers, the negotiation is a
1497    /// context and the syntax to encode it in.
1498    fn pair<'a>(
1499        parent: &Reader<'a>,
1500        alternative: &Element<'a>,
1501        field: &'static str,
1502        numbered: bool,
1503    ) -> Result<bool> {
1504        let mut inside = parent.enter(alternative).field(field)?;
1505        let (Some(first), Some(second)) = (
1506            inside.next_element().field(field)?,
1507            inside.next_element().field(field)?,
1508        ) else {
1509            return Ok(false);
1510        };
1511        let opens = if numbered {
1512            reads(inside.integer(&first), field)?
1513        } else {
1514            reads(inside.oid(&first), field)?
1515        };
1516        Ok(opens
1517            && first.tag() == Tag::context(false, 0)
1518            && second.tag() == Tag::context(false, 1)
1519            && reads(inside.oid(&second), field)?
1520            && inside.is_empty())
1521    }
1522
1523    let constructed = alternative.tag().is_constructed();
1524    Ok(match alternative.tag().number() {
1525        Some(0) => constructed && pair(parent, alternative, field, false)?,
1526        Some(1 | 4) => reads(parent.oid(alternative), field)?,
1527        Some(2) => reads(parent.integer(alternative), field)?,
1528        Some(3) => constructed && pair(parent, alternative, field, true)?,
1529        // The fixed alternative is a null, which says what it says by being
1530        // there and carries nothing.
1531        Some(5) => !constructed && alternative.contents().is_empty(),
1532        _ => false,
1533    })
1534}
1535
1536/// Whether a universal number belongs to a type at all.
1537///
1538/// Table 1 of X.680 assigns them. Zero is kept by the encoding rules,
1539/// fifteen is reserved for future editions, and thirty-seven and up are
1540/// reserved for addenda: nothing between the standard's covers gives any of
1541/// them a meaning, so bytes wearing one are a value of no type.
1542fn assigned_universal_type(number: u32) -> bool {
1543    !matches!(number, 0 | 15) && number <= RELATIVE_OID_IRI
1544}
1545
1546/// Whether a restricted string's contents are held to the alphabet its type
1547/// names.
1548///
1549/// The two answers are the two things a preserved value goes on to do. A
1550/// value handed to a scheme that clears a critical extension has to be a
1551/// value of the type it claims, or the extension is cleared on something
1552/// that is not one. A value that takes part in a name is kept as written:
1553/// refusing it would block a certificate over a spelling, and the profile
1554/// names binary comparison as a sufficient matching rule (RFC 5280 7.1), so
1555/// a malformed value still has an identity and is still shown to a person.
1556/// It is only withheld from folding, which is defined over values the schema
1557/// names.
1558#[derive(Clone, Copy, PartialEq, Eq)]
1559pub(crate) enum Strings {
1560    Checked,
1561    AsWritten,
1562}
1563
1564/// Reads every element under one, holding each to the rules the encoding
1565/// names even where nothing here interprets the value.
1566///
1567/// The places that preserve an opaque value share this: an attribute of a
1568/// name, the value of an other-name, the information of a qualified
1569/// statement, an algorithm's parameter and the value of a policy qualifier.
1570/// Each is handed to somebody who decides an identity, names the service that
1571/// issued the certificate, or clears a critical extension on the strength of
1572/// it, so what is preserved has to be the encoding the document claims, all
1573/// the way down. Checking the outer tag
1574/// alone leaves the same second spelling of a value one level lower, where it
1575/// arrives at the same reader by the same route.
1576pub(crate) fn walk_der<'a>(
1577    parent: &Reader<'a>,
1578    element: &Element<'a>,
1579    field: &'static str,
1580    strings: Strings,
1581) -> Result<()> {
1582    if !check_der(parent, element, field, strings)? {
1583        return Ok(());
1584    }
1585    // The descent keeps its own stack rather than the machine's. Depth is
1586    // the reader's to bound and a caller may raise that bound, so spending a
1587    // machine stack frame per element would turn a limit into a crash for
1588    // whoever raised it. On this stack the same input is the refusal the
1589    // limit describes.
1590    let mut open = parent.memory().vector::<Open<'a>>();
1591    open.try_push(Open::of(parent.enter(element).field(field)?, element.tag()))
1592        .map_err(|reason| Error::resource(reason, field, element.span().start))?;
1593    while let Some(level) = open.last_mut() {
1594        let Some(child) = level.reader.next_element().field(field)? else {
1595            open.pop();
1596            continue;
1597        };
1598        // The members of a set appear in ascending order of their encodings
1599        // (X.690 11.6), and a set's components in the tag order 10.3 names,
1600        // which the same comparison decides because a tag leads its own
1601        // encoding. Deciding it walks up to the longer member, so that
1602        // length is charged before the walk: a caller bounding work sees
1603        // this on the same meter the reads use.
1604        if level.ordered
1605            && let Some(previous) = level.previous
1606        {
1607            level
1608                .reader
1609                .charge(previous.len().max(child.as_bytes().len()) as u64)
1610                .field(field)?;
1611            if !der_set_ordered(previous, child.as_bytes()) {
1612                return Err(Error::new(
1613                    ErrorCode::MalformedValue,
1614                    field,
1615                    child.span().start,
1616                ));
1617            }
1618        }
1619        level.previous = Some(child.as_bytes());
1620
1621        let inside = &open
1622            .last()
1623            .expect("the reader the child was read from")
1624            .reader;
1625        if check_der(inside, &child, field, strings)? {
1626            let entered = inside.enter(&child).field(field)?;
1627            let tag = child.tag();
1628            open.try_push(Open::of(entered, tag))
1629                .map_err(|reason| Error::resource(reason, field, child.span().start))?;
1630        }
1631    }
1632    Ok(())
1633}
1634
1635/// One container the walk is inside, and what deciding its members needs.
1636struct Open<'a> {
1637    reader: Reader<'a>,
1638    /// Whether this container's members are ordered by their encodings,
1639    /// which is the case for a set and for nothing else.
1640    ordered: bool,
1641    /// The member read before this one, for that comparison.
1642    previous: Option<&'a [u8]>,
1643}
1644
1645impl<'a> Open<'a> {
1646    fn of(reader: Reader<'a>, tag: Tag) -> Self {
1647        let ordered = reader.encoding().is_der()
1648            && tag.class() == Class::Universal
1649            && tag.number() == Some(universal::SET);
1650        Self {
1651            reader,
1652            ordered,
1653            previous: None,
1654        }
1655    }
1656}
1657
1658/// Holds one element to the rules its tag names, and says whether it has
1659/// children the caller still has to walk.
1660fn check_der<'a>(
1661    parent: &Reader<'a>,
1662    element: &Element<'a>,
1663    field: &'static str,
1664    strings: Strings,
1665) -> Result<bool> {
1666    let fail = |code| Error::new(code, field, element.span().start);
1667    let tag = element.tag();
1668    // The construction rule runs both ways, and only one of the two is
1669    // about DER. A string written constructed is a second spelling of one
1670    // value, which the distinguished rules forbid (X.690 10.2). A container
1671    // written primitive is not the type at all: a sequence and a set are
1672    // constructed by definition (8.9.1, 8.11.1), as are the three types
1673    // whose definition is an associated sequence (8.17.1, 8.18.1, 8.24.1),
1674    // and that holds in either encoding.
1675    if tag.class() == Class::Universal {
1676        // Before the form, the number itself. Table 1 of X.680 assigns the
1677        // universal numbers, and three ranges belong to no type: zero, which
1678        // the encoding rules keep for themselves, fifteen, and everything
1679        // from thirty-seven up. Bytes wearing one of those claim a type the
1680        // standard has not defined, in either encoding, so preserving them
1681        // would hand a scheme a value of nothing.
1682        if !tag.number().is_some_and(assigned_universal_type) {
1683            return Err(fail(ErrorCode::Encoding(
1684                structured_asn1::ErrorCode::UnexpectedTag,
1685            )));
1686        }
1687        // A number this reader does not name is not one of the containers,
1688        // and universal numbers that wide are not assigned at all.
1689        let container = tag.number().is_some_and(constructed_universal_type);
1690        let wrong = if tag.is_constructed() {
1691            !container
1692                && (parent.encoding().is_der()
1693                    || !tag.number().is_some_and(segmented_universal_type))
1694        } else {
1695            container
1696        };
1697        if wrong {
1698            return Err(fail(ErrorCode::Encoding(
1699                structured_asn1::ErrorCode::UnexpectedTag,
1700            )));
1701        }
1702        if tag.is_constructed() && tag.number().is_some_and(segmented_universal_type) {
1703            segments::validate(parent, element, field, strings)?;
1704            return Ok(false);
1705        }
1706        // Three of the containers are not containers of anything: their
1707        // encoding is the encoding of a sequence defined for them, whose
1708        // components are the type. A tag with the wrong members under it
1709        // wears the type without being a value of it.
1710        if let Some(number @ (EXTERNAL | EMBEDDED_PDV | CHARACTER_STRING)) = tag.number()
1711            && !associated_sequence_fits(parent, element, field, number)?
1712        {
1713            return Err(fail(ErrorCode::MalformedValue));
1714        }
1715    }
1716    if !tag.is_constructed() {
1717        // The types whose contents the encoding settles: an integer written
1718        // a byte longer than it needs, a boolean spelled with a byte other
1719        // than the two DER allows, a bit string whose padding carries data.
1720        // Nothing here means anything by the value; what is checked is that
1721        // it is written the one way DER writes it.
1722        if tag.class() == Class::Universal {
1723            match tag.number() {
1724                Some(universal::INTEGER) => parent.integer(element).field(field).map(|_| ())?,
1725                Some(universal::BIT_STRING) => {
1726                    parent.bit_string(element).field(field).map(|_| ())?;
1727                }
1728                Some(universal::BOOLEAN) => parent.boolean(element).field(field).map(|_| ())?,
1729                Some(universal::NULL) => parent.null(element).field(field)?,
1730                Some(universal::OID) => parent.oid(element).field(field).map(|_| ())?,
1731                // An enumerated value is encoded as the integer it is
1732                // associated with (X.690 8.4), so the integer's rules are
1733                // its rules.
1734                Some(ENUMERATED) => parent.integer(element).field(field).map(|_| ())?,
1735                // A real's octets are settled to the last one (8.5), and the
1736                // distinguished rules settle them further (11.3). Nothing
1737                // here reads the number.
1738                Some(REAL) => parent.real(element).field(field)?,
1739                // A relative identifier's sub-identifiers are written the
1740                // way an identifier's are: in the fewest octets, so none
1741                // begins with 0x80, and the last of each series closes it
1742                // (X.690 8.20.2). That is what the identifier reader checks,
1743                // the joint first arc aside, which a relative one does not
1744                // have.
1745                Some(RELATIVE_OID) => parent.oid(element).field(field).map(|_| ())?,
1746                // Under the encoding's rule and not the profile's: a
1747                // certificate's validity dates are written without a
1748                // fraction because the profile says so (RFC 5280 4.1.2.5.2),
1749                // and a value preserved inside somebody else's payload is
1750                // not a validity date.
1751                Some(universal::UTC_TIME | universal::GENERALIZED_TIME) => {
1752                    // A fraction is held to digits by walking it, and it is
1753                    // as long as the element permits: the length goes on the
1754                    // shared meter first, as it does for the identifier and
1755                    // the strings below.
1756                    useful_time_fits(parent, element, field)?;
1757                }
1758                // The newer time types, whose contents are the value notation
1759                // with the characters X.690 8.26 names taken out. What each
1760                // one writes is settled by its property settings (X.680
1761                // 38.4), so a value that is not that notation is not a value
1762                // of the type, whatever the tag says.
1763                Some(kind @ (TIME | DATE | TIME_OF_DAY | DATE_TIME | DURATION)) => {
1764                    parent
1765                        .charge(element.contents().len() as u64)
1766                        .field(field)?;
1767                    let defined = match kind {
1768                        DATE => crate::time::Defined::Date,
1769                        TIME_OF_DAY => crate::time::Defined::TimeOfDay,
1770                        DATE_TIME => crate::time::Defined::DateTime,
1771                        DURATION => crate::time::Defined::Duration,
1772                        _ => crate::time::Defined::Any,
1773                    };
1774                    if !crate::time::defined_fits(defined, element.contents()) {
1775                        return Err(fail(ErrorCode::MalformedValue));
1776                    }
1777                }
1778                // The two identifiers written as resource names: their
1779                // contents are the arcs in UTF-8 with no white space between
1780                // the lexical items (X.690 8.21.2, 8.22.2), the object form
1781                // beginning at the root and the relative one not (X.680 34.3
1782                // and 35.3).
1783                Some(kind @ (OID_IRI | RELATIVE_OID_IRI)) => {
1784                    parent
1785                        .charge(element.contents().len() as u64)
1786                        .field(field)?;
1787                    if !iri_fits(element.contents(), kind == OID_IRI) {
1788                        return Err(fail(ErrorCode::MalformedValue));
1789                    }
1790                }
1791                // A restricted string's contents are settled by its type as
1792                // much as an integer's are by DER: bytes outside the type's
1793                // alphabet, a width that is not whole, or a unit that is not
1794                // a character wear the tag without being a value of it
1795                // (X.680 41). The scan streams and counts rather than
1796                // decoding into a copy, so a value the element limit permits
1797                // costs its length and not its size in memory.
1798                _ if strings == Strings::Checked => {
1799                    // The scan walks every character, and a preserved value
1800                    // has no ceiling of its own: the length is charged to
1801                    // the shared work budget first, so a caller who bounded
1802                    // the work gets the bound here as everywhere else.
1803                    parent
1804                        .charge(element.contents().len() as u64)
1805                        .field(field)?;
1806                    let value = AttributeValue {
1807                        tag,
1808                        contents: element.contents(),
1809                        der: element.as_bytes(),
1810                        offset: element.span().start,
1811                    };
1812                    // TeletexString is left out of this, as it is left out
1813                    // of the shape question a name asks: its repertoire is
1814                    // T.61, a negotiation this crate does not implement, so
1815                    // the bytes being there is what is checkable. What the
1816                    // alphabet below says about it is the approximation
1817                    // this crate reads it as for display, and holding a
1818                    // preserved value to that would refuse a legacy value
1819                    // the schema names.
1820                    let settled = !matches!(value.encoding(), Encoding::Other | Encoding::Teletex);
1821                    if settled && value.validated_count(|_| true).is_none() {
1822                        return Err(fail(ErrorCode::MalformedValue));
1823                    }
1824                }
1825                // What is left is what the encoding does not settle, and it
1826                // is left on purpose. The graphic and general strings and
1827                // the object descriptor carry a repertoire that is
1828                // negotiated rather than fixed (X.680 41, and the same
1829                // reasoning as the teletex string a name may hold). The
1830                // types that write a time as characters, and the two that
1831                // write an identifier as an internationalized resource
1832                // name, are settled by a syntax rather than by the octets,
1833                // and none of them has a reader here because no schema this
1834                // product parses names one; checking them would mean
1835                // writing a parser whose only caller is this check.
1836                _ => (),
1837            }
1838        }
1839        return Ok(false);
1840    }
1841    Ok(true)
1842}
1843
1844fn useful_time_fits(parent: &Reader<'_>, element: &Element<'_>, field: &'static str) -> Result<()> {
1845    let generalized = element.tag().number() == Some(universal::GENERALIZED_TIME);
1846    let bytes = element.contents();
1847    if parent.encoding().is_der() {
1848        parent.charge(bytes.len() as u64).field(field)?;
1849        if generalized {
1850            crate::temporal::admit_generalized(parent, element, field)?;
1851        }
1852        crate::time::read_as(element, field, crate::time::Fraction::Written)?;
1853    } else {
1854        let work = (bytes.len() as u64).checked_mul(3).ok_or_else(|| {
1855            Error::resource(
1856                structured_asn1::memory::MemoryError::WorkExceeded,
1857                field,
1858                element.span().start,
1859            )
1860        })?;
1861        parent.charge(work).field(field)?;
1862        if !crate::time::ber_fits(bytes, generalized) {
1863            return Err(Error::new(
1864                ErrorCode::MalformedTime,
1865                field,
1866                element.span().start,
1867            ));
1868        }
1869    }
1870    Ok(())
1871}
1872
1873/// BER permits segmentation only for bit/octet strings and the restricted
1874/// character strings, including the useful time types implicitly based on
1875/// `VisibleString`. It does not change primitive-only scalar encodings.
1876/// X.690 §§8.6, 8.7, 8.23; X.680 §§46.3, 47.3, 48.3.
1877/// <https://www.itu.int/rec/T-REC-X.690-202102-I/en>
1878fn segmented_universal_type(number: u32) -> bool {
1879    matches!(number, 3 | 4 | 7 | 12 | 18..=28 | 30)
1880}
1881
1882/// Whether the bytes stay inside the `IA5String` alphabet, the 128-character
1883/// IRV (X.680, 41.4): a byte above 0x7f wears the tag but is not the type.
1884pub(crate) fn is_ia5(bytes: &[u8]) -> bool {
1885    bytes.iter().all(u8::is_ascii)
1886}
1887
1888/// Whether the bytes stay inside the `NumericString` alphabet, digits and
1889/// space (X.680, 41.2).
1890pub(crate) fn is_numeric(bytes: &[u8]) -> bool {
1891    bytes
1892        .iter()
1893        .all(|&byte| byte.is_ascii_digit() || byte == b' ')
1894}
1895
1896/// Whether the bytes stay inside the closed `PrintableString` alphabet of
1897/// X.680, 41.4.
1898pub(crate) fn is_printable(bytes: &[u8]) -> bool {
1899    bytes
1900        .iter()
1901        .all(|&byte| byte.is_ascii() && is_printable_string(char::from(byte)))
1902}
1903
1904/// Whether a character belongs to the `PrintableString` alphabet, which X.680
1905/// closes over letters, digits, space and a short list of punctuation.
1906pub(crate) fn is_printable_string(c: char) -> bool {
1907    c.is_ascii_alphanumeric()
1908        || matches!(
1909            c,
1910            ' ' | '\'' | '(' | ')' | '+' | ',' | '-' | '.' | '/' | ':' | '=' | '?'
1911        )
1912}
1913
1914/// Whether two adjacent members of a set are in the order DER requires:
1915/// ascending as octet strings, the shorter compared as if padded at its end
1916/// with zeroes. Equal members are permitted, which is how a genuine duplicate
1917/// is encoded.
1918pub(crate) fn der_set_ordered(previous: &[u8], next: &[u8]) -> bool {
1919    let length = previous.len().max(next.len());
1920    for position in 0..length {
1921        let left = previous.get(position).copied().unwrap_or(0);
1922        let right = next.get(position).copied().unwrap_or(0);
1923        if left != right {
1924            return left < right;
1925        }
1926    }
1927    true
1928}
1929
1930/// Decodes a string of characters `width` bytes each.
1931/// Counts the characters of a wide string without building one: the size
1932/// constraint on such a value is in characters, and answering it is all a
1933/// gate needs. `None` is a value that does not decode.
1934pub(crate) fn wide_char_count(contents: &[u8], width: usize) -> Option<usize> {
1935    if !contents.len().is_multiple_of(width) {
1936        return None;
1937    }
1938    let mut count = 0usize;
1939    for character in wide_chars(contents, width) {
1940        character?;
1941        count += 1;
1942    }
1943    Some(count)
1944}
1945
1946/// The same reading, stopped one character past the bound a report shows.
1947///
1948/// A unit that is not a character still refuses the whole value, as it does
1949/// when the value is read entire; the difference is only that the units past
1950/// the bound are not looked at, because they are not going to be shown.
1951fn display_text(
1952    mut characters: impl Iterator<Item = Option<char>>,
1953    execution: &Memory,
1954) -> core::result::Result<Option<OwnedString>, structured_asn1::memory::MemoryError> {
1955    let mut text = execution.string();
1956    for index in 0..=DISPLAY_CEILING {
1957        execution.charge_work(1)?;
1958        let Some(character) = characters.next() else {
1959            break;
1960        };
1961        let Some(character) = character else {
1962            return Ok(None);
1963        };
1964        if index == DISPLAY_CEILING {
1965            text.try_push('…')?;
1966            break;
1967        }
1968        text.try_push(character)?;
1969    }
1970    Ok(Some(text))
1971}
1972
1973/// Reads a name from an element a schema said is one.
1974///
1975/// It is public for the same reason as [`crate::algorithm::read`]: a signed
1976/// message names a signer by the issuer name of its certificate, and comparing
1977/// that against a certificate requires both to have been read by the same
1978/// rules. A second reader would be a second answer to which encodings of a
1979/// name are the same name.
1980///
1981/// # Errors
1982///
1983/// Reports the encoding fault and the field it was in.
1984pub fn read<'a>(
1985    parent: &Reader<'a>,
1986    element: &Element<'a>,
1987    field: &'static str,
1988) -> Result<Name<'a>> {
1989    let fail = |code| Error::new(code, field, element.span().start);
1990
1991    if element.tag() != Tag::constructed(universal::SEQUENCE) {
1992        return Err(fail(ErrorCode::Encoding(
1993            structured_asn1::ErrorCode::UnexpectedTag,
1994        )));
1995    }
1996
1997    let mut sequence = parent.enter(element).field(field)?;
1998    let mut parts = parent.memory().vector();
1999
2000    while let Some(part) = sequence.next_element().field(field)? {
2001        if part.tag() != Tag::constructed(universal::SET) {
2002            return Err(Error::new(
2003                ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
2004                field,
2005                part.span().start,
2006            ));
2007        }
2008        parts
2009            .try_push(read_relative(&sequence, &part, field)?)
2010            .map_err(|reason| Error::resource(reason, field, part.span().start))?;
2011    }
2012
2013    Ok(Name {
2014        der: element.as_bytes(),
2015        parts,
2016        offset: element.span().start,
2017        field,
2018    })
2019}
2020
2021/// Reads one part of a name, which a distribution point carries on its own.
2022///
2023/// The tag belongs to the caller: here it is the set the schema names, and in
2024/// a distribution point it is the number that position gives it.
2025pub(crate) fn read_relative<'a>(
2026    parent: &Reader<'a>,
2027    element: &Element<'a>,
2028    field: &'static str,
2029) -> Result<RelativeName<'a>> {
2030    let fail = |code| Error::new(code, field, element.span().start);
2031
2032    let mut inside = parent.enter(element).field(field)?;
2033    let mut attributes = parent.memory().vector();
2034    let mut previous: Option<&[u8]> = None;
2035    while let Some(pair) = inside.next_element().field(field)? {
2036        // DER orders the members of a set by their encodings, ascending, and
2037        // the comparison of names deliberately ignores order. Without this
2038        // check an unsorted part would match a correctly sorted one, and a
2039        // malformed issuer could take part in a path. The comparison walks
2040        // up to the longer encoding, so that length is charged to the
2041        // shared work budget before the walk: a caller bounding work sees
2042        // two huge common-prefix members on the same meter the reads use.
2043        if inside.encoding().is_der()
2044            && let Some(previous) = previous
2045            && {
2046                inside
2047                    .charge(previous.len().max(pair.as_bytes().len()) as u64)
2048                    .field(field)?;
2049                !der_set_ordered(previous, pair.as_bytes())
2050            }
2051        {
2052            return Err(Error::new(
2053                ErrorCode::MalformedValue,
2054                field,
2055                pair.span().start,
2056            ));
2057        }
2058        previous = Some(pair.as_bytes());
2059        attributes
2060            .try_push(read_attribute(&inside, &pair, field)?)
2061            .map_err(|reason| Error::resource(reason, field, pair.span().start))?;
2062    }
2063
2064    // A part with nothing in it names nothing, and two names that differ only
2065    // by one of these would compare as different names.
2066    if attributes.is_empty() {
2067        return Err(fail(ErrorCode::EmptySequence));
2068    }
2069
2070    Ok(RelativeName { attributes })
2071}
2072
2073fn read_attribute<'a>(
2074    parent: &Reader<'a>,
2075    element: &Element<'a>,
2076    field: &'static str,
2077) -> Result<Attribute<'a>> {
2078    let fail = |code| Error::new(code, field, element.span().start);
2079
2080    if element.tag() != Tag::constructed(universal::SEQUENCE) {
2081        return Err(fail(ErrorCode::Encoding(
2082            structured_asn1::ErrorCode::UnexpectedTag,
2083        )));
2084    }
2085
2086    let mut pair = parent.enter(element).field(field)?;
2087    let kind = pair.read_oid().field(field)?;
2088    let value = pair
2089        .next_element()
2090        .field(field)?
2091        .ok_or_else(|| fail(ErrorCode::MissingField))?;
2092
2093    // Even an unknown kind's opaque value must be DER before it is
2094    // preserved: what is kept here is compared against the same attribute in
2095    // another certificate, and a second spelling of one value would be a
2096    // different name for the same holder.
2097    walk_der(&pair, &value, field, Strings::AsWritten)?;
2098
2099    if !pair.is_empty() {
2100        return Err(fail(ErrorCode::TrailingData));
2101    }
2102
2103    Ok(Attribute {
2104        kind,
2105        value: AttributeValue {
2106            tag: value.tag(),
2107            contents: value.contents(),
2108            der: value.as_bytes(),
2109            offset: value.span().start,
2110        },
2111    })
2112}
2113
2114#[cfg(test)]
2115mod tests;