Skip to main content

structured_pkix/
general_name.rs

1//! The several kinds of name an extension can carry.
2//!
3//! Some of these are locations: a distribution point, a status service, a
4//! practice statement. They are read as text and nothing here resolves one. A
5//! parser that fetched a location a document named would be asking a server
6//! chosen by whoever wrote the document to confirm what the document says, and
7//! would tell that server which document is being looked at.
8
9use crate::error::{Error, ErrorCode, Located, Result};
10use crate::extension::{self, Extension};
11use crate::name::{self, Name};
12use core::net::{Ipv4Addr, Ipv6Addr};
13use structured_asn1::memory::{Memory, OwnedVec};
14use structured_asn1::{Class, Element, Oid, Reader, Tag, universal};
15
16/// One name, in whichever of the forms the schema allows.
17#[derive(Debug)]
18#[non_exhaustive]
19pub enum GeneralName<'a> {
20    /// A form defined elsewhere, kept as its identifier and its value.
21    Other {
22        /// What kind of name this is.
23        type_id: Oid<'a>,
24        /// The value, as it was encoded.
25        value: &'a [u8],
26    },
27    /// An electronic mail address.
28    Email(&'a str),
29    /// A domain name.
30    Dns(&'a str),
31    /// An X.400 address, kept as encoded because nothing here reads one.
32    X400(&'a [u8]),
33    /// A distinguished name, the same kind a certificate's subject is.
34    Directory(Name<'a>),
35    /// An EDI party name, kept as encoded.
36    EdiParty(&'a [u8]),
37    /// A location, which is text and is never fetched.
38    Uri(&'a str),
39    /// An address, as the four or sixteen bytes it is written in. In a name
40    /// constraint this is twice that, the address and then its mask.
41    IpAddress(&'a [u8]),
42    /// A name that is itself an identifier.
43    RegisteredId(Oid<'a>),
44}
45
46/// Reads a sequence of names.
47pub(crate) fn read_all<'a>(
48    parent: &Reader<'a>,
49    element: &Element<'a>,
50    field: &'static str,
51) -> Result<OwnedVec<GeneralName<'a>>> {
52    let mut inside = parent.enter(element).field(field)?;
53    read_list(&mut inside, field, element.span().start)
54}
55
56/// Reads the names of a container already entered.
57pub(crate) fn read_list<'a>(
58    inside: &mut Reader<'a>,
59    field: &'static str,
60    offset: u64,
61) -> Result<OwnedVec<GeneralName<'a>>> {
62    let mut names = inside.memory().vector();
63    while let Some(entry) = inside.next_element().field(field)? {
64        names
65            .try_push(read(inside, &entry, field)?)
66            .map_err(|reason| Error::resource(reason, field, entry.span().start))?;
67    }
68
69    // A list of names that holds none says nothing while claiming to, and the
70    // schema asks for at least one everywhere this is used.
71    if names.is_empty() {
72        return Err(Error::new(ErrorCode::EmptySequence, field, offset));
73    }
74    Ok(names)
75}
76
77/// Reads the value of an alternative name extension, which is a list of names
78/// and nothing else.
79pub fn read_alternative<'a>(
80    extension: &Extension<'a>,
81    execution: &Memory,
82) -> Result<OwnedVec<GeneralName<'a>>> {
83    let field = if extension.kind() == crate::oid::ISSUER_ALT_NAME {
84        "extensions.issuerAltName"
85    } else {
86        "extensions.subjectAltName"
87    };
88
89    let mut inside = extension::sequence(extension, field, execution)?;
90    read_list(&mut inside, field, extension.span().start)
91}
92
93/// Where a name sits, which decides which forms its fields take.
94///
95/// The same tags carry different forms in the two positions: an address is
96/// bare in a list of names and paired with its mask in a name-constraint
97/// subtree, and a mail or location constraint may name a host or a domain
98/// where a name must be a mailbox or a URI. Only the position says which.
99#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100pub(crate) enum AddressForm {
101    /// A name in a list of names: a bare address, a mailbox, a URI.
102    Single,
103    /// The base of a name-constraint subtree: an address with its mask, and
104    /// the host and domain forms of a mail or location constraint.
105    WithMask,
106}
107
108impl AddressForm {
109    fn permits(self, length: usize) -> bool {
110        match self {
111            Self::Single => length == 4 || length == 16,
112            Self::WithMask => length == 8 || length == 32,
113        }
114    }
115}
116
117/// Reads one name from the element whose tag says which kind it is.
118///
119/// The parent must be the reader that produced the element: decoding retains
120/// its shared budget, depth and offsets. This also serves names outside
121/// certificates, such as RFC 3161 §2.4.2's timestamp `tsa` field.
122/// <https://www.rfc-editor.org/rfc/rfc3161#section-2.4.2>
123///
124/// # Errors
125///
126/// Reports malformed name syntax, encoding faults and exhausted limits.
127pub fn read<'a>(
128    parent: &Reader<'a>,
129    element: &Element<'a>,
130    field: &'static str,
131) -> Result<GeneralName<'a>> {
132    read_as(parent, element, field, AddressForm::Single)
133}
134
135/// Whether text is the mail form the position takes.
136///
137/// A name is a mailbox (RFC 5280 4.2.1.6). A constraint may also name every
138/// mailbox at a host, or every mailbox in a domain by a leading period
139/// (4.2.1.10).
140fn mailbox_fits(text: &str, address_form: AddressForm) -> bool {
141    match address_form {
142        AddressForm::Single => is_mailbox(text),
143        AddressForm::WithMask => {
144            is_mailbox(text) || is_domain(text) || text.strip_prefix('.').is_some_and(is_domain)
145        }
146    }
147}
148
149/// Whether text is the domain form the position takes.
150///
151/// A name holds the preferred name syntax (RFC 5280 4.2.1.6, via RFC 1034
152/// 3.5 as modified by RFC 1123): a value that is merely ASCII is not yet a
153/// domain, and reporting one would put an identity in the report the
154/// certificate does not carry.
155///
156/// A subtree base is written the same way, with one addition the profile
157/// does not spell out here. It writes a domain-name restriction as a name
158/// further labels are added to the left of (4.2.1.10), and gives the leading
159/// period to the mail and location forms in the two paragraphs above that
160/// one. It does not say to refuse the period here; issuers write it, and the
161/// extension is critical, so refusing the value refuses the authority and
162/// every certificate under it over a spelling of the same subtree. What the
163/// period means is for the reader of the constraint to decide, and the value
164/// is preserved as written.
165fn domain_fits(text: &str, address_form: AddressForm) -> bool {
166    match address_form {
167        AddressForm::Single => is_domain(text),
168        AddressForm::WithMask => is_domain(text) || text.strip_prefix('.').is_some_and(is_domain),
169    }
170}
171
172pub(crate) fn read_as<'a>(
173    parent: &Reader<'a>,
174    element: &Element<'a>,
175    field: &'static str,
176    address_form: AddressForm,
177) -> Result<GeneralName<'a>> {
178    let fail = |code| Error::new(code, field, element.span().start);
179    let tag = element.tag();
180
181    if tag.class() != Class::ContextSpecific {
182        return Err(fail(ErrorCode::Encoding(
183            structured_asn1::ErrorCode::UnexpectedTag,
184        )));
185    }
186
187    // The tag says which kind of name this is, and whether the value is a
188    // structure or a string. A string written as a structure is the segmented
189    // form, which is a second spelling of one value and is not read here. A
190    // number this reader does not name is none of the nine forms, and falls
191    // to the same refusal as a number it names that this schema does not
192    // have.
193    let Some(number) = tag.number() else {
194        return Err(fail(ErrorCode::Encoding(
195            structured_asn1::ErrorCode::UnexpectedTag,
196        )));
197    };
198    match (number, tag.is_constructed()) {
199        (0, true) => read_other(parent, element, field),
200        (1, false) => {
201            let email = text(parent, element.contents(), field, element)?;
202            if !mailbox_fits(email, address_form) {
203                return Err(fail(ErrorCode::MalformedValue));
204            }
205            Ok(GeneralName::Email(email))
206        }
207        (2, false) => {
208            let domain = text(parent, element.contents(), field, element)?;
209            if !domain_fits(domain, address_form) {
210                return Err(fail(ErrorCode::MalformedValue));
211            }
212            Ok(GeneralName::Dns(domain))
213        }
214        (3, true) => {
215            read_x400(parent, element, field)?;
216            Ok(GeneralName::X400(element.contents()))
217        }
218        (4, true) => {
219            // The name it holds is a choice, which cannot take the tag of its
220            // position, so the tag wraps it rather than replacing it.
221            let mut inside = parent.enter(element).field(field)?;
222            let inner = inside
223                .next_element()
224                .field(field)?
225                .ok_or_else(|| fail(ErrorCode::MissingField))?;
226            let name = name::read(&inside, &inner, field)?;
227            // An empty name is legal as a certificate's subject, where the
228            // alternative name carries the identity instead. As a general
229            // name it IS the identity, and empty it names nobody; as a
230            // subtree base it is the root, under which every directory name
231            // sits, so only the identity-bearing position refuses it. Every
232            // attribute of a kind this crate names must be written inside
233            // its syntax either way: an identity this run never read must
234            // not read as a supplied one. Unknown kinds stay data.
235            //
236            // The walk touches every attribute's contents, and a kind whose
237            // schema leaves the size unbounded has no local ceiling, so the
238            // lengths are charged to the shared work budget before it runs.
239            if address_form == AddressForm::Single && name.is_empty() {
240                return Err(fail(ErrorCode::MalformedValue));
241            }
242            for attribute in name.attributes() {
243                if !name::well_formed_in(attribute, &inside, field)? {
244                    return Err(fail(ErrorCode::MalformedValue));
245                }
246            }
247            if !inside.is_empty() {
248                return Err(fail(ErrorCode::TrailingData));
249            }
250            Ok(GeneralName::Directory(name))
251        }
252        (5, true) => {
253            read_edi_party(parent, element, field)?;
254            Ok(GeneralName::EdiParty(element.contents()))
255        }
256        (6, false) => {
257            let location = text(parent, element.contents(), field, element)?;
258            // RFC5280 §4.2.1.6 requires a scheme and forbids relative URIs.
259            // RFC3986 §3's URI includes a fragment; §4.3 absolute-URI is a
260            // distinct, fragment-free production, not the SAN grammar.
261            // https://www.rfc-editor.org/rfc/rfc5280.html#section-4.2.1.6
262            // https://www.rfc-editor.org/rfc/rfc3986.html#section-3
263            // A constraint
264            // applies to the host and is written as a host or a domain
265            // (4.2.1.10).
266            let fits = match address_form {
267                AddressForm::Single => {
268                    // Admit the additional fragment-delimiter scan before
269                    // selecting the existing scheme/authority semantic core.
270                    parent.charge(location.len() as u64).field(field)?;
271                    is_uri(location)
272                }
273                AddressForm::WithMask => {
274                    is_domain(location) || location.strip_prefix('.').is_some_and(is_domain)
275                }
276            };
277            if !fits {
278                return Err(fail(ErrorCode::MalformedValue));
279            }
280            Ok(GeneralName::Uri(location))
281        }
282        (7, false) => {
283            let contents = element.contents();
284            if !address_form.permits(contents.len()) {
285                return Err(fail(ErrorCode::MalformedValue));
286            }
287            // A constraint region is CIDR (RFC 5280 4.2.1.10, via RFC 4632):
288            // the mask half is leading one bits and nothing after them. A
289            // gap describes no range this profile defines.
290            if address_form == AddressForm::WithMask
291                && !is_contiguous_mask(&contents[contents.len() / 2..])
292            {
293                return Err(fail(ErrorCode::MalformedValue));
294            }
295            Ok(GeneralName::IpAddress(contents))
296        }
297        (8, false) => parent
298            .oid(element)
299            .field(field)
300            .map(GeneralName::RegisteredId),
301        _ => Err(fail(ErrorCode::Encoding(
302            structured_asn1::ErrorCode::UnexpectedTag,
303        ))),
304    }
305}
306
307/// Validates an X.400 OR-address: the mandatory built-in standard
308/// attributes, then optionally the domain-defined attributes and the
309/// extension attributes (X.411 `ORAddress`, referenced from RFC 5280
310/// appendix A). The members inside each container are validated against
311/// that schema too, because a critical name extension carrying members
312/// outside it must not read as parsed; the address as a whole still stays
313/// encoded, since nothing in this product routes to a messaging system.
314fn read_x400<'a>(parent: &Reader<'a>, element: &Element<'a>, field: &'static str) -> Result<()> {
315    let fail = |code| Error::new(code, field, element.span().start);
316
317    let mut inside = parent.enter(element).field(field)?;
318    let standard = inside
319        .next_element()
320        .field(field)?
321        .ok_or_else(|| fail(ErrorCode::MissingField))?;
322    if standard.tag() != Tag::constructed(universal::SEQUENCE) {
323        return Err(fail(ErrorCode::Encoding(
324            structured_asn1::ErrorCode::UnexpectedTag,
325        )));
326    }
327    read_standard_attributes(&inside, &standard, field)?;
328
329    // The two optional members, in order: a SEQUENCE OF, then a SET OF.
330    let mut next = inside.next_element().field(field)?;
331    if let Some(domain_defined) = next
332        && domain_defined.tag() == Tag::constructed(universal::SEQUENCE)
333    {
334        read_domain_defined(&inside, &domain_defined, field)?;
335        next = inside.next_element().field(field)?;
336    }
337    if let Some(extensions) = next {
338        if extensions.tag() != Tag::constructed(universal::SET) {
339            return Err(fail(ErrorCode::Encoding(
340                structured_asn1::ErrorCode::UnexpectedTag,
341            )));
342        }
343        read_extension_attributes(&inside, &extensions, field)?;
344        if !inside.is_empty() {
345            return Err(fail(ErrorCode::TrailingData));
346        }
347    }
348    Ok(())
349}
350
351/// The tag numbers X.411 string types carry, named here since nothing below
352/// the schema needs them.
353const X400_NUMERIC_STRING: u32 = 18;
354
355/// Requires a universal string member to be a `NumericString` or a
356/// `PrintableString`, inside its repertoire and the size the schema gives
357/// that member (X.411 via RFC 5280 appendix A, whose bounds these are).
358fn x400_string(element: &Element<'_>, field: &'static str, size: (usize, usize)) -> Result<()> {
359    let fail = |code| Error::new(code, field, element.span().start);
360    let contents = element.contents();
361    // The primitive form only: DER has no constructed spelling of these
362    // strings, and the class and number alone would let one through.
363    let fits = match (
364        element.tag().class(),
365        element.tag().number(),
366        element.tag().is_constructed(),
367    ) {
368        (Class::Universal, Some(X400_NUMERIC_STRING), false) => crate::name::is_numeric(contents),
369        (Class::Universal, Some(universal::PRINTABLE_STRING), false) => {
370            crate::name::is_printable(contents)
371        }
372        _ => {
373            return Err(fail(ErrorCode::Encoding(
374                structured_asn1::ErrorCode::UnexpectedTag,
375            )));
376        }
377    };
378    if !fits || contents.len() < size.0 || contents.len() > size.1 {
379        return Err(fail(ErrorCode::MalformedValue));
380    }
381    Ok(())
382}
383
384/// Requires a primitive `PrintableString` of the given size, refusing the
385/// numeric alternative the wider choice permits.
386fn x400_printable(element: &Element<'_>, field: &'static str, size: (usize, usize)) -> Result<()> {
387    let fail = |code| Error::new(code, field, element.span().start);
388    let tag = element.tag();
389    if tag.class() != Class::Universal
390        || tag.number() != Some(universal::PRINTABLE_STRING)
391        || tag.is_constructed()
392    {
393        return Err(fail(ErrorCode::Encoding(
394            structured_asn1::ErrorCode::UnexpectedTag,
395        )));
396    }
397    let contents = element.contents();
398    if !crate::name::is_printable(contents) || contents.len() < size.0 || contents.len() > size.1 {
399        return Err(fail(ErrorCode::MalformedValue));
400    }
401    Ok(())
402}
403
404/// Which repertoire an X.400 string member is held to. Teletex is a
405/// negotiation this crate does not implement, so only its presence and size
406/// are checkable.
407#[derive(Clone, Copy)]
408enum X400Repertoire {
409    Numeric,
410    Printable,
411    Teletex,
412}
413
414/// Requires an implicitly tagged member's contents to be one repertoire
415/// within one size, the tag having replaced the string type.
416fn x400_implicit(
417    element: &Element<'_>,
418    field: &'static str,
419    repertoire: X400Repertoire,
420    most: usize,
421) -> Result<()> {
422    let fail = |code| Error::new(code, field, element.span().start);
423    let contents = element.contents();
424    // The size is decided before the repertoire. These fields are bounded to
425    // a few dozen characters by the schema, while the element they arrive in
426    // may be as long as the parser's length limit permits: walking one to
427    // its end to learn it is digits, only to refuse it for its length, is
428    // work the caller's budget never asked for. Afterwards the walk is
429    // bounded by the schema's own ceiling.
430    if contents.is_empty() || contents.len() > most {
431        return Err(fail(ErrorCode::MalformedValue));
432    }
433    let fits = match repertoire {
434        X400Repertoire::Numeric => crate::name::is_numeric(contents),
435        X400Repertoire::Printable => crate::name::is_printable(contents),
436        X400Repertoire::Teletex => true,
437    };
438    if !fits {
439        return Err(fail(ErrorCode::MalformedValue));
440    }
441    Ok(())
442}
443
444/// Requires a universal `TeletexString` member, primitive, within one size.
445fn x400_teletex(element: &Element<'_>, field: &'static str, size: (usize, usize)) -> Result<()> {
446    let fail = |code| Error::new(code, field, element.span().start);
447    // TeletexString is tag number 20; its repertoire is a negotiation this
448    // crate does not implement, so presence and size are what is checkable.
449    if element.tag() != Tag::primitive(20) {
450        return Err(fail(ErrorCode::Encoding(
451            structured_asn1::ErrorCode::UnexpectedTag,
452        )));
453    }
454    let length = element.contents().len();
455    if length < size.0 || length > size.1 {
456        return Err(fail(ErrorCode::MalformedValue));
457    }
458    Ok(())
459}
460
461/// Requires a bare country choice: an X.121 DCC of exactly three digits, or
462/// an ISO 3166 alpha-2 code of exactly two uppercase letters. The wider
463/// repertoires of the string types name no country.
464fn x400_bare_country(value: &Element<'_>, field: &'static str) -> Result<()> {
465    let fail = |code| Error::new(code, field, value.span().start);
466    let contents = value.contents();
467    let fits = match (
468        value.tag().class(),
469        value.tag().number(),
470        value.tag().is_constructed(),
471    ) {
472        (Class::Universal, Some(X400_NUMERIC_STRING), false) => {
473            contents.len() == 3 && contents.iter().all(u8::is_ascii_digit)
474        }
475        (Class::Universal, Some(universal::PRINTABLE_STRING), false) => {
476            contents.len() == 2 && contents.iter().all(u8::is_ascii_uppercase)
477        }
478        _ => {
479            return Err(fail(ErrorCode::Encoding(
480                structured_asn1::ErrorCode::UnexpectedTag,
481            )));
482        }
483    };
484    if !fits {
485        return Err(fail(ErrorCode::MalformedValue));
486    }
487    Ok(())
488}
489
490/// Requires a wrapper to hold exactly one country choice.
491fn x400_country<'a>(parent: &Reader<'a>, wrapper: &Element<'a>, field: &'static str) -> Result<()> {
492    let fail = |code| Error::new(code, field, wrapper.span().start);
493    let mut inside = parent.enter(wrapper).field(field)?;
494    let value = inside
495        .next_element()
496        .field(field)?
497        .ok_or_else(|| fail(ErrorCode::MissingField))?;
498    if !inside.is_empty() {
499        return Err(fail(ErrorCode::TrailingData));
500    }
501    x400_bare_country(&value, field)
502}
503
504/// Requires a wrapper to hold exactly one string of a two-way choice, sized
505/// as the schema sizes each side of that choice.
506fn x400_choice<'a>(
507    parent: &Reader<'a>,
508    wrapper: &Element<'a>,
509    field: &'static str,
510    numeric: (usize, usize),
511    printable: (usize, usize),
512) -> Result<()> {
513    let fail = |code| Error::new(code, field, wrapper.span().start);
514    let mut inside = parent.enter(wrapper).field(field)?;
515    let value = inside
516        .next_element()
517        .field(field)?
518        .ok_or_else(|| fail(ErrorCode::MissingField))?;
519    if !inside.is_empty() {
520        return Err(fail(ErrorCode::TrailingData));
521    }
522    let size = match (value.tag().class(), value.tag().number()) {
523        (Class::Universal, Some(X400_NUMERIC_STRING)) => numeric,
524        (Class::Universal, Some(universal::PRINTABLE_STRING)) => printable,
525        _ => {
526            return Err(fail(ErrorCode::Encoding(
527                structured_asn1::ErrorCode::UnexpectedTag,
528            )));
529        }
530    };
531    x400_string(&value, field, size)
532}
533
534/// The members X.411 gives the built-in standard attributes, each optional,
535/// each at most once, in schema order, with the strings held to their
536/// repertoires and the appendix's upper bounds.
537fn read_standard_attributes<'a>(
538    parent: &Reader<'a>,
539    element: &Element<'a>,
540    field: &'static str,
541) -> Result<()> {
542    let mut inside = parent.enter(element).field(field)?;
543    let mut last_rank = -1i8;
544    while let Some(member) = inside.next_element().field(field)? {
545        let bad = |code| Error::new(code, field, member.span().start);
546        let tag = member.tag();
547        // A number this reader does not name is no member of the structure,
548        // and falls to the same refusal as any other number it does not have.
549        let Some(number) = tag.number() else {
550            return Err(bad(ErrorCode::Encoding(
551                structured_asn1::ErrorCode::UnexpectedTag,
552            )));
553        };
554        let rank: i8 = match (tag.class(), number, tag.is_constructed()) {
555            // The country: exactly a three-digit or a two-letter code,
556            // wrapped because a choice keeps its own tag.
557            (Class::Application, 1, true) => {
558                x400_country(&inside, &member, field)?;
559                0
560            }
561            // The administration domain: the same choice, up to sixteen
562            // characters, empty naming the default domain.
563            (Class::Application, 2, true) => {
564                x400_choice(&inside, &member, field, (0, 16), (0, 16))?;
565                1
566            }
567            // network-address: an X.121 address of up to sixteen digits.
568            (Class::ContextSpecific, 0, false) => {
569                x400_implicit(&member, field, X400Repertoire::Numeric, 16)?;
570                2
571            }
572            // terminal-identifier.
573            (Class::ContextSpecific, 1, false) => {
574                x400_implicit(&member, field, X400Repertoire::Printable, 24)?;
575                3
576            }
577            // private-domain-name: the numeric-or-printable choice again.
578            (Class::ContextSpecific, 2, true) => {
579                x400_choice(&inside, &member, field, (1, 16), (1, 16))?;
580                4
581            }
582            // organization-name.
583            (Class::ContextSpecific, 3, false) => {
584                x400_implicit(&member, field, X400Repertoire::Printable, 64)?;
585                5
586            }
587            // numeric-user-identifier.
588            (Class::ContextSpecific, 4, false) => {
589                x400_implicit(&member, field, X400Repertoire::Numeric, 32)?;
590                6
591            }
592            // personal-name: a set of up to four parts, the surname required.
593            (Class::ContextSpecific, 5, true) => {
594                read_personal_name(&inside, &member, field, X400Repertoire::Printable)?;
595                7
596            }
597            // organizational-unit-names: one to four unit names, each a
598            // PrintableString alone, unlike the explicit numeric-or-printable
599            // choices elsewhere in the address.
600            (Class::ContextSpecific, 6, true) => {
601                let mut units = inside.enter(&member).field(field)?;
602                let mut count = 0usize;
603                while let Some(unit) = units.next_element().field(field)? {
604                    x400_printable(&unit, field, (1, 32))?;
605                    count += 1;
606                }
607                if !(1..=4).contains(&count) {
608                    return Err(bad(ErrorCode::MalformedValue));
609                }
610                8
611            }
612            _ => {
613                return Err(bad(ErrorCode::Encoding(
614                    structured_asn1::ErrorCode::UnexpectedTag,
615                )));
616            }
617        };
618        // Each member appears at most once, in the order the schema writes
619        // them; a repeat or a step backwards is a second spelling of the
620        // structure.
621        if rank <= last_rank {
622            return Err(bad(ErrorCode::UnexpectedField));
623        }
624        last_rank = rank;
625    }
626    Ok(())
627}
628
629/// The personal name of X.411: up to four parts, each at most once, the
630/// surname required. The built-in form holds printable parts; the teletex
631/// extension attribute holds the same shape in teletex strings.
632fn read_personal_name<'a>(
633    parent: &Reader<'a>,
634    element: &Element<'a>,
635    field: &'static str,
636    repertoire: X400Repertoire,
637) -> Result<()> {
638    let fail = |code| Error::new(code, field, element.span().start);
639    let mut inside = parent.enter(element).field(field)?;
640    let mut seen = [false; 4];
641    let mut last: Option<usize> = None;
642    while let Some(part) = inside.next_element().field(field)? {
643        let bad = |code| Error::new(code, field, part.span().start);
644        let (number, most) = match (
645            part.tag().class(),
646            part.tag().number(),
647            part.tag().is_constructed(),
648        ) {
649            (Class::ContextSpecific, Some(0), false) => (0usize, 40),
650            (Class::ContextSpecific, Some(1), false) => (1, 16),
651            (Class::ContextSpecific, Some(2), false) => (2, 5),
652            (Class::ContextSpecific, Some(3), false) => (3, 3),
653            _ => {
654                return Err(bad(ErrorCode::Encoding(
655                    structured_asn1::ErrorCode::UnexpectedTag,
656                )));
657            }
658        };
659        if seen[number] {
660            return Err(bad(ErrorCode::UnexpectedField));
661        }
662        // A SET's distinct tags come in canonical order under DER (X.690
663        // 10.3): out of order is a second spelling of one value. BER carries
664        // no such rule.
665        if inside.encoding().is_der() && last.is_some_and(|last| number < last) {
666            return Err(bad(ErrorCode::UnexpectedField));
667        }
668        seen[number] = true;
669        last = Some(number);
670        x400_implicit(&part, field, repertoire, most)?;
671    }
672    if !seen[0] {
673        return Err(fail(ErrorCode::MissingField));
674    }
675    Ok(())
676}
677
678/// The domain-defined attributes of X.411: one to four pairs of a type and a
679/// value, each a printable string.
680fn read_domain_defined<'a>(
681    parent: &Reader<'a>,
682    element: &Element<'a>,
683    field: &'static str,
684) -> Result<()> {
685    read_defined_pairs(parent, element, field, false)
686}
687
688/// One to four pairs of a type and a value: printable strings in the
689/// built-in form, teletex strings in the teletex extension attribute.
690fn read_defined_pairs<'a>(
691    parent: &Reader<'a>,
692    element: &Element<'a>,
693    field: &'static str,
694    teletex: bool,
695) -> Result<()> {
696    let fail = |code| Error::new(code, field, element.span().start);
697    if element.tag() != Tag::constructed(universal::SEQUENCE) {
698        return Err(fail(ErrorCode::Encoding(
699            structured_asn1::ErrorCode::UnexpectedTag,
700        )));
701    }
702    let held_string = |element: &Element<'_>, size: (usize, usize)| {
703        if teletex {
704            x400_teletex(element, field, size)
705        } else {
706            // The built-in pair holds PrintableString in both members; the
707            // numeric encoding belongs to other positions of the address.
708            x400_printable(element, field, size)
709        }
710    };
711    let mut inside = parent.enter(element).field(field)?;
712    let mut count = 0usize;
713    while let Some(pair) = inside.next_element().field(field)? {
714        let bad = |code| Error::new(code, field, pair.span().start);
715        if pair.tag() != Tag::constructed(universal::SEQUENCE) {
716            return Err(bad(ErrorCode::Encoding(
717                structured_asn1::ErrorCode::UnexpectedTag,
718            )));
719        }
720        let mut two = inside.enter(&pair).field(field)?;
721        let kind = two
722            .next_element()
723            .field(field)?
724            .ok_or_else(|| bad(ErrorCode::MissingField))?;
725        held_string(&kind, (1, 8))?;
726        let value = two
727            .next_element()
728            .field(field)?
729            .ok_or_else(|| bad(ErrorCode::MissingField))?;
730        held_string(&value, (1, 128))?;
731        if !two.is_empty() {
732            return Err(bad(ErrorCode::TrailingData));
733        }
734        count += 1;
735    }
736    if !(1..=4).contains(&count) {
737        return Err(fail(ErrorCode::MalformedValue));
738    }
739    Ok(())
740}
741
742/// The extension attributes of X.411: each an identifying number and an
743/// explicitly wrapped value that number defines, decoded by that number
744/// below.
745fn read_extension_attributes<'a>(
746    parent: &Reader<'a>,
747    element: &Element<'a>,
748    field: &'static str,
749) -> Result<()> {
750    let fail = |code| Error::new(code, field, element.span().start);
751    let mut inside = parent.enter(element).field(field)?;
752    let mut count = 0usize;
753    let mut previous: Option<&[u8]> = None;
754    while let Some(entry) = inside.next_element().field(field)? {
755        let bad = |code| Error::new(code, field, entry.span().start);
756        if entry.tag() != Tag::constructed(universal::SEQUENCE) {
757            return Err(bad(ErrorCode::Encoding(
758                structured_asn1::ErrorCode::UnexpectedTag,
759            )));
760        }
761        // A SET OF, whose members DER writes in ascending encoded order
762        // (X.690 11.6): out of order is a second spelling of one value. BER
763        // carries no such rule. The comparison walks up to the longer
764        // encoding before either member is decoded, so that length is
765        // charged to the shared work budget first.
766        if inside.encoding().is_der()
767            && let Some(previous) = previous
768        {
769            inside
770                .charge(previous.len().max(entry.as_bytes().len()) as u64)
771                .field(field)?;
772            if entry.as_bytes() < previous {
773                return Err(bad(ErrorCode::UnexpectedField));
774            }
775        }
776        previous = Some(entry.as_bytes());
777        let mut two = inside.enter(&entry).field(field)?;
778        let kind = two
779            .next_element()
780            .field(field)?
781            .ok_or_else(|| bad(ErrorCode::MissingField))?;
782        // The number wears its position's tag; the decoding helper is
783        // tag-agnostic, which is exactly right for an implicit field, but the
784        // position is required first. The schema bounds it to 0..=256.
785        if extension::context_of(kind.tag()) != Some((0, false)) {
786            return Err(bad(ErrorCode::Encoding(
787                structured_asn1::ErrorCode::UnexpectedTag,
788            )));
789        }
790        let number = two.integer(&kind).field(field)?;
791        if number.as_u32().is_none_or(|number| number > 256) {
792            return Err(bad(ErrorCode::MalformedValue));
793        }
794        let value = two
795            .next_element()
796            .field(field)?
797            .ok_or_else(|| bad(ErrorCode::MissingField))?;
798        // The value is wrapped explicitly, because what it is depends on the
799        // number before it. It holds exactly one value, kept encoded.
800        if extension::context_of(value.tag()) != Some((1, true)) {
801            return Err(bad(ErrorCode::Encoding(
802                structured_asn1::ErrorCode::UnexpectedTag,
803            )));
804        }
805        let mut held = two.enter(&value).field(field)?;
806        let Some(declared) = held.next_element().field(field)? else {
807            return Err(bad(ErrorCode::MissingField));
808        };
809        // The number declares the value's syntax, so the value is decoded by
810        // it: an attribute wearing a number whose syntax it does not have was
811        // never decoded, and a critical name built on one must not read as
812        // parsed.
813        let number = number
814            .as_u32()
815            .expect("bounded to 0..=256 above, which fits");
816        read_extension_value(&held, &declared, number, field)?;
817        if !held.is_empty() || !two.is_empty() {
818            return Err(bad(ErrorCode::TrailingData));
819        }
820        count += 1;
821        // ub-extension-attributes bounds the set at 256 members (RFC 5280
822        // appendix A); a 257th puts the address outside the schema.
823        if count > 256 {
824            return Err(bad(ErrorCode::MalformedValue));
825        }
826    }
827    if count == 0 {
828        return Err(fail(ErrorCode::EmptySequence));
829    }
830    Ok(())
831}
832
833/// The value an extension attribute declares, decoded by the number before
834/// it: the syntaxes RFC 5280 appendix A gives the numbers it defines, with
835/// that module's size bounds. A number the appendix does not define is a
836/// value this crate cannot decode, and a name built on one must not read as
837/// parsed.
838fn read_extension_value<'a>(
839    parent: &Reader<'a>,
840    value: &Element<'a>,
841    number: u32,
842    field: &'static str,
843) -> Result<()> {
844    let fail = |code| Error::new(code, field, value.span().start);
845    match number {
846        // common-name: PrintableString alone, unlike the explicit
847        // numeric-or-printable choices elsewhere in the address.
848        1 => x400_printable(value, field, (1, 64)),
849        // teletex-common-name and teletex-organization-name.
850        2 | 3 => x400_teletex(value, field, (1, 64)),
851        // teletex-personal-name: the personal-name shape in teletex strings.
852        4 => {
853            if value.tag() != Tag::constructed(universal::SET) {
854                return Err(fail(ErrorCode::Encoding(
855                    structured_asn1::ErrorCode::UnexpectedTag,
856                )));
857            }
858            read_personal_name(parent, value, field, X400Repertoire::Teletex)
859        }
860        // teletex-organizational-unit-names: one to four unit names.
861        5 => {
862            if value.tag() != Tag::constructed(universal::SEQUENCE) {
863                return Err(fail(ErrorCode::Encoding(
864                    structured_asn1::ErrorCode::UnexpectedTag,
865                )));
866            }
867            let mut units = parent.enter(value).field(field)?;
868            let mut count = 0usize;
869            while let Some(unit) = units.next_element().field(field)? {
870                x400_teletex(&unit, field, (1, 32))?;
871                count += 1;
872            }
873            if !(1..=4).contains(&count) {
874                return Err(fail(ErrorCode::MalformedValue));
875            }
876            Ok(())
877        }
878        // teletex-domain-defined-attributes: the pairs again, in teletex.
879        6 => read_defined_pairs(parent, value, field, true),
880        // pds-name: PrintableString alone.
881        7 => x400_printable(value, field, (1, 16)),
882        // physical-delivery-country-name: exactly a three-digit or a
883        // two-letter code, the choice bare in this position.
884        8 => x400_bare_country(value, field),
885        // postal-code.
886        9 => x400_bare_choice(value, field, (1, 16), (1, 16)),
887        // The postal-delivery parameters, one shape under many numbers: an
888        // optional printable and an optional teletex string.
889        10..=15 | 17..=21 => read_pds_parameter(parent, value, field, 30),
890        // unformatted-postal-address.
891        16 => read_unformatted_address(parent, value, field),
892        // extended-network-address.
893        22 => read_extended_network_address(parent, value, field),
894        // terminal-type: an integer of the option table.
895        23 => {
896            if value.tag() != Tag::primitive(universal::INTEGER) {
897                return Err(fail(ErrorCode::Encoding(
898                    structured_asn1::ErrorCode::UnexpectedTag,
899                )));
900            }
901            let option = parent.integer(value).field(field)?;
902            if option.as_u32().is_none_or(|option| option > 256) {
903                return Err(fail(ErrorCode::MalformedValue));
904            }
905            Ok(())
906        }
907        _ => Err(fail(ErrorCode::MalformedValue)),
908    }
909}
910
911/// Requires a bare two-way choice: the string stands in the choice's own
912/// position, so its universal tag says which side it is.
913fn x400_bare_choice(
914    value: &Element<'_>,
915    field: &'static str,
916    numeric: (usize, usize),
917    printable: (usize, usize),
918) -> Result<()> {
919    let fail = |code| Error::new(code, field, value.span().start);
920    let size = match (
921        value.tag().class(),
922        value.tag().number(),
923        value.tag().is_constructed(),
924    ) {
925        (Class::Universal, Some(X400_NUMERIC_STRING), false) => numeric,
926        (Class::Universal, Some(universal::PRINTABLE_STRING), false) => printable,
927        _ => {
928            return Err(fail(ErrorCode::Encoding(
929                structured_asn1::ErrorCode::UnexpectedTag,
930            )));
931        }
932    };
933    x400_string(value, field, size)
934}
935
936/// The postal-delivery parameter of X.411: an optional printable and an
937/// optional teletex string, each at most once, each within one size.
938fn read_pds_parameter<'a>(
939    parent: &Reader<'a>,
940    value: &Element<'a>,
941    field: &'static str,
942    most: usize,
943) -> Result<()> {
944    let fail = |code| Error::new(code, field, value.span().start);
945    if value.tag() != Tag::constructed(universal::SET) {
946        return Err(fail(ErrorCode::Encoding(
947            structured_asn1::ErrorCode::UnexpectedTag,
948        )));
949    }
950    let mut inside = parent.enter(value).field(field)?;
951    let mut seen_printable = false;
952    let mut seen_teletex = false;
953    while let Some(member) = inside.next_element().field(field)? {
954        let bad = |code| Error::new(code, field, member.span().start);
955        if member.tag() == Tag::primitive(universal::PRINTABLE_STRING) {
956            // A SET's distinct tags come in canonical order under DER
957            // (X.690 10.3): the printable tag sorts before the teletex one,
958            // so arriving after it is a second spelling of one value. BER
959            // carries no such rule.
960            if seen_printable || (seen_teletex && inside.encoding().is_der()) {
961                return Err(bad(ErrorCode::UnexpectedField));
962            }
963            seen_printable = true;
964            x400_string(&member, field, (1, most))?;
965        } else if member.tag() == Tag::primitive(20) {
966            if seen_teletex {
967                return Err(bad(ErrorCode::UnexpectedField));
968            }
969            seen_teletex = true;
970            x400_teletex(&member, field, (1, most))?;
971        } else {
972            return Err(bad(ErrorCode::Encoding(
973                structured_asn1::ErrorCode::UnexpectedTag,
974            )));
975        }
976    }
977    Ok(())
978}
979
980/// The unformatted postal address of X.411: up to six printable lines and
981/// an optional teletex rendering, each part at most once.
982fn read_unformatted_address<'a>(
983    parent: &Reader<'a>,
984    value: &Element<'a>,
985    field: &'static str,
986) -> Result<()> {
987    let fail = |code| Error::new(code, field, value.span().start);
988    if value.tag() != Tag::constructed(universal::SET) {
989        return Err(fail(ErrorCode::Encoding(
990            structured_asn1::ErrorCode::UnexpectedTag,
991        )));
992    }
993    let mut inside = parent.enter(value).field(field)?;
994    let mut seen_lines = false;
995    let mut seen_teletex = false;
996    while let Some(member) = inside.next_element().field(field)? {
997        let bad = |code| Error::new(code, field, member.span().start);
998        if member.tag() == Tag::constructed(universal::SEQUENCE) {
999            // A SET's distinct tags come in canonical order under DER
1000            // (X.690 10.3): the SEQUENCE tag sorts before the teletex one,
1001            // so arriving after it is a second spelling of one value. BER
1002            // carries no such rule.
1003            if seen_lines || (seen_teletex && inside.encoding().is_der()) {
1004                return Err(bad(ErrorCode::UnexpectedField));
1005            }
1006            seen_lines = true;
1007            let mut lines = inside.enter(&member).field(field)?;
1008            let mut count = 0usize;
1009            while let Some(line) = lines.next_element().field(field)? {
1010                // Every line of the printable address is a PrintableString;
1011                // the numeric alternative belongs to other positions.
1012                x400_printable(&line, field, (1, 30))?;
1013                count += 1;
1014            }
1015            if !(1..=6).contains(&count) {
1016                return Err(bad(ErrorCode::MalformedValue));
1017            }
1018        } else if member.tag() == Tag::primitive(20) {
1019            if seen_teletex {
1020                return Err(bad(ErrorCode::UnexpectedField));
1021            }
1022            seen_teletex = true;
1023            x400_teletex(&member, field, (1, 180))?;
1024        } else {
1025            return Err(bad(ErrorCode::Encoding(
1026                structured_asn1::ErrorCode::UnexpectedTag,
1027            )));
1028        }
1029    }
1030    Ok(())
1031}
1032
1033/// The E.163/E.164 alternative: a number and an optional sub-address.
1034fn read_e163_address<'a>(
1035    parent: &Reader<'a>,
1036    value: &Element<'a>,
1037    field: &'static str,
1038) -> Result<()> {
1039    let fail = |code| Error::new(code, field, value.span().start);
1040    let mut inside = parent.enter(value).field(field)?;
1041    let number = inside
1042        .next_element()
1043        .field(field)?
1044        .ok_or_else(|| fail(ErrorCode::MissingField))?;
1045    if extension::context_of(number.tag()) != Some((0, false)) {
1046        return Err(fail(ErrorCode::Encoding(
1047            structured_asn1::ErrorCode::UnexpectedTag,
1048        )));
1049    }
1050    x400_implicit(&number, field, X400Repertoire::Numeric, 15)?;
1051    if let Some(sub) = inside.next_element().field(field)? {
1052        if extension::context_of(sub.tag()) != Some((1, false)) {
1053            return Err(fail(ErrorCode::Encoding(
1054                structured_asn1::ErrorCode::UnexpectedTag,
1055            )));
1056        }
1057        x400_implicit(&sub, field, X400Repertoire::Numeric, 40)?;
1058    }
1059    if !inside.is_empty() {
1060        return Err(fail(ErrorCode::TrailingData));
1061    }
1062    Ok(())
1063}
1064
1065/// The extended network address of X.411: an E.163/E.164 number with an
1066/// optional sub-address, or a presentation address of wrapped selectors and
1067/// the mandatory network addresses.
1068fn read_extended_network_address<'a>(
1069    parent: &Reader<'a>,
1070    value: &Element<'a>,
1071    field: &'static str,
1072) -> Result<()> {
1073    let fail = |code| Error::new(code, field, value.span().start);
1074    if value.tag() == Tag::constructed(universal::SEQUENCE) {
1075        read_e163_address(parent, value, field)
1076    } else if extension::context_of(value.tag()) == Some((0, true)) {
1077        // psap-address: three optional wrapped selectors, then the mandatory
1078        // set of network addresses, each member at most once in order.
1079        let mut inside = parent.enter(value).field(field)?;
1080        let mut last: i8 = -1;
1081        let mut saw_network = false;
1082        while let Some(member) = inside.next_element().field(field)? {
1083            let bad = |code| Error::new(code, field, member.span().start);
1084            let Some((number, true)) = extension::context_of(member.tag()) else {
1085                return Err(bad(ErrorCode::Encoding(
1086                    structured_asn1::ErrorCode::UnexpectedTag,
1087                )));
1088            };
1089            let rank = i8::try_from(number).map_err(|_| {
1090                bad(ErrorCode::Encoding(
1091                    structured_asn1::ErrorCode::UnexpectedTag,
1092                ))
1093            })?;
1094            if rank > 3 {
1095                return Err(bad(ErrorCode::Encoding(
1096                    structured_asn1::ErrorCode::UnexpectedTag,
1097                )));
1098            }
1099            if rank <= last {
1100                return Err(bad(ErrorCode::UnexpectedField));
1101            }
1102            last = rank;
1103            let mut held = inside.enter(&member).field(field)?;
1104            if rank == 3 {
1105                // The network addresses: at least one octet string.
1106                let addresses = held
1107                    .next_element()
1108                    .field(field)?
1109                    .ok_or_else(|| bad(ErrorCode::MissingField))?;
1110                if addresses.tag() != Tag::constructed(universal::SET) {
1111                    return Err(bad(ErrorCode::Encoding(
1112                        structured_asn1::ErrorCode::UnexpectedTag,
1113                    )));
1114                }
1115                let mut each = held.enter(&addresses).field(field)?;
1116                let mut count = 0usize;
1117                let mut previous: Option<&[u8]> = None;
1118                while let Some(address) = each.next_element().field(field)? {
1119                    if address.tag() != Tag::primitive(universal::OCTET_STRING) {
1120                        return Err(bad(ErrorCode::Encoding(
1121                            structured_asn1::ErrorCode::UnexpectedTag,
1122                        )));
1123                    }
1124                    // A SET OF, whose members DER writes in ascending
1125                    // encoded order (X.690 11.6): out of order is a second
1126                    // spelling of one value. BER carries no such rule. The
1127                    // comparison walks up to the longer encoding, so that
1128                    // length is charged to the shared work budget first.
1129                    if each.encoding().is_der()
1130                        && let Some(previous) = previous
1131                    {
1132                        each.charge(previous.len().max(address.as_bytes().len()) as u64)
1133                            .field(field)?;
1134                        if address.as_bytes() < previous {
1135                            return Err(bad(ErrorCode::UnexpectedField));
1136                        }
1137                    }
1138                    previous = Some(address.as_bytes());
1139                    count += 1;
1140                }
1141                if count == 0 {
1142                    return Err(bad(ErrorCode::EmptySequence));
1143                }
1144                saw_network = true;
1145            } else {
1146                // A selector: one wrapped octet string.
1147                let selector = held
1148                    .next_element()
1149                    .field(field)?
1150                    .ok_or_else(|| bad(ErrorCode::MissingField))?;
1151                if selector.tag() != Tag::primitive(universal::OCTET_STRING) {
1152                    return Err(bad(ErrorCode::Encoding(
1153                        structured_asn1::ErrorCode::UnexpectedTag,
1154                    )));
1155                }
1156            }
1157            if !held.is_empty() {
1158                return Err(bad(ErrorCode::TrailingData));
1159            }
1160        }
1161        if !saw_network {
1162            return Err(fail(ErrorCode::MissingField));
1163        }
1164        Ok(())
1165    } else {
1166        Err(fail(ErrorCode::Encoding(
1167            structured_asn1::ErrorCode::UnexpectedTag,
1168        )))
1169    }
1170}
1171
1172/// Validates an EDI party name: an optional assigner, then the mandatory
1173/// party, each an explicitly tagged wrapper holding one directory string.
1174/// The tags wrap rather than replace, because a directory string is a choice
1175/// and RFC 5280 appendix A keeps a choice's own tag.
1176fn read_edi_party<'a>(
1177    parent: &Reader<'a>,
1178    element: &Element<'a>,
1179    field: &'static str,
1180) -> Result<()> {
1181    let fail = |code| Error::new(code, field, element.span().start);
1182
1183    let mut inside = parent.enter(element).field(field)?;
1184    let mut next = inside.next_element().field(field)?;
1185
1186    if let Some(assigner) = next
1187        && extension::context_of(assigner.tag()) == Some((0, true))
1188    {
1189        require_directory_string(&inside, &assigner, field)?;
1190        next = inside.next_element().field(field)?;
1191    }
1192
1193    let party = next.ok_or_else(|| fail(ErrorCode::MissingField))?;
1194    if extension::context_of(party.tag()) != Some((1, true)) {
1195        return Err(Error::new(
1196            ErrorCode::UnexpectedField,
1197            field,
1198            party.span().start,
1199        ));
1200    }
1201    require_directory_string(&inside, &party, field)?;
1202
1203    if !inside.is_empty() {
1204        return Err(fail(ErrorCode::TrailingData));
1205    }
1206    Ok(())
1207}
1208
1209/// Requires a wrapper to hold exactly one non-empty directory string.
1210fn require_directory_string<'a>(
1211    parent: &Reader<'a>,
1212    wrapper: &Element<'a>,
1213    field: &'static str,
1214) -> Result<()> {
1215    /// The ub-name character bound both EDI fields carry (RFC 5280 appendix A).
1216    const MOST: usize = 32768;
1217    let fail = |code| Error::new(code, field, wrapper.span().start);
1218
1219    let mut inside = parent.enter(wrapper).field(field)?;
1220    let value = inside
1221        .next_element()
1222        .field(field)?
1223        .ok_or_else(|| fail(ErrorCode::MissingField))?;
1224    if !inside.is_empty() {
1225        return Err(fail(ErrorCode::TrailingData));
1226    }
1227
1228    // The directory string choice of X.520: a primitive universal string of
1229    // one of its five types, holding one to 32768 characters, the ub-name
1230    // bound both EDI fields carry (RFC 5280 appendix A). The tag alone is not
1231    // the type, so the value must also decode under the type chosen.
1232    let tag = value.tag();
1233    let is_directory_string = tag.class() == Class::Universal
1234        && !tag.is_constructed()
1235        && matches!(tag.number(), Some(12 | 19 | 20 | 28 | 30));
1236    // The ceiling is checked on the encoded bytes before any text is
1237    // materialized: each encoding spends a known number of bytes per
1238    // character, so contents past the per-encoding multiple of the bound
1239    // can never fit it and are refused without allocating a copy.
1240    let ceiling = match tag.number() {
1241        Some(12 | 28) => MOST.saturating_mul(4),
1242        Some(30) => MOST.saturating_mul(2),
1243        _ => MOST,
1244    };
1245    if value.contents().len() > ceiling {
1246        return Err(fail(ErrorCode::MalformedValue));
1247    }
1248    // The decode below scans every content byte, and the per-field ceiling
1249    // does not bound the aggregate across many fields: the scan is charged
1250    // to the shared work budget first.
1251    parent.charge(value.contents().len() as u64).field(field)?;
1252    let decodes = match tag.number() {
1253        Some(12) => {
1254            core::str::from_utf8(value.contents()).is_ok_and(|text| text.chars().count() <= MOST)
1255        }
1256        Some(19) => crate::name::is_printable(value.contents()) && value.contents().len() <= MOST,
1257        Some(28) => {
1258            crate::name::wide_char_count(value.contents(), 4).is_some_and(|count| count <= MOST)
1259        }
1260        Some(30) => {
1261            crate::name::wide_char_count(value.contents(), 2).is_some_and(|count| count <= MOST)
1262        }
1263        // TeletexString's repertoire is a negotiation this crate does not
1264        // implement: the bytes being there and inside the bound is what is
1265        // checkable.
1266        _ => value.contents().len() <= MOST,
1267    };
1268    if !is_directory_string || value.contents().is_empty() || !decodes {
1269        return Err(fail(ErrorCode::MalformedValue));
1270    }
1271    Ok(())
1272}
1273
1274fn read_other<'a>(
1275    parent: &Reader<'a>,
1276    element: &Element<'a>,
1277    field: &'static str,
1278) -> Result<GeneralName<'a>> {
1279    let fail = |code| Error::new(code, field, element.span().start);
1280
1281    let mut inside = parent.enter(element).field(field)?;
1282    let type_id = inside.read_oid().field(field)?;
1283    let wrapper = inside
1284        .next_element()
1285        .field(field)?
1286        .ok_or_else(|| fail(ErrorCode::MissingField))?;
1287
1288    // The value is tagged explicitly, because what it is depends on the
1289    // identifier before it and a tag cannot replace one it does not know.
1290    if wrapper.tag() != Tag::context(true, 0) {
1291        return Err(fail(ErrorCode::Encoding(
1292            structured_asn1::ErrorCode::UnexpectedTag,
1293        )));
1294    }
1295    if !inside.is_empty() {
1296        return Err(fail(ErrorCode::TrailingData));
1297    }
1298
1299    // The wrapper holds the one value the identifier describes. Empty it
1300    // names nothing, and with a second element there is no answer to which
1301    // value the name is.
1302    let mut held = inside.enter(&wrapper).field(field)?;
1303    let value = held
1304        .next_element()
1305        .field(field)?
1306        .ok_or_else(|| fail(ErrorCode::MissingField))?;
1307    if !held.is_empty() {
1308        return Err(fail(ErrorCode::TrailingData));
1309    }
1310
1311    // The outer tag is not the whole value: a container this crate does not
1312    // interpret may still hold children that are not DER, an integer written
1313    // a byte longer than it needs or a marker belonging to the indefinite
1314    // lengths DER does not have. A recognizer clears a critical extension on
1315    // the strength of this value, so every element inside it is held to the
1316    // encoding's rules before it is preserved.
1317    crate::name::walk_der(&held, &value, field, crate::name::Strings::Checked)?;
1318
1319    Ok(GeneralName::Other {
1320        type_id,
1321        value: value.as_bytes(),
1322    })
1323}
1324
1325/// Reads the ASCII a schema calls an `IA5String`.
1326/// Whether text is a domain in the preferred name syntax: dot-separated
1327/// labels of letters, digits and inner hyphens, each of one to sixty-three
1328/// characters (RFC 1034 3.5, its leading letter relaxed to a letter or digit
1329/// by RFC 1123 2.1).
1330pub(crate) fn is_domain(text: &str) -> bool {
1331    // The whole name is bounded too: 255 octets in the wire form, which is
1332    // 253 characters of the presentation form (RFC 1035 2.3.4). The
1333    // highest-level label stays alphabetic-bearing (RFC 1123 2.1), which is
1334    // what separates a host name from a dotted-decimal address: an address
1335    // wearing this field would ride under the wrong name-constraint form.
1336    text.len() <= 253
1337        && text.split('.').all(|label| {
1338            (1..=63).contains(&label.len())
1339                && label
1340                    .bytes()
1341                    .all(|byte| byte.is_ascii_alphanumeric() || byte == b'-')
1342                && !label.starts_with('-')
1343                && !label.ends_with('-')
1344        })
1345        && text
1346            .rsplit('.')
1347            .next()
1348            .is_some_and(|top| top.bytes().any(|byte| byte.is_ascii_alphabetic()))
1349}
1350
1351/// Whether text is a mailbox, the form RFC 5280 4.2.1.6 points at: "the
1352/// format of an rfc822Name is a Mailbox as defined in RFC 5321 section
1353/// 4.1.2".
1354///
1355/// The dependency's ASCII SMTP predicate shares its strict envelope grammar,
1356/// including quoted local parts, single-label domains and §4.1.3 literals.
1357/// It performs no allocation or normalization. Both callers admit the bounded
1358/// linear scan first: name decoding through `text()`, and legacy subject
1359/// mailbox formation through the path's current execution account. Header
1360/// comments are outside this grammar. Literal tag registration/deliverability
1361/// is not established by this syntax check.
1362pub(crate) fn is_mailbox(text: &str) -> bool {
1363    structured_email_address::is_smtp_mailbox(text)
1364}
1365
1366/// Whether text is an absolute URI: a scheme of a letter then letters,
1367/// digits, plus, minus and dots (RFC 3986 3.1), a colon, and a non-empty
1368/// remainder inside the URI alphabet, a percent sign spelling a byte only
1369/// with two hexadecimal digits behind it (RFC 3986 2.1). The fragment
1370/// delimiter is not in the alphabet: absolute-URI carries no fragment
1371/// (RFC 3986 4.3), which belongs to URI references. What follows the scheme
1372/// is the scheme's to define, and is never fetched.
1373pub(crate) fn is_absolute_uri(text: &str) -> bool {
1374    absolute_uri::<true>(text)
1375}
1376
1377fn absolute_uri<const CERTIFICATE_NAME: bool>(text: &str) -> bool {
1378    let Some((scheme, rest)) = text.split_once(':') else {
1379        return false;
1380    };
1381    let mut bytes = scheme.bytes();
1382    if !(bytes.next().is_some_and(|byte| byte.is_ascii_alphabetic())
1383        && bytes.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'+' | b'-' | b'.')))
1384    {
1385        return false;
1386    }
1387    // The remainder is required, which the generic grammar does not require:
1388    // RFC 3986's hier-part admits path-empty, so "urn:" parses there. The
1389    // profile is stricter, and it is the profile this reads under: a name
1390    // "MUST include both a scheme (e.g., "http" or "ftp") and a
1391    // scheme-specific-part" (RFC 5280 4.2.1.6). A scheme alone names no
1392    // place, and accepting one would report a location a report cannot
1393    // explain.
1394    if CERTIFICATE_NAME && rest.is_empty() {
1395        return false;
1396    }
1397
1398    // The authority is [userinfo "@"] host [":" port] (RFC 3986 3.2), and
1399    // it is validated structurally: the user-info delimiter appears at most
1400    // once, the brackets exist only around an IP literal in the host
1401    // (3.2.2), and the port holds digits and nothing else (3.2.3). The
1402    // character walk below covers the remaining free-form segments.
1403    let mut userinfo = "";
1404    let mut bare_host = "";
1405    let mut tail = rest;
1406    if let Some(after) = rest.strip_prefix("//") {
1407        let end = after.find(['/', '?']).unwrap_or(after.len());
1408        let authority = &after[..end];
1409        tail = &after[end..];
1410        let (before, host_port) = match authority.split_once('@') {
1411            Some((before, host_port)) => (before, host_port),
1412            None => ("", authority),
1413        };
1414        // A second raw at-sign belongs to no component: neither user-info
1415        // nor the host may carry one.
1416        if host_port.contains('@') {
1417            return false;
1418        }
1419        userinfo = before;
1420        let port = if let Some(inside) = host_port.strip_prefix('[') {
1421            let Some((literal, past)) = inside.split_once(']') else {
1422                return false;
1423            };
1424            if !is_ip_literal(literal) {
1425                return false;
1426            }
1427            // After the literal only a port may follow within the authority.
1428            if past.is_empty() {
1429                None
1430            } else {
1431                let Some(digits) = past.strip_prefix(':') else {
1432                    return false;
1433                };
1434                Some(digits)
1435            }
1436        } else {
1437            // A colon in a bare host is the port delimiter: reg-names have
1438            // no colon of their own.
1439            let port = if let Some((host, port)) = host_port.split_once(':') {
1440                bare_host = host;
1441                Some(port)
1442            } else {
1443                bare_host = host_port;
1444                None
1445            };
1446            // "URIs that include an authority (RFC 3986 3.2) MUST include a
1447            // fully qualified domain name or IP address as the host"
1448            // (RFC 5280 4.2.1.6). The bracketed form is an address already;
1449            // a bare host is a name or a dotted-quad, and nothing else, so
1450            // an empty authority and a word that is neither are refused
1451            // here rather than passed on as a location.
1452            //
1453            // A single closing period is the absolute spelling of a name,
1454            // which ends at the root (RFC 1034 3.1). It qualifies a name
1455            // rather than leaving it short of qualified, so it is read here
1456            // and kept in the location, which is preserved as written.
1457            let named = bare_host.strip_suffix('.').unwrap_or(bare_host);
1458            if CERTIFICATE_NAME && !is_domain(named) && bare_host.parse::<Ipv4Addr>().is_err() {
1459                return false;
1460            }
1461            port
1462        };
1463        // The port is digits alone, the grammar's *DIGIT; empty included.
1464        if port.is_some_and(|digits| !digits.bytes().all(|byte| byte.is_ascii_digit())) {
1465            return false;
1466        }
1467    }
1468
1469    uri_alphabet(userinfo) && uri_alphabet(bare_host) && uri_alphabet(tail)
1470}
1471
1472/// Whether a segment holds only what a URI is written from: the unreserved
1473/// characters, the sub-delimiters, the two component delimiters that appear
1474/// inside a path or a query, and a percent sign only where two hexadecimal
1475/// digits follow it (RFC 3986 2).
1476fn uri_alphabet(segment: &str) -> bool {
1477    let mut bytes = segment.bytes();
1478    while let Some(byte) = bytes.next() {
1479        let permitted = byte.is_ascii_alphanumeric()
1480            || matches!(
1481                byte,
1482                b'-' | b'.'
1483                    | b'_'
1484                    | b'~'
1485                    | b':'
1486                    | b'/'
1487                    | b'?'
1488                    | b'@'
1489                    | b'!'
1490                    | b'$'
1491                    | b'&'
1492                    | b'\''
1493                    | b'('
1494                    | b')'
1495                    | b'*'
1496                    | b'+'
1497                    | b','
1498                    | b';'
1499                    | b'='
1500            );
1501        if byte == b'%' {
1502            let mut pair = [bytes.next(), bytes.next()].into_iter();
1503            if !pair.all(|digit| digit.is_some_and(|digit| digit.is_ascii_hexdigit())) {
1504                return false;
1505            }
1506        } else if !permitted {
1507            return false;
1508        }
1509    }
1510    true
1511}
1512
1513/// Whether text is a URI, the production that carries an optional fragment
1514/// after the rest of it (RFC 3986 3).
1515///
1516/// Certificate names (RFC5280 §4.2.1.6) additionally require their
1517/// scheme-specific part and host shape. A fragment does not make a
1518/// scheme-bearing URI relative. CPS pointers use the generic branch below.
1519pub(crate) fn is_uri(text: &str) -> bool {
1520    uri::<true>(text)
1521}
1522
1523/// `CPSuri` uses RFC3986 URI grammar (RFC5280 §4.2.1.4), independently of
1524/// §4.2.1.6's certificate-name host and scheme-specific-part requirements.
1525/// <https://www.rfc-editor.org/rfc/rfc5280.html#section-4.2.1.4>
1526pub(crate) fn is_cps_uri(text: &str) -> bool {
1527    uri::<false>(text)
1528}
1529
1530fn uri<const CERTIFICATE_NAME: bool>(text: &str) -> bool {
1531    match text.split_once('#') {
1532        // The fragment is written from the same alphabet, and the delimiter
1533        // appears once: a second one is inside no production.
1534        Some((rest, fragment)) => absolute_uri::<CERTIFICATE_NAME>(rest) && uri_alphabet(fragment),
1535        None => absolute_uri::<CERTIFICATE_NAME>(text),
1536    }
1537}
1538
1539/// Whether mask bytes are leading one bits and nothing after them.
1540/// Whether bracketed host contents are one of the two IP-literal forms of
1541/// RFC 3986 3.2.2: an IPv6 address, or the versioned future form. A word
1542/// that merely fits the bracket alphabet is neither and names no host.
1543fn is_ip_literal(text: &str) -> bool {
1544    if let Some(rest) = text.strip_prefix(['v', 'V']) {
1545        // IPvFuture: "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ).
1546        let Some((version, suffix)) = rest.split_once('.') else {
1547            return false;
1548        };
1549        return !version.is_empty()
1550            && version.bytes().all(|byte| byte.is_ascii_hexdigit())
1551            && !suffix.is_empty()
1552            && suffix.bytes().all(|byte| {
1553                byte.is_ascii_alphanumeric()
1554                    || matches!(
1555                        byte,
1556                        b'-' | b'.'
1557                            | b'_'
1558                            | b'~'
1559                            | b':'
1560                            | b'!'
1561                            | b'$'
1562                            | b'&'
1563                            | b'\''
1564                            | b'('
1565                            | b')'
1566                            | b'*'
1567                            | b'+'
1568                            | b','
1569                            | b';'
1570                            | b'='
1571                    )
1572            });
1573    }
1574    text.parse::<Ipv6Addr>().is_ok()
1575}
1576
1577fn is_contiguous_mask(mask: &[u8]) -> bool {
1578    let mut still_ones = true;
1579    for &byte in mask {
1580        if still_ones {
1581            if byte == 0xff {
1582                continue;
1583            }
1584            // The one partial byte: leading ones, then zeros to its end.
1585            let ones = byte.leading_ones();
1586            let expected = if ones == 0 { 0 } else { 0xffu8 << (8 - ones) };
1587            if byte != expected {
1588                return false;
1589            }
1590            still_ones = false;
1591        } else if byte != 0 {
1592            return false;
1593        }
1594    }
1595    true
1596}
1597
1598fn text<'a>(
1599    parent: &Reader<'a>,
1600    contents: &'a [u8],
1601    field: &'static str,
1602    element: &Element<'a>,
1603) -> Result<&'a str> {
1604    // The scans behind this text, ASCII, grammar and bounds alike, walk
1605    // every content byte: they are charged to the shared work budget, so a
1606    // caller bounding work sees them on the same meter the reads use.
1607    parent.charge(contents.len() as u64).field(field)?;
1608    // An empty address, domain or location satisfies the shape while naming
1609    // nothing, and a critical alternative-name list carrying only one of
1610    // these would count as having supplied an identity.
1611    if contents.is_empty() {
1612        return Err(Error::new(
1613            ErrorCode::MalformedValue,
1614            field,
1615            element.span().start,
1616        ));
1617    }
1618    if !contents.is_ascii() {
1619        // The schema's alphabet is ASCII, and a byte outside it is a name
1620        // written in an encoding the field does not have. Guessing at one
1621        // would put a domain or an address in the report that the certificate
1622        // does not carry.
1623        return Err(Error::new(
1624            ErrorCode::MalformedValue,
1625            field,
1626            element.span().start,
1627        ));
1628    }
1629    core::str::from_utf8(contents)
1630        .map_err(|_| Error::new(ErrorCode::MalformedValue, field, element.span().start))
1631}
1632
1633#[cfg(test)]
1634mod tests;