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, OwnedVec};
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(crate) fn matches_at(
120 left: &GeneralName<'_>,
121 right: &GeneralName<'_>,
122 execution: &impl structured_asn1::memory::Work,
123 at: u64,
124 field: &'static str,
125) -> Result<bool> {
126 equality::matches(left, right, execution, None, at, field)
127}
128
129pub(crate) fn read_all<'a>(
131 parent: &Reader<'a, '_>,
132 element: &Element<'a>,
133 field: &'static str,
134) -> Result<OwnedVec<GeneralName<'a>>> {
135 let mut inside = parent.enter(element).field(field)?;
136 read_list(&mut inside, field, element.span().start)
137}
138
139pub(crate) fn read_list<'a>(
141 inside: &mut Reader<'a, '_>,
142 field: &'static str,
143 offset: u64,
144) -> Result<OwnedVec<GeneralName<'a>>> {
145 read_list_as(inside, field, offset, AddressForm::Single)
146}
147
148pub(crate) fn read_locations<'a>(
152 parent: &Reader<'a, '_>,
153 element: &Element<'a>,
154 field: &'static str,
155) -> Result<OwnedVec<GeneralName<'a>>> {
156 let mut inside = parent.enter(element).field(field)?;
157 read_list_as(
158 &mut inside,
159 field,
160 element.span().start,
161 AddressForm::Location,
162 )
163}
164
165fn read_list_as<'a>(
166 inside: &mut Reader<'a, '_>,
167 field: &'static str,
168 offset: u64,
169 form: AddressForm,
170) -> Result<OwnedVec<GeneralName<'a>>> {
171 let mut names = inside.memory().vector();
172 while let Some(entry) = inside.next_element().field(field)? {
173 let name = read_as(inside, &entry, field, form)?;
174 let work = inside.execution();
175 let Ok(mut scoped) = names.with_execution(&work) else {
179 unreachable!("the name decoder preserves its catalogue account")
180 };
181 scoped
182 .try_push(name)
183 .map_err(|reason| Error::resource(reason, field, entry.span().start))?;
184 names = scoped.into_owned();
185 }
186
187 if names.is_empty() {
190 return Err(Error::new(ErrorCode::EmptySequence, field, offset));
191 }
192 Ok(names)
193}
194
195pub fn read_alternative<'a, W: structured_asn1::memory::Work>(
198 extension: &Extension<'a>,
199 execution: &W,
200) -> Result<OwnedVec<GeneralName<'a>>> {
201 let field = if extension.kind() == crate::oid::ISSUER_ALT_NAME {
202 "extensions.issuerAltName"
203 } else {
204 "extensions.subjectAltName"
205 };
206
207 let mut inside = extension::sequence(extension, field, execution)?;
208 read_list(&mut inside, field, extension.span().start)
209}
210
211#[derive(Debug, Clone, Copy, PartialEq, Eq)]
218pub(crate) enum AddressForm {
219 Single,
221 Location,
223 WithMask,
226}
227
228impl AddressForm {
229 fn permits(self, length: usize) -> bool {
230 match self {
231 Self::Single | Self::Location => length == 4 || length == 16,
232 Self::WithMask => length == 8 || length == 32,
233 }
234 }
235}
236
237pub fn read<'a>(
248 parent: &Reader<'a, '_>,
249 element: &Element<'a>,
250 field: &'static str,
251) -> Result<GeneralName<'a>> {
252 read_as(parent, element, field, AddressForm::Single)
253}
254
255fn mailbox_fits(text: &str, address_form: AddressForm) -> bool {
261 match address_form {
262 AddressForm::Single | AddressForm::Location => is_mailbox(text),
263 AddressForm::WithMask => {
264 is_mailbox(text) || is_domain(text) || text.strip_prefix('.').is_some_and(is_domain)
265 }
266 }
267}
268
269fn domain_fits(text: &str, address_form: AddressForm) -> bool {
286 match address_form {
287 AddressForm::Single | AddressForm::Location => is_domain(text),
288 AddressForm::WithMask => is_domain(text) || text.strip_prefix('.').is_some_and(is_domain),
289 }
290}
291
292pub(crate) fn read_as<'a>(
293 parent: &Reader<'a, '_>,
294 element: &Element<'a>,
295 field: &'static str,
296 address_form: AddressForm,
297) -> Result<GeneralName<'a>> {
298 let fail = |code| Error::new(code, field, element.span().start);
299 let tag = element.tag();
300
301 if tag.class() != Class::ContextSpecific {
302 return Err(fail(ErrorCode::Encoding(
303 structured_asn1::ErrorCode::UnexpectedTag,
304 )));
305 }
306
307 let Some(number) = tag.number() else {
314 return Err(fail(ErrorCode::Encoding(
315 structured_asn1::ErrorCode::UnexpectedTag,
316 )));
317 };
318 match (number, tag.is_constructed()) {
319 (0, true) => read_other(parent, element, field),
320 (1, false) => {
321 let email = text(parent, element.contents(), field, element)?;
322 if !mailbox_fits(email, address_form) {
323 return Err(fail(ErrorCode::MalformedValue));
324 }
325 Ok(GeneralName::Email(email))
326 }
327 (2, false) => {
328 let domain = text(parent, element.contents(), field, element)?;
329 if !domain_fits(domain, address_form) {
330 return Err(fail(ErrorCode::MalformedValue));
331 }
332 Ok(GeneralName::Dns(domain))
333 }
334 (3, true) => {
335 read_x400(parent, element, field)?;
336 Ok(GeneralName::X400(element.contents()))
337 }
338 (4, true) => {
339 let mut inside = parent.enter(element).field(field)?;
342 let inner = inside
343 .next_element()
344 .field(field)?
345 .ok_or_else(|| fail(ErrorCode::MissingField))?;
346 let name = name::read(&inside, &inner, field)?;
347 if address_form != AddressForm::WithMask && name.is_empty() {
360 return Err(fail(ErrorCode::MalformedValue));
361 }
362 for attribute in name.attributes() {
363 if !name::well_formed_in(attribute, &inside, field)? {
364 return Err(fail(ErrorCode::MalformedValue));
365 }
366 }
367 if !inside.is_empty() {
368 return Err(fail(ErrorCode::TrailingData));
369 }
370 Ok(GeneralName::Directory(name))
371 }
372 (5, true) => {
373 read_edi_party(parent, element, field)?;
374 Ok(GeneralName::EdiParty(element.contents()))
375 }
376 (6, false) => {
377 let location = text(parent, element.contents(), field, element)?;
378 let fits = match address_form {
387 AddressForm::Single => {
388 parent.charge(location.len() as u64).field(field)?;
391 is_uri(location)
392 }
393 AddressForm::Location => {
394 location_uri(parent, element, location, field)?
398 }
399 AddressForm::WithMask => {
400 is_domain(location) || location.strip_prefix('.').is_some_and(is_domain)
401 }
402 };
403 if !fits {
404 return Err(fail(ErrorCode::MalformedValue));
405 }
406 Ok(GeneralName::Uri(location))
407 }
408 (7, false) => {
409 let contents = element.contents();
410 if !address_form.permits(contents.len()) {
411 return Err(fail(ErrorCode::MalformedValue));
412 }
413 if address_form == AddressForm::WithMask
417 && !is_contiguous_mask(&contents[contents.len() / 2..])
418 {
419 return Err(fail(ErrorCode::MalformedValue));
420 }
421 Ok(GeneralName::IpAddress(contents))
422 }
423 (8, false) => parent
424 .oid(element)
425 .field(field)
426 .map(GeneralName::RegisteredId),
427 _ => Err(fail(ErrorCode::Encoding(
428 structured_asn1::ErrorCode::UnexpectedTag,
429 ))),
430 }
431}
432
433fn read_x400<'a>(
441 parent: &Reader<'a, '_>,
442 element: &Element<'a>,
443 field: &'static str,
444) -> Result<()> {
445 let fail = |code| Error::new(code, field, element.span().start);
446
447 let mut inside = parent.enter(element).field(field)?;
448 let standard = inside
449 .next_element()
450 .field(field)?
451 .ok_or_else(|| fail(ErrorCode::MissingField))?;
452 if standard.tag() != Tag::constructed(universal::SEQUENCE) {
453 return Err(fail(ErrorCode::Encoding(
454 structured_asn1::ErrorCode::UnexpectedTag,
455 )));
456 }
457 read_standard_attributes(&inside, &standard, field)?;
458
459 let mut next = inside.next_element().field(field)?;
461 if let Some(domain_defined) = next
462 && domain_defined.tag() == Tag::constructed(universal::SEQUENCE)
463 {
464 read_domain_defined(&inside, &domain_defined, field)?;
465 next = inside.next_element().field(field)?;
466 }
467 if let Some(extensions) = next {
468 if extensions.tag() != Tag::constructed(universal::SET) {
469 return Err(fail(ErrorCode::Encoding(
470 structured_asn1::ErrorCode::UnexpectedTag,
471 )));
472 }
473 read_extension_attributes(&inside, &extensions, field)?;
474 if !inside.is_empty() {
475 return Err(fail(ErrorCode::TrailingData));
476 }
477 }
478 Ok(())
479}
480
481const X400_NUMERIC_STRING: u32 = 18;
484
485fn x400_string(element: &Element<'_>, field: &'static str, size: (usize, usize)) -> Result<()> {
489 let fail = |code| Error::new(code, field, element.span().start);
490 let contents = element.contents();
491 let fits = match (
494 element.tag().class(),
495 element.tag().number(),
496 element.tag().is_constructed(),
497 ) {
498 (Class::Universal, Some(X400_NUMERIC_STRING), false) => crate::name::is_numeric(contents),
499 (Class::Universal, Some(universal::PRINTABLE_STRING), false) => {
500 crate::name::is_printable(contents)
501 }
502 _ => {
503 return Err(fail(ErrorCode::Encoding(
504 structured_asn1::ErrorCode::UnexpectedTag,
505 )));
506 }
507 };
508 if !fits || contents.len() < size.0 || contents.len() > size.1 {
509 return Err(fail(ErrorCode::MalformedValue));
510 }
511 Ok(())
512}
513
514fn x400_printable(element: &Element<'_>, field: &'static str, size: (usize, usize)) -> Result<()> {
517 let fail = |code| Error::new(code, field, element.span().start);
518 let tag = element.tag();
519 if tag.class() != Class::Universal
520 || tag.number() != Some(universal::PRINTABLE_STRING)
521 || tag.is_constructed()
522 {
523 return Err(fail(ErrorCode::Encoding(
524 structured_asn1::ErrorCode::UnexpectedTag,
525 )));
526 }
527 let contents = element.contents();
528 if !crate::name::is_printable(contents) || contents.len() < size.0 || contents.len() > size.1 {
529 return Err(fail(ErrorCode::MalformedValue));
530 }
531 Ok(())
532}
533
534#[derive(Clone, Copy)]
538enum X400Repertoire {
539 Numeric,
540 Printable,
541 Teletex,
542}
543
544fn x400_implicit(
547 element: &Element<'_>,
548 field: &'static str,
549 repertoire: X400Repertoire,
550 most: usize,
551) -> Result<()> {
552 let fail = |code| Error::new(code, field, element.span().start);
553 let contents = element.contents();
554 if contents.is_empty() || contents.len() > most {
561 return Err(fail(ErrorCode::MalformedValue));
562 }
563 let fits = match repertoire {
564 X400Repertoire::Numeric => crate::name::is_numeric(contents),
565 X400Repertoire::Printable => crate::name::is_printable(contents),
566 X400Repertoire::Teletex => true,
567 };
568 if !fits {
569 return Err(fail(ErrorCode::MalformedValue));
570 }
571 Ok(())
572}
573
574fn x400_teletex(element: &Element<'_>, field: &'static str, size: (usize, usize)) -> Result<()> {
576 let fail = |code| Error::new(code, field, element.span().start);
577 if element.tag() != Tag::primitive(20) {
580 return Err(fail(ErrorCode::Encoding(
581 structured_asn1::ErrorCode::UnexpectedTag,
582 )));
583 }
584 let length = element.contents().len();
585 if length < size.0 || length > size.1 {
586 return Err(fail(ErrorCode::MalformedValue));
587 }
588 Ok(())
589}
590
591fn x400_bare_country(value: &Element<'_>, field: &'static str) -> Result<()> {
595 let fail = |code| Error::new(code, field, value.span().start);
596 let contents = value.contents();
597 let fits = match (
598 value.tag().class(),
599 value.tag().number(),
600 value.tag().is_constructed(),
601 ) {
602 (Class::Universal, Some(X400_NUMERIC_STRING), false) => {
603 contents.len() == 3 && contents.iter().all(u8::is_ascii_digit)
604 }
605 (Class::Universal, Some(universal::PRINTABLE_STRING), false) => {
606 contents.len() == 2 && contents.iter().all(u8::is_ascii_uppercase)
607 }
608 _ => {
609 return Err(fail(ErrorCode::Encoding(
610 structured_asn1::ErrorCode::UnexpectedTag,
611 )));
612 }
613 };
614 if !fits {
615 return Err(fail(ErrorCode::MalformedValue));
616 }
617 Ok(())
618}
619
620fn x400_country<'a>(
622 parent: &Reader<'a, '_>,
623 wrapper: &Element<'a>,
624 field: &'static str,
625) -> Result<()> {
626 let fail = |code| Error::new(code, field, wrapper.span().start);
627 let mut inside = parent.enter(wrapper).field(field)?;
628 let value = inside
629 .next_element()
630 .field(field)?
631 .ok_or_else(|| fail(ErrorCode::MissingField))?;
632 if !inside.is_empty() {
633 return Err(fail(ErrorCode::TrailingData));
634 }
635 x400_bare_country(&value, field)
636}
637
638fn x400_choice<'a>(
641 parent: &Reader<'a, '_>,
642 wrapper: &Element<'a>,
643 field: &'static str,
644 numeric: (usize, usize),
645 printable: (usize, usize),
646) -> Result<()> {
647 let fail = |code| Error::new(code, field, wrapper.span().start);
648 let mut inside = parent.enter(wrapper).field(field)?;
649 let value = inside
650 .next_element()
651 .field(field)?
652 .ok_or_else(|| fail(ErrorCode::MissingField))?;
653 if !inside.is_empty() {
654 return Err(fail(ErrorCode::TrailingData));
655 }
656 let size = match (value.tag().class(), value.tag().number()) {
657 (Class::Universal, Some(X400_NUMERIC_STRING)) => numeric,
658 (Class::Universal, Some(universal::PRINTABLE_STRING)) => printable,
659 _ => {
660 return Err(fail(ErrorCode::Encoding(
661 structured_asn1::ErrorCode::UnexpectedTag,
662 )));
663 }
664 };
665 x400_string(&value, field, size)
666}
667
668fn read_standard_attributes<'a>(
672 parent: &Reader<'a, '_>,
673 element: &Element<'a>,
674 field: &'static str,
675) -> Result<()> {
676 let mut inside = parent.enter(element).field(field)?;
677 let mut last_rank = -1i8;
678 while let Some(member) = inside.next_element().field(field)? {
679 let bad = |code| Error::new(code, field, member.span().start);
680 let tag = member.tag();
681 let Some(number) = tag.number() else {
684 return Err(bad(ErrorCode::Encoding(
685 structured_asn1::ErrorCode::UnexpectedTag,
686 )));
687 };
688 let rank: i8 = match (tag.class(), number, tag.is_constructed()) {
689 (Class::Application, 1, true) => {
692 x400_country(&inside, &member, field)?;
693 0
694 }
695 (Class::Application, 2, true) => {
698 x400_choice(&inside, &member, field, (0, 16), (0, 16))?;
699 1
700 }
701 (Class::ContextSpecific, 0, false) => {
703 x400_implicit(&member, field, X400Repertoire::Numeric, 16)?;
704 2
705 }
706 (Class::ContextSpecific, 1, false) => {
708 x400_implicit(&member, field, X400Repertoire::Printable, 24)?;
709 3
710 }
711 (Class::ContextSpecific, 2, true) => {
713 x400_choice(&inside, &member, field, (1, 16), (1, 16))?;
714 4
715 }
716 (Class::ContextSpecific, 3, false) => {
718 x400_implicit(&member, field, X400Repertoire::Printable, 64)?;
719 5
720 }
721 (Class::ContextSpecific, 4, false) => {
723 x400_implicit(&member, field, X400Repertoire::Numeric, 32)?;
724 6
725 }
726 (Class::ContextSpecific, 5, true) => {
728 read_personal_name(&inside, &member, field, X400Repertoire::Printable)?;
729 7
730 }
731 (Class::ContextSpecific, 6, true) => {
735 let mut units = inside.enter(&member).field(field)?;
736 let mut count = 0usize;
737 while let Some(unit) = units.next_element().field(field)? {
738 x400_printable(&unit, field, (1, 32))?;
739 count += 1;
740 }
741 if !(1..=4).contains(&count) {
742 return Err(bad(ErrorCode::MalformedValue));
743 }
744 8
745 }
746 _ => {
747 return Err(bad(ErrorCode::Encoding(
748 structured_asn1::ErrorCode::UnexpectedTag,
749 )));
750 }
751 };
752 if rank <= last_rank {
756 return Err(bad(ErrorCode::UnexpectedField));
757 }
758 last_rank = rank;
759 }
760 Ok(())
761}
762
763fn read_personal_name<'a>(
767 parent: &Reader<'a, '_>,
768 element: &Element<'a>,
769 field: &'static str,
770 repertoire: X400Repertoire,
771) -> Result<()> {
772 let fail = |code| Error::new(code, field, element.span().start);
773 let mut inside = parent.enter(element).field(field)?;
774 let mut seen = [false; 4];
775 let mut last: Option<usize> = None;
776 while let Some(part) = inside.next_element().field(field)? {
777 let bad = |code| Error::new(code, field, part.span().start);
778 let (number, most) = match (
779 part.tag().class(),
780 part.tag().number(),
781 part.tag().is_constructed(),
782 ) {
783 (Class::ContextSpecific, Some(0), false) => (0usize, 40),
784 (Class::ContextSpecific, Some(1), false) => (1, 16),
785 (Class::ContextSpecific, Some(2), false) => (2, 5),
786 (Class::ContextSpecific, Some(3), false) => (3, 3),
787 _ => {
788 return Err(bad(ErrorCode::Encoding(
789 structured_asn1::ErrorCode::UnexpectedTag,
790 )));
791 }
792 };
793 if seen[number] {
794 return Err(bad(ErrorCode::UnexpectedField));
795 }
796 if inside.encoding().is_der() && last.is_some_and(|last| number < last) {
800 return Err(bad(ErrorCode::UnexpectedField));
801 }
802 seen[number] = true;
803 last = Some(number);
804 x400_implicit(&part, field, repertoire, most)?;
805 }
806 if !seen[0] {
807 return Err(fail(ErrorCode::MissingField));
808 }
809 Ok(())
810}
811
812fn read_domain_defined<'a>(
815 parent: &Reader<'a, '_>,
816 element: &Element<'a>,
817 field: &'static str,
818) -> Result<()> {
819 read_defined_pairs(parent, element, field, false)
820}
821
822fn read_defined_pairs<'a>(
825 parent: &Reader<'a, '_>,
826 element: &Element<'a>,
827 field: &'static str,
828 teletex: bool,
829) -> Result<()> {
830 let fail = |code| Error::new(code, field, element.span().start);
831 if element.tag() != Tag::constructed(universal::SEQUENCE) {
832 return Err(fail(ErrorCode::Encoding(
833 structured_asn1::ErrorCode::UnexpectedTag,
834 )));
835 }
836 let held_string = |element: &Element<'_>, size: (usize, usize)| {
837 if teletex {
838 x400_teletex(element, field, size)
839 } else {
840 x400_printable(element, field, size)
843 }
844 };
845 let mut inside = parent.enter(element).field(field)?;
846 let mut count = 0usize;
847 while let Some(pair) = inside.next_element().field(field)? {
848 let bad = |code| Error::new(code, field, pair.span().start);
849 if pair.tag() != Tag::constructed(universal::SEQUENCE) {
850 return Err(bad(ErrorCode::Encoding(
851 structured_asn1::ErrorCode::UnexpectedTag,
852 )));
853 }
854 let mut two = inside.enter(&pair).field(field)?;
855 let kind = two
856 .next_element()
857 .field(field)?
858 .ok_or_else(|| bad(ErrorCode::MissingField))?;
859 held_string(&kind, (1, 8))?;
860 let value = two
861 .next_element()
862 .field(field)?
863 .ok_or_else(|| bad(ErrorCode::MissingField))?;
864 held_string(&value, (1, 128))?;
865 if !two.is_empty() {
866 return Err(bad(ErrorCode::TrailingData));
867 }
868 count += 1;
869 }
870 if !(1..=4).contains(&count) {
871 return Err(fail(ErrorCode::MalformedValue));
872 }
873 Ok(())
874}
875
876fn read_extension_attributes<'a>(
880 parent: &Reader<'a, '_>,
881 element: &Element<'a>,
882 field: &'static str,
883) -> Result<()> {
884 let fail = |code| Error::new(code, field, element.span().start);
885 let mut inside = parent.enter(element).field(field)?;
886 let mut count = 0usize;
887 let mut previous: Option<&[u8]> = None;
888 while let Some(entry) = inside.next_element().field(field)? {
889 let bad = |code| Error::new(code, field, entry.span().start);
890 if entry.tag() != Tag::constructed(universal::SEQUENCE) {
891 return Err(bad(ErrorCode::Encoding(
892 structured_asn1::ErrorCode::UnexpectedTag,
893 )));
894 }
895 if inside.encoding().is_der()
901 && let Some(previous) = previous
902 {
903 inside
904 .charge(previous.len().max(entry.as_bytes().len()) as u64)
905 .field(field)?;
906 if entry.as_bytes() < previous {
907 return Err(bad(ErrorCode::UnexpectedField));
908 }
909 }
910 previous = Some(entry.as_bytes());
911 let mut two = inside.enter(&entry).field(field)?;
912 let kind = two
913 .next_element()
914 .field(field)?
915 .ok_or_else(|| bad(ErrorCode::MissingField))?;
916 if extension::context_of(kind.tag()) != Some((0, false)) {
920 return Err(bad(ErrorCode::Encoding(
921 structured_asn1::ErrorCode::UnexpectedTag,
922 )));
923 }
924 let number = two.integer(&kind).field(field)?;
925 if number.as_u32().is_none_or(|number| number > 256) {
926 return Err(bad(ErrorCode::MalformedValue));
927 }
928 let value = two
929 .next_element()
930 .field(field)?
931 .ok_or_else(|| bad(ErrorCode::MissingField))?;
932 if extension::context_of(value.tag()) != Some((1, true)) {
935 return Err(bad(ErrorCode::Encoding(
936 structured_asn1::ErrorCode::UnexpectedTag,
937 )));
938 }
939 let mut held = two.enter(&value).field(field)?;
940 let Some(declared) = held.next_element().field(field)? else {
941 return Err(bad(ErrorCode::MissingField));
942 };
943 let number = number
948 .as_u32()
949 .expect("bounded to 0..=256 above, which fits");
950 read_extension_value(&held, &declared, number, field)?;
951 if !held.is_empty() || !two.is_empty() {
952 return Err(bad(ErrorCode::TrailingData));
953 }
954 count += 1;
955 if count > 256 {
958 return Err(bad(ErrorCode::MalformedValue));
959 }
960 }
961 if count == 0 {
962 return Err(fail(ErrorCode::EmptySequence));
963 }
964 Ok(())
965}
966
967fn read_extension_value<'a>(
973 parent: &Reader<'a, '_>,
974 value: &Element<'a>,
975 number: u32,
976 field: &'static str,
977) -> Result<()> {
978 let fail = |code| Error::new(code, field, value.span().start);
979 match number {
980 1 => x400_printable(value, field, (1, 64)),
983 2 | 3 => x400_teletex(value, field, (1, 64)),
985 4 => {
987 if value.tag() != Tag::constructed(universal::SET) {
988 return Err(fail(ErrorCode::Encoding(
989 structured_asn1::ErrorCode::UnexpectedTag,
990 )));
991 }
992 read_personal_name(parent, value, field, X400Repertoire::Teletex)
993 }
994 5 => {
996 if value.tag() != Tag::constructed(universal::SEQUENCE) {
997 return Err(fail(ErrorCode::Encoding(
998 structured_asn1::ErrorCode::UnexpectedTag,
999 )));
1000 }
1001 let mut units = parent.enter(value).field(field)?;
1002 let mut count = 0usize;
1003 while let Some(unit) = units.next_element().field(field)? {
1004 x400_teletex(&unit, field, (1, 32))?;
1005 count += 1;
1006 }
1007 if !(1..=4).contains(&count) {
1008 return Err(fail(ErrorCode::MalformedValue));
1009 }
1010 Ok(())
1011 }
1012 6 => read_defined_pairs(parent, value, field, true),
1014 7 => x400_printable(value, field, (1, 16)),
1016 8 => x400_bare_country(value, field),
1019 9 => x400_bare_choice(value, field, (1, 16), (1, 16)),
1021 10..=15 | 17..=21 => read_pds_parameter(parent, value, field, 30),
1024 16 => read_unformatted_address(parent, value, field),
1026 22 => read_extended_network_address(parent, value, field),
1028 23 => {
1030 if value.tag() != Tag::primitive(universal::INTEGER) {
1031 return Err(fail(ErrorCode::Encoding(
1032 structured_asn1::ErrorCode::UnexpectedTag,
1033 )));
1034 }
1035 let option = parent.integer(value).field(field)?;
1036 if option.as_u32().is_none_or(|option| option > 256) {
1037 return Err(fail(ErrorCode::MalformedValue));
1038 }
1039 Ok(())
1040 }
1041 _ => Err(fail(ErrorCode::MalformedValue)),
1042 }
1043}
1044
1045fn x400_bare_choice(
1048 value: &Element<'_>,
1049 field: &'static str,
1050 numeric: (usize, usize),
1051 printable: (usize, usize),
1052) -> Result<()> {
1053 let fail = |code| Error::new(code, field, value.span().start);
1054 let size = match (
1055 value.tag().class(),
1056 value.tag().number(),
1057 value.tag().is_constructed(),
1058 ) {
1059 (Class::Universal, Some(X400_NUMERIC_STRING), false) => numeric,
1060 (Class::Universal, Some(universal::PRINTABLE_STRING), false) => printable,
1061 _ => {
1062 return Err(fail(ErrorCode::Encoding(
1063 structured_asn1::ErrorCode::UnexpectedTag,
1064 )));
1065 }
1066 };
1067 x400_string(value, field, size)
1068}
1069
1070fn read_pds_parameter<'a>(
1073 parent: &Reader<'a, '_>,
1074 value: &Element<'a>,
1075 field: &'static str,
1076 most: usize,
1077) -> Result<()> {
1078 let fail = |code| Error::new(code, field, value.span().start);
1079 if value.tag() != Tag::constructed(universal::SET) {
1080 return Err(fail(ErrorCode::Encoding(
1081 structured_asn1::ErrorCode::UnexpectedTag,
1082 )));
1083 }
1084 let mut inside = parent.enter(value).field(field)?;
1085 let mut seen_printable = false;
1086 let mut seen_teletex = false;
1087 while let Some(member) = inside.next_element().field(field)? {
1088 let bad = |code| Error::new(code, field, member.span().start);
1089 if member.tag() == Tag::primitive(universal::PRINTABLE_STRING) {
1090 if seen_printable || (seen_teletex && inside.encoding().is_der()) {
1095 return Err(bad(ErrorCode::UnexpectedField));
1096 }
1097 seen_printable = true;
1098 x400_string(&member, field, (1, most))?;
1099 } else if member.tag() == Tag::primitive(20) {
1100 if seen_teletex {
1101 return Err(bad(ErrorCode::UnexpectedField));
1102 }
1103 seen_teletex = true;
1104 x400_teletex(&member, field, (1, most))?;
1105 } else {
1106 return Err(bad(ErrorCode::Encoding(
1107 structured_asn1::ErrorCode::UnexpectedTag,
1108 )));
1109 }
1110 }
1111 Ok(())
1112}
1113
1114fn read_unformatted_address<'a>(
1117 parent: &Reader<'a, '_>,
1118 value: &Element<'a>,
1119 field: &'static str,
1120) -> Result<()> {
1121 let fail = |code| Error::new(code, field, value.span().start);
1122 if value.tag() != Tag::constructed(universal::SET) {
1123 return Err(fail(ErrorCode::Encoding(
1124 structured_asn1::ErrorCode::UnexpectedTag,
1125 )));
1126 }
1127 let mut inside = parent.enter(value).field(field)?;
1128 let mut seen_lines = false;
1129 let mut seen_teletex = false;
1130 while let Some(member) = inside.next_element().field(field)? {
1131 let bad = |code| Error::new(code, field, member.span().start);
1132 if member.tag() == Tag::constructed(universal::SEQUENCE) {
1133 if seen_lines || (seen_teletex && inside.encoding().is_der()) {
1138 return Err(bad(ErrorCode::UnexpectedField));
1139 }
1140 seen_lines = true;
1141 let mut lines = inside.enter(&member).field(field)?;
1142 let mut count = 0usize;
1143 while let Some(line) = lines.next_element().field(field)? {
1144 x400_printable(&line, field, (1, 30))?;
1147 count += 1;
1148 }
1149 if !(1..=6).contains(&count) {
1150 return Err(bad(ErrorCode::MalformedValue));
1151 }
1152 } else if member.tag() == Tag::primitive(20) {
1153 if seen_teletex {
1154 return Err(bad(ErrorCode::UnexpectedField));
1155 }
1156 seen_teletex = true;
1157 x400_teletex(&member, field, (1, 180))?;
1158 } else {
1159 return Err(bad(ErrorCode::Encoding(
1160 structured_asn1::ErrorCode::UnexpectedTag,
1161 )));
1162 }
1163 }
1164 Ok(())
1165}
1166
1167fn read_e163_address<'a>(
1169 parent: &Reader<'a, '_>,
1170 value: &Element<'a>,
1171 field: &'static str,
1172) -> Result<()> {
1173 let fail = |code| Error::new(code, field, value.span().start);
1174 let mut inside = parent.enter(value).field(field)?;
1175 let number = inside
1176 .next_element()
1177 .field(field)?
1178 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1179 if extension::context_of(number.tag()) != Some((0, false)) {
1180 return Err(fail(ErrorCode::Encoding(
1181 structured_asn1::ErrorCode::UnexpectedTag,
1182 )));
1183 }
1184 x400_implicit(&number, field, X400Repertoire::Numeric, 15)?;
1185 if let Some(sub) = inside.next_element().field(field)? {
1186 if extension::context_of(sub.tag()) != Some((1, false)) {
1187 return Err(fail(ErrorCode::Encoding(
1188 structured_asn1::ErrorCode::UnexpectedTag,
1189 )));
1190 }
1191 x400_implicit(&sub, field, X400Repertoire::Numeric, 40)?;
1192 }
1193 if !inside.is_empty() {
1194 return Err(fail(ErrorCode::TrailingData));
1195 }
1196 Ok(())
1197}
1198
1199fn read_extended_network_address<'a>(
1203 parent: &Reader<'a, '_>,
1204 value: &Element<'a>,
1205 field: &'static str,
1206) -> Result<()> {
1207 let fail = |code| Error::new(code, field, value.span().start);
1208 if value.tag() == Tag::constructed(universal::SEQUENCE) {
1209 read_e163_address(parent, value, field)
1210 } else if extension::context_of(value.tag()) == Some((0, true)) {
1211 let mut inside = parent.enter(value).field(field)?;
1214 let mut last: i8 = -1;
1215 let mut saw_network = false;
1216 while let Some(member) = inside.next_element().field(field)? {
1217 let bad = |code| Error::new(code, field, member.span().start);
1218 let Some((number, true)) = extension::context_of(member.tag()) else {
1219 return Err(bad(ErrorCode::Encoding(
1220 structured_asn1::ErrorCode::UnexpectedTag,
1221 )));
1222 };
1223 let rank = i8::try_from(number).map_err(|_| {
1224 bad(ErrorCode::Encoding(
1225 structured_asn1::ErrorCode::UnexpectedTag,
1226 ))
1227 })?;
1228 if rank > 3 {
1229 return Err(bad(ErrorCode::Encoding(
1230 structured_asn1::ErrorCode::UnexpectedTag,
1231 )));
1232 }
1233 if rank <= last {
1234 return Err(bad(ErrorCode::UnexpectedField));
1235 }
1236 last = rank;
1237 let mut held = inside.enter(&member).field(field)?;
1238 if rank == 3 {
1239 let addresses = held
1241 .next_element()
1242 .field(field)?
1243 .ok_or_else(|| bad(ErrorCode::MissingField))?;
1244 if addresses.tag() != Tag::constructed(universal::SET) {
1245 return Err(bad(ErrorCode::Encoding(
1246 structured_asn1::ErrorCode::UnexpectedTag,
1247 )));
1248 }
1249 let mut each = held.enter(&addresses).field(field)?;
1250 let mut count = 0usize;
1251 let mut previous: Option<&[u8]> = None;
1252 while let Some(address) = each.next_element().field(field)? {
1253 if address.tag() != Tag::primitive(universal::OCTET_STRING) {
1254 return Err(bad(ErrorCode::Encoding(
1255 structured_asn1::ErrorCode::UnexpectedTag,
1256 )));
1257 }
1258 if each.encoding().is_der()
1264 && let Some(previous) = previous
1265 {
1266 each.charge(previous.len().max(address.as_bytes().len()) as u64)
1267 .field(field)?;
1268 if address.as_bytes() < previous {
1269 return Err(bad(ErrorCode::UnexpectedField));
1270 }
1271 }
1272 previous = Some(address.as_bytes());
1273 count += 1;
1274 }
1275 if count == 0 {
1276 return Err(bad(ErrorCode::EmptySequence));
1277 }
1278 saw_network = true;
1279 } else {
1280 let selector = held
1282 .next_element()
1283 .field(field)?
1284 .ok_or_else(|| bad(ErrorCode::MissingField))?;
1285 if selector.tag() != Tag::primitive(universal::OCTET_STRING) {
1286 return Err(bad(ErrorCode::Encoding(
1287 structured_asn1::ErrorCode::UnexpectedTag,
1288 )));
1289 }
1290 }
1291 if !held.is_empty() {
1292 return Err(bad(ErrorCode::TrailingData));
1293 }
1294 }
1295 if !saw_network {
1296 return Err(fail(ErrorCode::MissingField));
1297 }
1298 Ok(())
1299 } else {
1300 Err(fail(ErrorCode::Encoding(
1301 structured_asn1::ErrorCode::UnexpectedTag,
1302 )))
1303 }
1304}
1305
1306fn read_edi_party<'a>(
1311 parent: &Reader<'a, '_>,
1312 element: &Element<'a>,
1313 field: &'static str,
1314) -> Result<()> {
1315 let fail = |code| Error::new(code, field, element.span().start);
1316
1317 let mut inside = parent.enter(element).field(field)?;
1318 let mut next = inside.next_element().field(field)?;
1319
1320 if let Some(assigner) = next
1321 && extension::context_of(assigner.tag()) == Some((0, true))
1322 {
1323 require_directory_string(&inside, &assigner, field)?;
1324 next = inside.next_element().field(field)?;
1325 }
1326
1327 let party = next.ok_or_else(|| fail(ErrorCode::MissingField))?;
1328 if extension::context_of(party.tag()) != Some((1, true)) {
1329 return Err(Error::new(
1330 ErrorCode::UnexpectedField,
1331 field,
1332 party.span().start,
1333 ));
1334 }
1335 require_directory_string(&inside, &party, field)?;
1336
1337 if !inside.is_empty() {
1338 return Err(fail(ErrorCode::TrailingData));
1339 }
1340 Ok(())
1341}
1342
1343fn require_directory_string<'a>(
1345 parent: &Reader<'a, '_>,
1346 wrapper: &Element<'a>,
1347 field: &'static str,
1348) -> Result<()> {
1349 const MOST: usize = 32768;
1351 let fail = |code| Error::new(code, field, wrapper.span().start);
1352
1353 let mut inside = parent.enter(wrapper).field(field)?;
1354 let value = inside
1355 .next_element()
1356 .field(field)?
1357 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1358 if !inside.is_empty() {
1359 return Err(fail(ErrorCode::TrailingData));
1360 }
1361
1362 let tag = value.tag();
1367 let is_directory_string = tag.class() == Class::Universal
1368 && !tag.is_constructed()
1369 && matches!(tag.number(), Some(12 | 19 | 20 | 28 | 30));
1370 let ceiling = match tag.number() {
1375 Some(12 | 28) => MOST.saturating_mul(4),
1376 Some(30) => MOST.saturating_mul(2),
1377 _ => MOST,
1378 };
1379 if value.contents().len() > ceiling {
1380 return Err(fail(ErrorCode::MalformedValue));
1381 }
1382 parent.charge(value.contents().len() as u64).field(field)?;
1386 let decodes = match tag.number() {
1387 Some(12) => {
1388 core::str::from_utf8(value.contents()).is_ok_and(|text| text.chars().count() <= MOST)
1389 }
1390 Some(19) => crate::name::is_printable(value.contents()) && value.contents().len() <= MOST,
1391 Some(28) => {
1392 crate::name::wide_char_count(value.contents(), 4).is_some_and(|count| count <= MOST)
1393 }
1394 Some(30) => {
1395 crate::name::wide_char_count(value.contents(), 2).is_some_and(|count| count <= MOST)
1396 }
1397 _ => value.contents().len() <= MOST,
1401 };
1402 if !is_directory_string || value.contents().is_empty() || !decodes {
1403 return Err(fail(ErrorCode::MalformedValue));
1404 }
1405 Ok(())
1406}
1407
1408fn read_other<'a>(
1409 parent: &Reader<'a, '_>,
1410 element: &Element<'a>,
1411 field: &'static str,
1412) -> Result<GeneralName<'a>> {
1413 let fail = |code| Error::new(code, field, element.span().start);
1414
1415 let mut inside = parent.enter(element).field(field)?;
1416 let type_id = inside.read_oid().field(field)?;
1417 let wrapper = inside
1418 .next_element()
1419 .field(field)?
1420 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1421
1422 if wrapper.tag() != Tag::context(true, 0) {
1425 return Err(fail(ErrorCode::Encoding(
1426 structured_asn1::ErrorCode::UnexpectedTag,
1427 )));
1428 }
1429 if !inside.is_empty() {
1430 return Err(fail(ErrorCode::TrailingData));
1431 }
1432
1433 let mut held = inside.enter(&wrapper).field(field)?;
1437 let value = held
1438 .next_element()
1439 .field(field)?
1440 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1441 if !held.is_empty() {
1442 return Err(fail(ErrorCode::TrailingData));
1443 }
1444
1445 crate::name::walk_der(&held, &value, field, crate::name::Strings::Checked)?;
1452
1453 Ok(GeneralName::Other {
1454 type_id,
1455 value: value.as_bytes(),
1456 })
1457}
1458
1459pub(crate) fn is_domain(text: &str) -> bool {
1465 text.len() <= 253
1471 && text.split('.').all(|label| {
1472 (1..=63).contains(&label.len())
1473 && label
1474 .bytes()
1475 .all(|byte| byte.is_ascii_alphanumeric() || byte == b'-')
1476 && !label.starts_with('-')
1477 && !label.ends_with('-')
1478 })
1479 && text
1480 .rsplit('.')
1481 .next()
1482 .is_some_and(|top| top.bytes().any(|byte| byte.is_ascii_alphabetic()))
1483}
1484
1485pub(crate) fn is_mailbox(text: &str) -> bool {
1497 structured_email_address::is_smtp_mailbox(text)
1498}
1499
1500pub(crate) fn is_absolute_uri(text: &str) -> bool {
1508 absolute_uri::<true>(text)
1509}
1510
1511fn absolute_uri<const CERTIFICATE_NAME: bool>(text: &str) -> bool {
1512 let Some((scheme, rest)) = text.split_once(':') else {
1513 return false;
1514 };
1515 let mut bytes = scheme.bytes();
1516 if !(bytes.next().is_some_and(|byte| byte.is_ascii_alphabetic())
1517 && bytes.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'+' | b'-' | b'.')))
1518 {
1519 return false;
1520 }
1521 if CERTIFICATE_NAME && rest.is_empty() {
1529 return false;
1530 }
1531
1532 let mut userinfo = "";
1538 let mut bare_host = "";
1539 let mut tail = rest;
1540 if let Some(after) = rest.strip_prefix("//") {
1541 let end = after.find(['/', '?']).unwrap_or(after.len());
1542 let authority = &after[..end];
1543 tail = &after[end..];
1544 let (before, host_port) = match authority.split_once('@') {
1545 Some((before, host_port)) => (before, host_port),
1546 None => ("", authority),
1547 };
1548 if host_port.contains('@') {
1551 return false;
1552 }
1553 userinfo = before;
1554 let port = if let Some(inside) = host_port.strip_prefix('[') {
1555 let Some((literal, past)) = inside.split_once(']') else {
1556 return false;
1557 };
1558 if !is_ip_literal(literal) {
1559 return false;
1560 }
1561 if past.is_empty() {
1563 None
1564 } else {
1565 let Some(digits) = past.strip_prefix(':') else {
1566 return false;
1567 };
1568 Some(digits)
1569 }
1570 } else {
1571 let port = if let Some((host, port)) = host_port.split_once(':') {
1574 bare_host = host;
1575 Some(port)
1576 } else {
1577 bare_host = host_port;
1578 None
1579 };
1580 let named = bare_host.strip_suffix('.').unwrap_or(bare_host);
1592 if CERTIFICATE_NAME && !is_domain(named) && bare_host.parse::<Ipv4Addr>().is_err() {
1593 return false;
1594 }
1595 port
1596 };
1597 if port.is_some_and(|digits| !digits.bytes().all(|byte| byte.is_ascii_digit())) {
1599 return false;
1600 }
1601 }
1602
1603 uri_alphabet(userinfo) && uri_alphabet(bare_host) && uri_alphabet(tail)
1604}
1605
1606fn uri_alphabet(segment: &str) -> bool {
1611 let mut bytes = segment.bytes();
1612 while let Some(byte) = bytes.next() {
1613 let permitted = byte.is_ascii_alphanumeric()
1614 || matches!(
1615 byte,
1616 b'-' | b'.'
1617 | b'_'
1618 | b'~'
1619 | b':'
1620 | b'/'
1621 | b'?'
1622 | b'@'
1623 | b'!'
1624 | b'$'
1625 | b'&'
1626 | b'\''
1627 | b'('
1628 | b')'
1629 | b'*'
1630 | b'+'
1631 | b','
1632 | b';'
1633 | b'='
1634 );
1635 if byte == b'%' {
1636 let mut pair = [bytes.next(), bytes.next()].into_iter();
1637 if !pair.all(|digit| digit.is_some_and(|digit| digit.is_ascii_hexdigit())) {
1638 return false;
1639 }
1640 } else if !permitted {
1641 return false;
1642 }
1643 }
1644 true
1645}
1646
1647pub(crate) fn is_uri(text: &str) -> bool {
1654 uri::<true>(text)
1655}
1656
1657pub(crate) fn is_cps_uri(text: &str) -> bool {
1661 uri::<false>(text)
1662}
1663
1664fn location_uri(
1665 parent: &Reader<'_, '_>,
1666 element: &Element<'_>,
1667 text: &str,
1668 field: &'static str,
1669) -> Result<bool> {
1670 let work = u64::try_from(text.len())
1673 .ok()
1674 .and_then(|n| n.checked_mul(32))
1675 .and_then(|n| n.checked_add(256))
1676 .ok_or_else(|| {
1677 Error::resource(
1678 structured_asn1::memory::MemoryError::WorkExceeded,
1679 field,
1680 element.span().start,
1681 )
1682 })?;
1683 parent.charge(work).field(field)?;
1684 if !is_cps_uri(text) {
1685 return Ok(false);
1686 }
1687 if text
1688 .split_once(':')
1689 .is_some_and(|(scheme, _)| scheme.eq_ignore_ascii_case("ldap"))
1690 {
1691 return ldap::valid(parent, element, text, field);
1692 }
1693 Ok(known_location_authority_fits(text))
1694}
1695
1696fn known_location_authority_fits(text: &str) -> bool {
1697 let (scheme, rest) = text.split_once(':').expect("URI syntax checked");
1698 let ftp = scheme.eq_ignore_ascii_case("ftp");
1699 if !ftp && !scheme.eq_ignore_ascii_case("http") && !scheme.eq_ignore_ascii_case("https") {
1700 return true;
1706 }
1707 let Some(after) = rest.strip_prefix("//") else {
1713 return false;
1714 };
1715 let end = after.find(['/', '?', '#']).unwrap_or(after.len());
1716 let authority = &after[..end];
1717 let host_port = authority
1718 .rsplit_once('@')
1719 .map_or(authority, |(_, host)| host);
1720 if host_port.starts_with('[') {
1721 return true;
1723 }
1724 let host = host_port
1725 .split_once(':')
1726 .map_or(host_port, |(host, _)| host);
1727 if host.is_empty() {
1728 return false;
1729 }
1730 !ftp || is_domain(host.strip_suffix('.').unwrap_or(host)) || host.parse::<Ipv4Addr>().is_ok()
1731}
1732
1733fn uri<const CERTIFICATE_NAME: bool>(text: &str) -> bool {
1734 match text.split_once('#') {
1735 Some((rest, fragment)) => absolute_uri::<CERTIFICATE_NAME>(rest) && uri_alphabet(fragment),
1738 None => absolute_uri::<CERTIFICATE_NAME>(text),
1739 }
1740}
1741
1742fn is_ip_literal(text: &str) -> bool {
1747 if let Some(rest) = text.strip_prefix(['v', 'V']) {
1748 let Some((version, suffix)) = rest.split_once('.') else {
1750 return false;
1751 };
1752 return !version.is_empty()
1753 && version.bytes().all(|byte| byte.is_ascii_hexdigit())
1754 && !suffix.is_empty()
1755 && suffix.bytes().all(|byte| {
1756 byte.is_ascii_alphanumeric()
1757 || matches!(
1758 byte,
1759 b'-' | b'.'
1760 | b'_'
1761 | b'~'
1762 | b':'
1763 | b'!'
1764 | b'$'
1765 | b'&'
1766 | b'\''
1767 | b'('
1768 | b')'
1769 | b'*'
1770 | b'+'
1771 | b','
1772 | b';'
1773 | b'='
1774 )
1775 });
1776 }
1777 text.parse::<Ipv6Addr>().is_ok()
1778}
1779
1780fn is_contiguous_mask(mask: &[u8]) -> bool {
1781 let mut still_ones = true;
1782 for &byte in mask {
1783 if still_ones {
1784 if byte == 0xff {
1785 continue;
1786 }
1787 let ones = byte.leading_ones();
1789 let expected = if ones == 0 { 0 } else { 0xffu8 << (8 - ones) };
1790 if byte != expected {
1791 return false;
1792 }
1793 still_ones = false;
1794 } else if byte != 0 {
1795 return false;
1796 }
1797 }
1798 true
1799}
1800
1801fn text<'a>(
1802 parent: &Reader<'a, '_>,
1803 contents: &'a [u8],
1804 field: &'static str,
1805 element: &Element<'a>,
1806) -> Result<&'a str> {
1807 parent.charge(contents.len() as u64).field(field)?;
1811 if contents.is_empty() {
1815 return Err(Error::new(
1816 ErrorCode::MalformedValue,
1817 field,
1818 element.span().start,
1819 ));
1820 }
1821 if !contents.is_ascii() {
1822 return Err(Error::new(
1827 ErrorCode::MalformedValue,
1828 field,
1829 element.span().start,
1830 ));
1831 }
1832 core::str::from_utf8(contents)
1833 .map_err(|_| Error::new(ErrorCode::MalformedValue, field, element.span().start))
1834}
1835
1836#[cfg(test)]
1837mod tests;