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