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