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