1use 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, MemoryError, OwnedVec, Work};
14use structured_asn1::{Class, Element, Oid, ScopedReader as Reader, Tag, universal};
15
16mod equality;
17mod ldap;
18mod uri;
19
20#[derive(Debug)]
22#[non_exhaustive]
23pub enum GeneralName<'a> {
24 Other {
26 type_id: Oid<'a>,
28 value: &'a [u8],
30 },
31 Email(&'a str),
33 Dns(&'a str),
35 X400(&'a [u8]),
37 Directory(Name<'a>),
39 EdiParty(&'a [u8]),
41 Uri(&'a str),
43 IpAddress(&'a [u8]),
46 RegisteredId(Oid<'a>),
48}
49
50impl GeneralName<'_> {
51 pub fn matches(
76 &self,
77 other: &GeneralName<'_>,
78 execution: &Memory,
79 ) -> core::result::Result<bool, ErrorCode> {
80 equality::matches(self, other, execution, None, 0, "generalName")
81 .map_err(|error| error.code())
82 }
83}
84
85pub fn matches(
110 parent: &Reader<'_, '_>,
111 left: &GeneralName<'_>,
112 right: &GeneralName<'_>,
113 at: u64,
114 field: &'static str,
115) -> Result<bool> {
116 equality::matches(left, right, &parent.execution(), Some(parent), at, field)
117}
118
119pub fn matches_at(
132 left: &GeneralName<'_>,
133 right: &GeneralName<'_>,
134 execution: &impl structured_asn1::memory::Work,
135 at: u64,
136 field: &'static str,
137) -> Result<bool> {
138 equality::matches(left, right, execution, None, at, field)
139}
140
141pub fn matches_between<'a, 'b, L: Work, R: Work>(
148 left: &GeneralName<'a>,
149 right: &GeneralName<'b>,
150 left_source: (&L, &'a structured_asn1::Parser),
151 right_source: (&R, &'b structured_asn1::Parser),
152 at: u64,
153 field: &'static str,
154) -> Result<bool> {
155 equality::matches_between(left, right, left_source, right_source, at, field)
156}
157
158pub(crate) fn read_all<'a>(
160 parent: &Reader<'a, '_>,
161 element: &Element<'a>,
162 field: &'static str,
163) -> Result<OwnedVec<GeneralName<'a>>> {
164 let mut inside = parent.enter(element).field(field)?;
165 read_list(&mut inside, field, element.span().start)
166}
167
168pub(crate) fn read_list<'a>(
170 inside: &mut Reader<'a, '_>,
171 field: &'static str,
172 offset: u64,
173) -> Result<OwnedVec<GeneralName<'a>>> {
174 read_list_as(inside, field, offset, AddressForm::Single)
175}
176
177pub(crate) fn read_locations<'a>(
181 parent: &Reader<'a, '_>,
182 element: &Element<'a>,
183 field: &'static str,
184) -> Result<OwnedVec<GeneralName<'a>>> {
185 let mut inside = parent.enter(element).field(field)?;
186 read_list_as(
187 &mut inside,
188 field,
189 element.span().start,
190 AddressForm::Location,
191 )
192}
193
194fn read_list_as<'a>(
195 inside: &mut Reader<'a, '_>,
196 field: &'static str,
197 offset: u64,
198 form: AddressForm,
199) -> Result<OwnedVec<GeneralName<'a>>> {
200 let mut names = inside.memory().vector();
201 while let Some(entry) = inside.next_element().field(field)? {
202 let name = read_as(inside, &entry, field, form)?;
203 let work = inside.execution();
204 let Ok(mut scoped) = names.with_execution(&work) else {
208 unreachable!("the name decoder preserves its catalogue account")
209 };
210 scoped
211 .try_push(name)
212 .map_err(|reason| Error::resource(reason, field, entry.span().start))?;
213 names = scoped.into_owned();
214 }
215
216 if names.is_empty() {
219 return Err(Error::new(ErrorCode::EmptySequence, field, offset));
220 }
221 Ok(names)
222}
223
224pub fn read_alternative<'a, W: structured_asn1::memory::Work>(
227 extension: &Extension<'a>,
228 execution: &W,
229) -> Result<OwnedVec<GeneralName<'a>>> {
230 let field = if extension.kind() == crate::oid::ISSUER_ALT_NAME {
231 "extensions.issuerAltName"
232 } else {
233 "extensions.subjectAltName"
234 };
235
236 let mut inside = extension::sequence(extension, field, execution)?;
237 read_list(&mut inside, field, extension.span().start)
238}
239
240#[derive(Debug, Clone, Copy, PartialEq, Eq)]
247pub(crate) enum AddressForm {
248 Single,
250 Location,
252 WithMask,
255}
256
257impl AddressForm {
258 fn permits(self, length: usize) -> bool {
259 match self {
260 Self::Single | Self::Location => length == 4 || length == 16,
261 Self::WithMask => length == 8 || length == 32,
262 }
263 }
264}
265
266pub fn read<'a>(
277 parent: &Reader<'a, '_>,
278 element: &Element<'a>,
279 field: &'static str,
280) -> Result<GeneralName<'a>> {
281 read_as(parent, element, field, AddressForm::Single)
282}
283
284fn mailbox_fits(text: &str, address_form: AddressForm) -> bool {
290 match address_form {
291 AddressForm::Single | AddressForm::Location => is_mailbox(text),
292 AddressForm::WithMask => {
293 is_mailbox(text) || is_domain(text) || text.strip_prefix('.').is_some_and(is_domain)
294 }
295 }
296}
297
298fn domain_fits(text: &str, address_form: AddressForm) -> bool {
315 match address_form {
316 AddressForm::Single | AddressForm::Location => is_domain(text),
317 AddressForm::WithMask => is_domain(text) || text.strip_prefix('.').is_some_and(is_domain),
318 }
319}
320
321pub(crate) fn read_as<'a>(
322 parent: &Reader<'a, '_>,
323 element: &Element<'a>,
324 field: &'static str,
325 address_form: AddressForm,
326) -> Result<GeneralName<'a>> {
327 let fail = |code| Error::new(code, field, element.span().start);
328 let tag = element.tag();
329
330 if tag.class() != Class::ContextSpecific {
331 return Err(fail(ErrorCode::Encoding(
332 structured_asn1::ErrorCode::UnexpectedTag,
333 )));
334 }
335
336 let Some(number) = tag.number() else {
343 return Err(fail(ErrorCode::Encoding(
344 structured_asn1::ErrorCode::UnexpectedTag,
345 )));
346 };
347 match (number, tag.is_constructed()) {
348 (0, true) => read_other(parent, element, field),
349 (1, false) => {
350 let email = text(parent, element.contents(), field, element)?;
351 if !mailbox_fits(email, address_form) {
352 return Err(fail(ErrorCode::MalformedValue));
353 }
354 Ok(GeneralName::Email(email))
355 }
356 (2, false) => {
357 let domain = text(parent, element.contents(), field, element)?;
358 if !domain_fits(domain, address_form) {
359 return Err(fail(ErrorCode::MalformedValue));
360 }
361 Ok(GeneralName::Dns(domain))
362 }
363 (3, true) => {
364 read_x400(parent, element, field)?;
365 Ok(GeneralName::X400(element.contents()))
366 }
367 (4, true) => {
368 let mut inside = parent.enter(element).field(field)?;
371 let inner = inside
372 .next_element()
373 .field(field)?
374 .ok_or_else(|| fail(ErrorCode::MissingField))?;
375 let name = name::read(&inside, &inner, field)?;
376 if address_form != AddressForm::WithMask && name.is_empty() {
389 return Err(fail(ErrorCode::MalformedValue));
390 }
391 for attribute in name.attributes() {
392 if !name::well_formed_in(attribute, &inside, field)? {
393 return Err(fail(ErrorCode::MalformedValue));
394 }
395 }
396 if !inside.is_empty() {
397 return Err(fail(ErrorCode::TrailingData));
398 }
399 Ok(GeneralName::Directory(name))
400 }
401 (5, true) => {
402 read_edi_party(parent, element, field)?;
403 Ok(GeneralName::EdiParty(element.contents()))
404 }
405 (6, false) => {
406 let location = text(parent, element.contents(), field, element)?;
407 let fits = match address_form {
416 AddressForm::Single => {
417 parent.charge(location.len() as u64).field(field)?;
420 is_uri(location)
421 }
422 AddressForm::Location => {
423 location_uri(parent, element, location, field)?
427 }
428 AddressForm::WithMask => {
429 is_domain(location) || location.strip_prefix('.').is_some_and(is_domain)
430 }
431 };
432 if !fits {
433 return Err(fail(ErrorCode::MalformedValue));
434 }
435 Ok(GeneralName::Uri(location))
436 }
437 (7, false) => {
438 let contents = element.contents();
439 if !address_form.permits(contents.len()) {
440 return Err(fail(ErrorCode::MalformedValue));
441 }
442 if address_form == AddressForm::WithMask
446 && !is_contiguous_mask(&contents[contents.len() / 2..])
447 {
448 return Err(fail(ErrorCode::MalformedValue));
449 }
450 Ok(GeneralName::IpAddress(contents))
451 }
452 (8, false) => parent
453 .oid(element)
454 .field(field)
455 .map(GeneralName::RegisteredId),
456 _ => Err(fail(ErrorCode::Encoding(
457 structured_asn1::ErrorCode::UnexpectedTag,
458 ))),
459 }
460}
461
462fn read_x400<'a>(
470 parent: &Reader<'a, '_>,
471 element: &Element<'a>,
472 field: &'static str,
473) -> Result<()> {
474 let fail = |code| Error::new(code, field, element.span().start);
475
476 let mut inside = parent.enter(element).field(field)?;
477 let standard = inside
478 .next_element()
479 .field(field)?
480 .ok_or_else(|| fail(ErrorCode::MissingField))?;
481 if standard.tag() != Tag::constructed(universal::SEQUENCE) {
482 return Err(fail(ErrorCode::Encoding(
483 structured_asn1::ErrorCode::UnexpectedTag,
484 )));
485 }
486 read_standard_attributes(&inside, &standard, field)?;
487
488 let mut next = inside.next_element().field(field)?;
490 if let Some(domain_defined) = next
491 && domain_defined.tag() == Tag::constructed(universal::SEQUENCE)
492 {
493 read_domain_defined(&inside, &domain_defined, field)?;
494 next = inside.next_element().field(field)?;
495 }
496 if let Some(extensions) = next {
497 if extensions.tag() != Tag::constructed(universal::SET) {
498 return Err(fail(ErrorCode::Encoding(
499 structured_asn1::ErrorCode::UnexpectedTag,
500 )));
501 }
502 read_extension_attributes(&inside, &extensions, field)?;
503 if !inside.is_empty() {
504 return Err(fail(ErrorCode::TrailingData));
505 }
506 }
507 Ok(())
508}
509
510const X400_NUMERIC_STRING: u32 = 18;
513
514fn x400_string(element: &Element<'_>, field: &'static str, size: (usize, usize)) -> Result<()> {
518 let fail = |code| Error::new(code, field, element.span().start);
519 let contents = element.contents();
520 let fits = match (
523 element.tag().class(),
524 element.tag().number(),
525 element.tag().is_constructed(),
526 ) {
527 (Class::Universal, Some(X400_NUMERIC_STRING), false) => crate::name::is_numeric(contents),
528 (Class::Universal, Some(universal::PRINTABLE_STRING), false) => {
529 crate::name::is_printable(contents)
530 }
531 _ => {
532 return Err(fail(ErrorCode::Encoding(
533 structured_asn1::ErrorCode::UnexpectedTag,
534 )));
535 }
536 };
537 if !fits || contents.len() < size.0 || contents.len() > size.1 {
538 return Err(fail(ErrorCode::MalformedValue));
539 }
540 Ok(())
541}
542
543fn x400_printable(element: &Element<'_>, field: &'static str, size: (usize, usize)) -> Result<()> {
546 let fail = |code| Error::new(code, field, element.span().start);
547 let tag = element.tag();
548 if tag.class() != Class::Universal
549 || tag.number() != Some(universal::PRINTABLE_STRING)
550 || tag.is_constructed()
551 {
552 return Err(fail(ErrorCode::Encoding(
553 structured_asn1::ErrorCode::UnexpectedTag,
554 )));
555 }
556 let contents = element.contents();
557 if !crate::name::is_printable(contents) || contents.len() < size.0 || contents.len() > size.1 {
558 return Err(fail(ErrorCode::MalformedValue));
559 }
560 Ok(())
561}
562
563#[derive(Clone, Copy)]
567enum X400Repertoire {
568 Numeric,
569 Printable,
570 Teletex,
571}
572
573fn x400_implicit(
576 element: &Element<'_>,
577 field: &'static str,
578 repertoire: X400Repertoire,
579 most: usize,
580) -> Result<()> {
581 let fail = |code| Error::new(code, field, element.span().start);
582 let contents = element.contents();
583 if contents.is_empty() || contents.len() > most {
590 return Err(fail(ErrorCode::MalformedValue));
591 }
592 let fits = match repertoire {
593 X400Repertoire::Numeric => crate::name::is_numeric(contents),
594 X400Repertoire::Printable => crate::name::is_printable(contents),
595 X400Repertoire::Teletex => true,
596 };
597 if !fits {
598 return Err(fail(ErrorCode::MalformedValue));
599 }
600 Ok(())
601}
602
603fn x400_teletex(element: &Element<'_>, field: &'static str, size: (usize, usize)) -> Result<()> {
605 let fail = |code| Error::new(code, field, element.span().start);
606 if element.tag() != Tag::primitive(20) {
609 return Err(fail(ErrorCode::Encoding(
610 structured_asn1::ErrorCode::UnexpectedTag,
611 )));
612 }
613 let length = element.contents().len();
614 if length < size.0 || length > size.1 {
615 return Err(fail(ErrorCode::MalformedValue));
616 }
617 Ok(())
618}
619
620fn x400_bare_country(value: &Element<'_>, field: &'static str) -> Result<()> {
624 let fail = |code| Error::new(code, field, value.span().start);
625 let contents = value.contents();
626 let fits = match (
627 value.tag().class(),
628 value.tag().number(),
629 value.tag().is_constructed(),
630 ) {
631 (Class::Universal, Some(X400_NUMERIC_STRING), false) => {
632 contents.len() == 3 && contents.iter().all(u8::is_ascii_digit)
633 }
634 (Class::Universal, Some(universal::PRINTABLE_STRING), false) => {
635 contents.len() == 2 && contents.iter().all(u8::is_ascii_uppercase)
636 }
637 _ => {
638 return Err(fail(ErrorCode::Encoding(
639 structured_asn1::ErrorCode::UnexpectedTag,
640 )));
641 }
642 };
643 if !fits {
644 return Err(fail(ErrorCode::MalformedValue));
645 }
646 Ok(())
647}
648
649fn x400_country<'a>(
651 parent: &Reader<'a, '_>,
652 wrapper: &Element<'a>,
653 field: &'static str,
654) -> Result<()> {
655 let fail = |code| Error::new(code, field, wrapper.span().start);
656 let mut inside = parent.enter(wrapper).field(field)?;
657 let value = inside
658 .next_element()
659 .field(field)?
660 .ok_or_else(|| fail(ErrorCode::MissingField))?;
661 if !inside.is_empty() {
662 return Err(fail(ErrorCode::TrailingData));
663 }
664 x400_bare_country(&value, field)
665}
666
667fn x400_choice<'a>(
670 parent: &Reader<'a, '_>,
671 wrapper: &Element<'a>,
672 field: &'static str,
673 numeric: (usize, usize),
674 printable: (usize, usize),
675) -> Result<()> {
676 let fail = |code| Error::new(code, field, wrapper.span().start);
677 let mut inside = parent.enter(wrapper).field(field)?;
678 let value = inside
679 .next_element()
680 .field(field)?
681 .ok_or_else(|| fail(ErrorCode::MissingField))?;
682 if !inside.is_empty() {
683 return Err(fail(ErrorCode::TrailingData));
684 }
685 let size = match (value.tag().class(), value.tag().number()) {
686 (Class::Universal, Some(X400_NUMERIC_STRING)) => numeric,
687 (Class::Universal, Some(universal::PRINTABLE_STRING)) => printable,
688 _ => {
689 return Err(fail(ErrorCode::Encoding(
690 structured_asn1::ErrorCode::UnexpectedTag,
691 )));
692 }
693 };
694 x400_string(&value, field, size)
695}
696
697fn read_standard_attributes<'a>(
701 parent: &Reader<'a, '_>,
702 element: &Element<'a>,
703 field: &'static str,
704) -> Result<()> {
705 let mut inside = parent.enter(element).field(field)?;
706 let mut last_rank = -1i8;
707 while let Some(member) = inside.next_element().field(field)? {
708 let bad = |code| Error::new(code, field, member.span().start);
709 let tag = member.tag();
710 let Some(number) = tag.number() else {
713 return Err(bad(ErrorCode::Encoding(
714 structured_asn1::ErrorCode::UnexpectedTag,
715 )));
716 };
717 let rank: i8 = match (tag.class(), number, tag.is_constructed()) {
718 (Class::Application, 1, true) => {
721 x400_country(&inside, &member, field)?;
722 0
723 }
724 (Class::Application, 2, true) => {
727 x400_choice(&inside, &member, field, (0, 16), (0, 16))?;
728 1
729 }
730 (Class::ContextSpecific, 0, false) => {
732 x400_implicit(&member, field, X400Repertoire::Numeric, 16)?;
733 2
734 }
735 (Class::ContextSpecific, 1, false) => {
737 x400_implicit(&member, field, X400Repertoire::Printable, 24)?;
738 3
739 }
740 (Class::ContextSpecific, 2, true) => {
742 x400_choice(&inside, &member, field, (1, 16), (1, 16))?;
743 4
744 }
745 (Class::ContextSpecific, 3, false) => {
747 x400_implicit(&member, field, X400Repertoire::Printable, 64)?;
748 5
749 }
750 (Class::ContextSpecific, 4, false) => {
752 x400_implicit(&member, field, X400Repertoire::Numeric, 32)?;
753 6
754 }
755 (Class::ContextSpecific, 5, true) => {
757 read_personal_name(&inside, &member, field, X400Repertoire::Printable)?;
758 7
759 }
760 (Class::ContextSpecific, 6, true) => {
764 let mut units = inside.enter(&member).field(field)?;
765 let mut count = 0usize;
766 while let Some(unit) = units.next_element().field(field)? {
767 x400_printable(&unit, field, (1, 32))?;
768 count += 1;
769 }
770 if !(1..=4).contains(&count) {
771 return Err(bad(ErrorCode::MalformedValue));
772 }
773 8
774 }
775 _ => {
776 return Err(bad(ErrorCode::Encoding(
777 structured_asn1::ErrorCode::UnexpectedTag,
778 )));
779 }
780 };
781 if rank <= last_rank {
785 return Err(bad(ErrorCode::UnexpectedField));
786 }
787 last_rank = rank;
788 }
789 Ok(())
790}
791
792fn read_personal_name<'a>(
796 parent: &Reader<'a, '_>,
797 element: &Element<'a>,
798 field: &'static str,
799 repertoire: X400Repertoire,
800) -> Result<()> {
801 let fail = |code| Error::new(code, field, element.span().start);
802 let mut inside = parent.enter(element).field(field)?;
803 let mut seen = [false; 4];
804 let mut last: Option<usize> = None;
805 while let Some(part) = inside.next_element().field(field)? {
806 let bad = |code| Error::new(code, field, part.span().start);
807 let (number, most) = match (
808 part.tag().class(),
809 part.tag().number(),
810 part.tag().is_constructed(),
811 ) {
812 (Class::ContextSpecific, Some(0), false) => (0usize, 40),
813 (Class::ContextSpecific, Some(1), false) => (1, 16),
814 (Class::ContextSpecific, Some(2), false) => (2, 5),
815 (Class::ContextSpecific, Some(3), false) => (3, 3),
816 _ => {
817 return Err(bad(ErrorCode::Encoding(
818 structured_asn1::ErrorCode::UnexpectedTag,
819 )));
820 }
821 };
822 if seen[number] {
823 return Err(bad(ErrorCode::UnexpectedField));
824 }
825 if inside.encoding().is_der() && last.is_some_and(|last| number < last) {
829 return Err(bad(ErrorCode::UnexpectedField));
830 }
831 seen[number] = true;
832 last = Some(number);
833 x400_implicit(&part, field, repertoire, most)?;
834 }
835 if !seen[0] {
836 return Err(fail(ErrorCode::MissingField));
837 }
838 Ok(())
839}
840
841fn read_domain_defined<'a>(
844 parent: &Reader<'a, '_>,
845 element: &Element<'a>,
846 field: &'static str,
847) -> Result<()> {
848 read_defined_pairs(parent, element, field, false)
849}
850
851fn read_defined_pairs<'a>(
854 parent: &Reader<'a, '_>,
855 element: &Element<'a>,
856 field: &'static str,
857 teletex: bool,
858) -> Result<()> {
859 let fail = |code| Error::new(code, field, element.span().start);
860 if element.tag() != Tag::constructed(universal::SEQUENCE) {
861 return Err(fail(ErrorCode::Encoding(
862 structured_asn1::ErrorCode::UnexpectedTag,
863 )));
864 }
865 let held_string = |element: &Element<'_>, size: (usize, usize)| {
866 if teletex {
867 x400_teletex(element, field, size)
868 } else {
869 x400_printable(element, field, size)
872 }
873 };
874 let mut inside = parent.enter(element).field(field)?;
875 let mut count = 0usize;
876 while let Some(pair) = inside.next_element().field(field)? {
877 let bad = |code| Error::new(code, field, pair.span().start);
878 if pair.tag() != Tag::constructed(universal::SEQUENCE) {
879 return Err(bad(ErrorCode::Encoding(
880 structured_asn1::ErrorCode::UnexpectedTag,
881 )));
882 }
883 let mut two = inside.enter(&pair).field(field)?;
884 let kind = two
885 .next_element()
886 .field(field)?
887 .ok_or_else(|| bad(ErrorCode::MissingField))?;
888 held_string(&kind, (1, 8))?;
889 let value = two
890 .next_element()
891 .field(field)?
892 .ok_or_else(|| bad(ErrorCode::MissingField))?;
893 held_string(&value, (1, 128))?;
894 if !two.is_empty() {
895 return Err(bad(ErrorCode::TrailingData));
896 }
897 count += 1;
898 }
899 if !(1..=4).contains(&count) {
900 return Err(fail(ErrorCode::MalformedValue));
901 }
902 Ok(())
903}
904
905fn read_extension_attributes<'a>(
909 parent: &Reader<'a, '_>,
910 element: &Element<'a>,
911 field: &'static str,
912) -> Result<()> {
913 let fail = |code| Error::new(code, field, element.span().start);
914 let mut inside = parent.enter(element).field(field)?;
915 let mut count = 0usize;
916 let mut previous: Option<&[u8]> = None;
917 while let Some(entry) = inside.next_element().field(field)? {
918 let bad = |code| Error::new(code, field, entry.span().start);
919 if entry.tag() != Tag::constructed(universal::SEQUENCE) {
920 return Err(bad(ErrorCode::Encoding(
921 structured_asn1::ErrorCode::UnexpectedTag,
922 )));
923 }
924 if inside.encoding().is_der()
930 && let Some(previous) = previous
931 {
932 inside
933 .charge(previous.len().max(entry.as_bytes().len()) as u64)
934 .field(field)?;
935 if entry.as_bytes() < previous {
936 return Err(bad(ErrorCode::UnexpectedField));
937 }
938 }
939 previous = Some(entry.as_bytes());
940 let mut two = inside.enter(&entry).field(field)?;
941 let kind = two
942 .next_element()
943 .field(field)?
944 .ok_or_else(|| bad(ErrorCode::MissingField))?;
945 if extension::context_of(kind.tag()) != Some((0, false)) {
949 return Err(bad(ErrorCode::Encoding(
950 structured_asn1::ErrorCode::UnexpectedTag,
951 )));
952 }
953 let number = two.integer(&kind).field(field)?;
954 if number.as_u32().is_none_or(|number| number > 256) {
955 return Err(bad(ErrorCode::MalformedValue));
956 }
957 let value = two
958 .next_element()
959 .field(field)?
960 .ok_or_else(|| bad(ErrorCode::MissingField))?;
961 if extension::context_of(value.tag()) != Some((1, true)) {
964 return Err(bad(ErrorCode::Encoding(
965 structured_asn1::ErrorCode::UnexpectedTag,
966 )));
967 }
968 let mut held = two.enter(&value).field(field)?;
969 let Some(declared) = held.next_element().field(field)? else {
970 return Err(bad(ErrorCode::MissingField));
971 };
972 let number = number
977 .as_u32()
978 .expect("bounded to 0..=256 above, which fits");
979 read_extension_value(&held, &declared, number, field)?;
980 if !held.is_empty() || !two.is_empty() {
981 return Err(bad(ErrorCode::TrailingData));
982 }
983 count += 1;
984 if count > 256 {
987 return Err(bad(ErrorCode::MalformedValue));
988 }
989 }
990 if count == 0 {
991 return Err(fail(ErrorCode::EmptySequence));
992 }
993 Ok(())
994}
995
996fn read_extension_value<'a>(
1002 parent: &Reader<'a, '_>,
1003 value: &Element<'a>,
1004 number: u32,
1005 field: &'static str,
1006) -> Result<()> {
1007 let fail = |code| Error::new(code, field, value.span().start);
1008 match number {
1009 1 => x400_printable(value, field, (1, 64)),
1012 2 | 3 => x400_teletex(value, field, (1, 64)),
1014 4 => {
1016 if value.tag() != Tag::constructed(universal::SET) {
1017 return Err(fail(ErrorCode::Encoding(
1018 structured_asn1::ErrorCode::UnexpectedTag,
1019 )));
1020 }
1021 read_personal_name(parent, value, field, X400Repertoire::Teletex)
1022 }
1023 5 => {
1025 if value.tag() != Tag::constructed(universal::SEQUENCE) {
1026 return Err(fail(ErrorCode::Encoding(
1027 structured_asn1::ErrorCode::UnexpectedTag,
1028 )));
1029 }
1030 let mut units = parent.enter(value).field(field)?;
1031 let mut count = 0usize;
1032 while let Some(unit) = units.next_element().field(field)? {
1033 x400_teletex(&unit, field, (1, 32))?;
1034 count += 1;
1035 }
1036 if !(1..=4).contains(&count) {
1037 return Err(fail(ErrorCode::MalformedValue));
1038 }
1039 Ok(())
1040 }
1041 6 => read_defined_pairs(parent, value, field, true),
1043 7 => x400_printable(value, field, (1, 16)),
1045 8 => x400_bare_country(value, field),
1048 9 => x400_bare_choice(value, field, (1, 16), (1, 16)),
1050 10..=15 | 17..=21 => read_pds_parameter(parent, value, field, 30),
1053 16 => read_unformatted_address(parent, value, field),
1055 22 => read_extended_network_address(parent, value, field),
1057 23 => {
1059 if value.tag() != Tag::primitive(universal::INTEGER) {
1060 return Err(fail(ErrorCode::Encoding(
1061 structured_asn1::ErrorCode::UnexpectedTag,
1062 )));
1063 }
1064 let option = parent.integer(value).field(field)?;
1065 if option.as_u32().is_none_or(|option| option > 256) {
1066 return Err(fail(ErrorCode::MalformedValue));
1067 }
1068 Ok(())
1069 }
1070 _ => Err(fail(ErrorCode::MalformedValue)),
1071 }
1072}
1073
1074fn x400_bare_choice(
1077 value: &Element<'_>,
1078 field: &'static str,
1079 numeric: (usize, usize),
1080 printable: (usize, usize),
1081) -> Result<()> {
1082 let fail = |code| Error::new(code, field, value.span().start);
1083 let size = match (
1084 value.tag().class(),
1085 value.tag().number(),
1086 value.tag().is_constructed(),
1087 ) {
1088 (Class::Universal, Some(X400_NUMERIC_STRING), false) => numeric,
1089 (Class::Universal, Some(universal::PRINTABLE_STRING), false) => printable,
1090 _ => {
1091 return Err(fail(ErrorCode::Encoding(
1092 structured_asn1::ErrorCode::UnexpectedTag,
1093 )));
1094 }
1095 };
1096 x400_string(value, field, size)
1097}
1098
1099fn read_pds_parameter<'a>(
1102 parent: &Reader<'a, '_>,
1103 value: &Element<'a>,
1104 field: &'static str,
1105 most: usize,
1106) -> Result<()> {
1107 let fail = |code| Error::new(code, field, value.span().start);
1108 if value.tag() != Tag::constructed(universal::SET) {
1109 return Err(fail(ErrorCode::Encoding(
1110 structured_asn1::ErrorCode::UnexpectedTag,
1111 )));
1112 }
1113 let mut inside = parent.enter(value).field(field)?;
1114 let mut seen_printable = false;
1115 let mut seen_teletex = false;
1116 while let Some(member) = inside.next_element().field(field)? {
1117 let bad = |code| Error::new(code, field, member.span().start);
1118 if member.tag() == Tag::primitive(universal::PRINTABLE_STRING) {
1119 if seen_printable || (seen_teletex && inside.encoding().is_der()) {
1124 return Err(bad(ErrorCode::UnexpectedField));
1125 }
1126 seen_printable = true;
1127 x400_string(&member, field, (1, most))?;
1128 } else if member.tag() == Tag::primitive(20) {
1129 if seen_teletex {
1130 return Err(bad(ErrorCode::UnexpectedField));
1131 }
1132 seen_teletex = true;
1133 x400_teletex(&member, field, (1, most))?;
1134 } else {
1135 return Err(bad(ErrorCode::Encoding(
1136 structured_asn1::ErrorCode::UnexpectedTag,
1137 )));
1138 }
1139 }
1140 Ok(())
1141}
1142
1143fn read_unformatted_address<'a>(
1146 parent: &Reader<'a, '_>,
1147 value: &Element<'a>,
1148 field: &'static str,
1149) -> Result<()> {
1150 let fail = |code| Error::new(code, field, value.span().start);
1151 if value.tag() != Tag::constructed(universal::SET) {
1152 return Err(fail(ErrorCode::Encoding(
1153 structured_asn1::ErrorCode::UnexpectedTag,
1154 )));
1155 }
1156 let mut inside = parent.enter(value).field(field)?;
1157 let mut seen_lines = false;
1158 let mut seen_teletex = false;
1159 while let Some(member) = inside.next_element().field(field)? {
1160 let bad = |code| Error::new(code, field, member.span().start);
1161 if member.tag() == Tag::constructed(universal::SEQUENCE) {
1162 if seen_lines || (seen_teletex && inside.encoding().is_der()) {
1167 return Err(bad(ErrorCode::UnexpectedField));
1168 }
1169 seen_lines = true;
1170 let mut lines = inside.enter(&member).field(field)?;
1171 let mut count = 0usize;
1172 while let Some(line) = lines.next_element().field(field)? {
1173 x400_printable(&line, field, (1, 30))?;
1176 count += 1;
1177 }
1178 if !(1..=6).contains(&count) {
1179 return Err(bad(ErrorCode::MalformedValue));
1180 }
1181 } else if member.tag() == Tag::primitive(20) {
1182 if seen_teletex {
1183 return Err(bad(ErrorCode::UnexpectedField));
1184 }
1185 seen_teletex = true;
1186 x400_teletex(&member, field, (1, 180))?;
1187 } else {
1188 return Err(bad(ErrorCode::Encoding(
1189 structured_asn1::ErrorCode::UnexpectedTag,
1190 )));
1191 }
1192 }
1193 Ok(())
1194}
1195
1196fn read_e163_address<'a>(
1198 parent: &Reader<'a, '_>,
1199 value: &Element<'a>,
1200 field: &'static str,
1201) -> Result<()> {
1202 let fail = |code| Error::new(code, field, value.span().start);
1203 let mut inside = parent.enter(value).field(field)?;
1204 let number = inside
1205 .next_element()
1206 .field(field)?
1207 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1208 if extension::context_of(number.tag()) != Some((0, false)) {
1209 return Err(fail(ErrorCode::Encoding(
1210 structured_asn1::ErrorCode::UnexpectedTag,
1211 )));
1212 }
1213 x400_implicit(&number, field, X400Repertoire::Numeric, 15)?;
1214 if let Some(sub) = inside.next_element().field(field)? {
1215 if extension::context_of(sub.tag()) != Some((1, false)) {
1216 return Err(fail(ErrorCode::Encoding(
1217 structured_asn1::ErrorCode::UnexpectedTag,
1218 )));
1219 }
1220 x400_implicit(&sub, field, X400Repertoire::Numeric, 40)?;
1221 }
1222 if !inside.is_empty() {
1223 return Err(fail(ErrorCode::TrailingData));
1224 }
1225 Ok(())
1226}
1227
1228fn read_extended_network_address<'a>(
1232 parent: &Reader<'a, '_>,
1233 value: &Element<'a>,
1234 field: &'static str,
1235) -> Result<()> {
1236 let fail = |code| Error::new(code, field, value.span().start);
1237 if value.tag() == Tag::constructed(universal::SEQUENCE) {
1238 read_e163_address(parent, value, field)
1239 } else if extension::context_of(value.tag()) == Some((0, true)) {
1240 let mut inside = parent.enter(value).field(field)?;
1243 let mut last: i8 = -1;
1244 let mut saw_network = false;
1245 while let Some(member) = inside.next_element().field(field)? {
1246 let bad = |code| Error::new(code, field, member.span().start);
1247 let Some((number, true)) = extension::context_of(member.tag()) else {
1248 return Err(bad(ErrorCode::Encoding(
1249 structured_asn1::ErrorCode::UnexpectedTag,
1250 )));
1251 };
1252 let rank = i8::try_from(number).map_err(|_| {
1253 bad(ErrorCode::Encoding(
1254 structured_asn1::ErrorCode::UnexpectedTag,
1255 ))
1256 })?;
1257 if rank > 3 {
1258 return Err(bad(ErrorCode::Encoding(
1259 structured_asn1::ErrorCode::UnexpectedTag,
1260 )));
1261 }
1262 if rank <= last {
1263 return Err(bad(ErrorCode::UnexpectedField));
1264 }
1265 last = rank;
1266 let mut held = inside.enter(&member).field(field)?;
1267 if rank == 3 {
1268 let addresses = held
1270 .next_element()
1271 .field(field)?
1272 .ok_or_else(|| bad(ErrorCode::MissingField))?;
1273 if addresses.tag() != Tag::constructed(universal::SET) {
1274 return Err(bad(ErrorCode::Encoding(
1275 structured_asn1::ErrorCode::UnexpectedTag,
1276 )));
1277 }
1278 let mut each = held.enter(&addresses).field(field)?;
1279 let mut count = 0usize;
1280 let mut previous: Option<&[u8]> = None;
1281 while let Some(address) = each.next_element().field(field)? {
1282 if address.tag() != Tag::primitive(universal::OCTET_STRING) {
1283 return Err(bad(ErrorCode::Encoding(
1284 structured_asn1::ErrorCode::UnexpectedTag,
1285 )));
1286 }
1287 if each.encoding().is_der()
1293 && let Some(previous) = previous
1294 {
1295 each.charge(previous.len().max(address.as_bytes().len()) as u64)
1296 .field(field)?;
1297 if address.as_bytes() < previous {
1298 return Err(bad(ErrorCode::UnexpectedField));
1299 }
1300 }
1301 previous = Some(address.as_bytes());
1302 count += 1;
1303 }
1304 if count == 0 {
1305 return Err(bad(ErrorCode::EmptySequence));
1306 }
1307 saw_network = true;
1308 } else {
1309 let selector = held
1311 .next_element()
1312 .field(field)?
1313 .ok_or_else(|| bad(ErrorCode::MissingField))?;
1314 if selector.tag() != Tag::primitive(universal::OCTET_STRING) {
1315 return Err(bad(ErrorCode::Encoding(
1316 structured_asn1::ErrorCode::UnexpectedTag,
1317 )));
1318 }
1319 }
1320 if !held.is_empty() {
1321 return Err(bad(ErrorCode::TrailingData));
1322 }
1323 }
1324 if !saw_network {
1325 return Err(fail(ErrorCode::MissingField));
1326 }
1327 Ok(())
1328 } else {
1329 Err(fail(ErrorCode::Encoding(
1330 structured_asn1::ErrorCode::UnexpectedTag,
1331 )))
1332 }
1333}
1334
1335fn read_edi_party<'a>(
1340 parent: &Reader<'a, '_>,
1341 element: &Element<'a>,
1342 field: &'static str,
1343) -> Result<()> {
1344 let fail = |code| Error::new(code, field, element.span().start);
1345
1346 let mut inside = parent.enter(element).field(field)?;
1347 let mut next = inside.next_element().field(field)?;
1348
1349 if let Some(assigner) = next
1350 && extension::context_of(assigner.tag()) == Some((0, true))
1351 {
1352 require_directory_string(&inside, &assigner, field)?;
1353 next = inside.next_element().field(field)?;
1354 }
1355
1356 let party = next.ok_or_else(|| fail(ErrorCode::MissingField))?;
1357 if extension::context_of(party.tag()) != Some((1, true)) {
1358 return Err(Error::new(
1359 ErrorCode::UnexpectedField,
1360 field,
1361 party.span().start,
1362 ));
1363 }
1364 require_directory_string(&inside, &party, field)?;
1365
1366 if !inside.is_empty() {
1367 return Err(fail(ErrorCode::TrailingData));
1368 }
1369 Ok(())
1370}
1371
1372fn require_directory_string<'a>(
1374 parent: &Reader<'a, '_>,
1375 wrapper: &Element<'a>,
1376 field: &'static str,
1377) -> Result<()> {
1378 const MOST: usize = 32768;
1380 let fail = |code| Error::new(code, field, wrapper.span().start);
1381
1382 let mut inside = parent.enter(wrapper).field(field)?;
1383 let value = inside
1384 .next_element()
1385 .field(field)?
1386 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1387 if !inside.is_empty() {
1388 return Err(fail(ErrorCode::TrailingData));
1389 }
1390
1391 let tag = value.tag();
1396 let is_directory_string = tag.class() == Class::Universal
1397 && !tag.is_constructed()
1398 && matches!(tag.number(), Some(12 | 19 | 20 | 28 | 30));
1399 let ceiling = match tag.number() {
1404 Some(12 | 28) => MOST.saturating_mul(4),
1405 Some(30) => MOST.saturating_mul(2),
1406 _ => MOST,
1407 };
1408 if value.contents().len() > ceiling {
1409 return Err(fail(ErrorCode::MalformedValue));
1410 }
1411 parent.charge(value.contents().len() as u64).field(field)?;
1415 let decodes = match tag.number() {
1416 Some(12) => {
1417 core::str::from_utf8(value.contents()).is_ok_and(|text| text.chars().count() <= MOST)
1418 }
1419 Some(19) => crate::name::is_printable(value.contents()) && value.contents().len() <= MOST,
1420 Some(28) => {
1421 crate::name::wide_char_count(value.contents(), 4).is_some_and(|count| count <= MOST)
1422 }
1423 Some(30) => {
1424 crate::name::wide_char_count(value.contents(), 2).is_some_and(|count| count <= MOST)
1425 }
1426 _ => value.contents().len() <= MOST,
1430 };
1431 if !is_directory_string || value.contents().is_empty() || !decodes {
1432 return Err(fail(ErrorCode::MalformedValue));
1433 }
1434 Ok(())
1435}
1436
1437fn read_other<'a>(
1438 parent: &Reader<'a, '_>,
1439 element: &Element<'a>,
1440 field: &'static str,
1441) -> Result<GeneralName<'a>> {
1442 let fail = |code| Error::new(code, field, element.span().start);
1443
1444 let mut inside = parent.enter(element).field(field)?;
1445 let type_id = inside.read_oid().field(field)?;
1446 let wrapper = inside
1447 .next_element()
1448 .field(field)?
1449 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1450
1451 if wrapper.tag() != Tag::context(true, 0) {
1454 return Err(fail(ErrorCode::Encoding(
1455 structured_asn1::ErrorCode::UnexpectedTag,
1456 )));
1457 }
1458 if !inside.is_empty() {
1459 return Err(fail(ErrorCode::TrailingData));
1460 }
1461
1462 let mut held = inside.enter(&wrapper).field(field)?;
1466 let value = held
1467 .next_element()
1468 .field(field)?
1469 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1470 if !held.is_empty() {
1471 return Err(fail(ErrorCode::TrailingData));
1472 }
1473
1474 crate::name::walk_der(&held, &value, field, crate::name::Strings::Checked)?;
1481
1482 Ok(GeneralName::Other {
1483 type_id,
1484 value: value.as_bytes(),
1485 })
1486}
1487
1488pub(crate) fn is_domain(text: &str) -> bool {
1494 text.len() <= 253
1500 && text.split('.').all(|label| {
1501 (1..=63).contains(&label.len())
1502 && label
1503 .bytes()
1504 .all(|byte| byte.is_ascii_alphanumeric() || byte == b'-')
1505 && !label.starts_with('-')
1506 && !label.ends_with('-')
1507 })
1508 && text
1509 .rsplit('.')
1510 .next()
1511 .is_some_and(|top| top.bytes().any(|byte| byte.is_ascii_alphabetic()))
1512}
1513
1514pub(crate) fn is_mailbox(text: &str) -> bool {
1526 structured_email_address::is_smtp_mailbox(text)
1527}
1528
1529pub(crate) fn is_absolute_uri(text: &str) -> bool {
1537 absolute_uri::<true>(text)
1538}
1539
1540fn absolute_uri<const CERTIFICATE_NAME: bool>(text: &str) -> bool {
1541 let Some((scheme, rest)) = text.split_once(':') else {
1542 return false;
1543 };
1544 let mut bytes = scheme.bytes();
1545 if !(bytes.next().is_some_and(|byte| byte.is_ascii_alphabetic())
1546 && bytes.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'+' | b'-' | b'.')))
1547 {
1548 return false;
1549 }
1550 if CERTIFICATE_NAME && rest.is_empty() {
1558 return false;
1559 }
1560
1561 let mut userinfo = "";
1567 let mut bare_host = "";
1568 let mut tail = rest;
1569 if let Some(after) = rest.strip_prefix("//") {
1570 let end = after.find(['/', '?']).unwrap_or(after.len());
1571 let authority = &after[..end];
1572 tail = &after[end..];
1573 let (before, host_port) = match authority.split_once('@') {
1574 Some((before, host_port)) => (before, host_port),
1575 None => ("", authority),
1576 };
1577 if host_port.contains('@') {
1580 return false;
1581 }
1582 userinfo = before;
1583 let port = if let Some(inside) = host_port.strip_prefix('[') {
1584 let Some((literal, past)) = inside.split_once(']') else {
1585 return false;
1586 };
1587 if !is_ip_literal(literal) {
1588 return false;
1589 }
1590 if past.is_empty() {
1592 None
1593 } else {
1594 let Some(digits) = past.strip_prefix(':') else {
1595 return false;
1596 };
1597 Some(digits)
1598 }
1599 } else {
1600 let port = if let Some((host, port)) = host_port.split_once(':') {
1603 bare_host = host;
1604 Some(port)
1605 } else {
1606 bare_host = host_port;
1607 None
1608 };
1609 let named = bare_host.strip_suffix('.').unwrap_or(bare_host);
1621 if CERTIFICATE_NAME && !is_domain(named) && bare_host.parse::<Ipv4Addr>().is_err() {
1622 return false;
1623 }
1624 port
1625 };
1626 if port.is_some_and(|digits| !digits.bytes().all(|byte| byte.is_ascii_digit())) {
1628 return false;
1629 }
1630 }
1631
1632 uri_alphabet(userinfo) && uri_alphabet(bare_host) && uri_alphabet(tail)
1633}
1634
1635fn uri_alphabet(segment: &str) -> bool {
1640 let mut bytes = segment.bytes();
1641 while let Some(byte) = bytes.next() {
1642 let permitted = byte.is_ascii_alphanumeric()
1643 || matches!(
1644 byte,
1645 b'-' | b'.'
1646 | b'_'
1647 | b'~'
1648 | b':'
1649 | b'/'
1650 | b'?'
1651 | b'@'
1652 | b'!'
1653 | b'$'
1654 | b'&'
1655 | b'\''
1656 | b'('
1657 | b')'
1658 | b'*'
1659 | b'+'
1660 | b','
1661 | b';'
1662 | b'='
1663 );
1664 if byte == b'%' {
1665 let mut pair = [bytes.next(), bytes.next()].into_iter();
1666 if !pair.all(|digit| digit.is_some_and(|digit| digit.is_ascii_hexdigit())) {
1667 return false;
1668 }
1669 } else if !permitted {
1670 return false;
1671 }
1672 }
1673 true
1674}
1675
1676pub(crate) fn is_uri(text: &str) -> bool {
1683 uri::<true>(text)
1684}
1685
1686pub(crate) fn is_cps_uri(text: &str) -> bool {
1690 uri::<false>(text)
1691}
1692
1693pub fn uri_syntax<W: Work>(text: &str, execution: &W) -> core::result::Result<bool, MemoryError> {
1699 let units = (text.len() as u64)
1700 .checked_mul(12)
1701 .and_then(|n| n.checked_add(1))
1702 .ok_or(MemoryError::WorkExceeded)?;
1703 execution.charge_work(units)?;
1704 Ok(is_cps_uri(text))
1705}
1706
1707fn location_uri(
1708 parent: &Reader<'_, '_>,
1709 element: &Element<'_>,
1710 text: &str,
1711 field: &'static str,
1712) -> Result<bool> {
1713 let work = u64::try_from(text.len())
1716 .ok()
1717 .and_then(|n| n.checked_mul(32))
1718 .and_then(|n| n.checked_add(256))
1719 .ok_or_else(|| {
1720 Error::resource(
1721 structured_asn1::memory::MemoryError::WorkExceeded,
1722 field,
1723 element.span().start,
1724 )
1725 })?;
1726 parent.charge(work).field(field)?;
1727 if !is_cps_uri(text) {
1728 return Ok(false);
1729 }
1730 if text
1731 .split_once(':')
1732 .is_some_and(|(scheme, _)| scheme.eq_ignore_ascii_case("ldap"))
1733 {
1734 return ldap::valid(parent, element, text, field);
1735 }
1736 Ok(known_location_authority_fits(text))
1737}
1738
1739fn known_location_authority_fits(text: &str) -> bool {
1740 let (scheme, rest) = text.split_once(':').expect("URI syntax checked");
1741 let ftp = scheme.eq_ignore_ascii_case("ftp");
1742 if !ftp && !scheme.eq_ignore_ascii_case("http") && !scheme.eq_ignore_ascii_case("https") {
1743 return true;
1749 }
1750 let Some(after) = rest.strip_prefix("//") else {
1756 return false;
1757 };
1758 let end = after.find(['/', '?', '#']).unwrap_or(after.len());
1759 let authority = &after[..end];
1760 let host_port = authority
1761 .rsplit_once('@')
1762 .map_or(authority, |(_, host)| host);
1763 if host_port.starts_with('[') {
1764 return true;
1766 }
1767 let host = host_port
1768 .split_once(':')
1769 .map_or(host_port, |(host, _)| host);
1770 if host.is_empty() {
1771 return false;
1772 }
1773 !ftp || is_domain(host.strip_suffix('.').unwrap_or(host)) || host.parse::<Ipv4Addr>().is_ok()
1774}
1775
1776fn uri<const CERTIFICATE_NAME: bool>(text: &str) -> bool {
1777 match text.split_once('#') {
1778 Some((rest, fragment)) => absolute_uri::<CERTIFICATE_NAME>(rest) && uri_alphabet(fragment),
1781 None => absolute_uri::<CERTIFICATE_NAME>(text),
1782 }
1783}
1784
1785fn is_ip_literal(text: &str) -> bool {
1790 if let Some(rest) = text.strip_prefix(['v', 'V']) {
1791 let Some((version, suffix)) = rest.split_once('.') else {
1793 return false;
1794 };
1795 return !version.is_empty()
1796 && version.bytes().all(|byte| byte.is_ascii_hexdigit())
1797 && !suffix.is_empty()
1798 && suffix.bytes().all(|byte| {
1799 byte.is_ascii_alphanumeric()
1800 || matches!(
1801 byte,
1802 b'-' | b'.'
1803 | b'_'
1804 | b'~'
1805 | b':'
1806 | b'!'
1807 | b'$'
1808 | b'&'
1809 | b'\''
1810 | b'('
1811 | b')'
1812 | b'*'
1813 | b'+'
1814 | b','
1815 | b';'
1816 | b'='
1817 )
1818 });
1819 }
1820 text.parse::<Ipv6Addr>().is_ok()
1821}
1822
1823fn is_contiguous_mask(mask: &[u8]) -> bool {
1824 let mut still_ones = true;
1825 for &byte in mask {
1826 if still_ones {
1827 if byte == 0xff {
1828 continue;
1829 }
1830 let ones = byte.leading_ones();
1832 let expected = if ones == 0 { 0 } else { 0xffu8 << (8 - ones) };
1833 if byte != expected {
1834 return false;
1835 }
1836 still_ones = false;
1837 } else if byte != 0 {
1838 return false;
1839 }
1840 }
1841 true
1842}
1843
1844fn text<'a>(
1845 parent: &Reader<'a, '_>,
1846 contents: &'a [u8],
1847 field: &'static str,
1848 element: &Element<'a>,
1849) -> Result<&'a str> {
1850 parent.charge(contents.len() as u64).field(field)?;
1854 if contents.is_empty() {
1858 return Err(Error::new(
1859 ErrorCode::MalformedValue,
1860 field,
1861 element.span().start,
1862 ));
1863 }
1864 if !contents.is_ascii() {
1865 return Err(Error::new(
1870 ErrorCode::MalformedValue,
1871 field,
1872 element.span().start,
1873 ));
1874 }
1875 core::str::from_utf8(contents)
1876 .map_err(|_| Error::new(ErrorCode::MalformedValue, field, element.span().start))
1877}
1878
1879#[cfg(test)]
1880mod tests;