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, 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: &Memory,
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>(
198 extension: &Extension<'a>,
199 execution: &Memory,
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>(parent: &Reader<'a>, element: &Element<'a>, field: &'static str) -> Result<()> {
441 let fail = |code| Error::new(code, field, element.span().start);
442
443 let mut inside = parent.enter(element).field(field)?;
444 let standard = inside
445 .next_element()
446 .field(field)?
447 .ok_or_else(|| fail(ErrorCode::MissingField))?;
448 if standard.tag() != Tag::constructed(universal::SEQUENCE) {
449 return Err(fail(ErrorCode::Encoding(
450 structured_asn1::ErrorCode::UnexpectedTag,
451 )));
452 }
453 read_standard_attributes(&inside, &standard, field)?;
454
455 let mut next = inside.next_element().field(field)?;
457 if let Some(domain_defined) = next
458 && domain_defined.tag() == Tag::constructed(universal::SEQUENCE)
459 {
460 read_domain_defined(&inside, &domain_defined, field)?;
461 next = inside.next_element().field(field)?;
462 }
463 if let Some(extensions) = next {
464 if extensions.tag() != Tag::constructed(universal::SET) {
465 return Err(fail(ErrorCode::Encoding(
466 structured_asn1::ErrorCode::UnexpectedTag,
467 )));
468 }
469 read_extension_attributes(&inside, &extensions, field)?;
470 if !inside.is_empty() {
471 return Err(fail(ErrorCode::TrailingData));
472 }
473 }
474 Ok(())
475}
476
477const X400_NUMERIC_STRING: u32 = 18;
480
481fn x400_string(element: &Element<'_>, field: &'static str, size: (usize, usize)) -> Result<()> {
485 let fail = |code| Error::new(code, field, element.span().start);
486 let contents = element.contents();
487 let fits = match (
490 element.tag().class(),
491 element.tag().number(),
492 element.tag().is_constructed(),
493 ) {
494 (Class::Universal, Some(X400_NUMERIC_STRING), false) => crate::name::is_numeric(contents),
495 (Class::Universal, Some(universal::PRINTABLE_STRING), false) => {
496 crate::name::is_printable(contents)
497 }
498 _ => {
499 return Err(fail(ErrorCode::Encoding(
500 structured_asn1::ErrorCode::UnexpectedTag,
501 )));
502 }
503 };
504 if !fits || contents.len() < size.0 || contents.len() > size.1 {
505 return Err(fail(ErrorCode::MalformedValue));
506 }
507 Ok(())
508}
509
510fn x400_printable(element: &Element<'_>, field: &'static str, size: (usize, usize)) -> Result<()> {
513 let fail = |code| Error::new(code, field, element.span().start);
514 let tag = element.tag();
515 if tag.class() != Class::Universal
516 || tag.number() != Some(universal::PRINTABLE_STRING)
517 || tag.is_constructed()
518 {
519 return Err(fail(ErrorCode::Encoding(
520 structured_asn1::ErrorCode::UnexpectedTag,
521 )));
522 }
523 let contents = element.contents();
524 if !crate::name::is_printable(contents) || contents.len() < size.0 || contents.len() > size.1 {
525 return Err(fail(ErrorCode::MalformedValue));
526 }
527 Ok(())
528}
529
530#[derive(Clone, Copy)]
534enum X400Repertoire {
535 Numeric,
536 Printable,
537 Teletex,
538}
539
540fn x400_implicit(
543 element: &Element<'_>,
544 field: &'static str,
545 repertoire: X400Repertoire,
546 most: usize,
547) -> Result<()> {
548 let fail = |code| Error::new(code, field, element.span().start);
549 let contents = element.contents();
550 if contents.is_empty() || contents.len() > most {
557 return Err(fail(ErrorCode::MalformedValue));
558 }
559 let fits = match repertoire {
560 X400Repertoire::Numeric => crate::name::is_numeric(contents),
561 X400Repertoire::Printable => crate::name::is_printable(contents),
562 X400Repertoire::Teletex => true,
563 };
564 if !fits {
565 return Err(fail(ErrorCode::MalformedValue));
566 }
567 Ok(())
568}
569
570fn x400_teletex(element: &Element<'_>, field: &'static str, size: (usize, usize)) -> Result<()> {
572 let fail = |code| Error::new(code, field, element.span().start);
573 if element.tag() != Tag::primitive(20) {
576 return Err(fail(ErrorCode::Encoding(
577 structured_asn1::ErrorCode::UnexpectedTag,
578 )));
579 }
580 let length = element.contents().len();
581 if length < size.0 || length > size.1 {
582 return Err(fail(ErrorCode::MalformedValue));
583 }
584 Ok(())
585}
586
587fn x400_bare_country(value: &Element<'_>, field: &'static str) -> Result<()> {
591 let fail = |code| Error::new(code, field, value.span().start);
592 let contents = value.contents();
593 let fits = match (
594 value.tag().class(),
595 value.tag().number(),
596 value.tag().is_constructed(),
597 ) {
598 (Class::Universal, Some(X400_NUMERIC_STRING), false) => {
599 contents.len() == 3 && contents.iter().all(u8::is_ascii_digit)
600 }
601 (Class::Universal, Some(universal::PRINTABLE_STRING), false) => {
602 contents.len() == 2 && contents.iter().all(u8::is_ascii_uppercase)
603 }
604 _ => {
605 return Err(fail(ErrorCode::Encoding(
606 structured_asn1::ErrorCode::UnexpectedTag,
607 )));
608 }
609 };
610 if !fits {
611 return Err(fail(ErrorCode::MalformedValue));
612 }
613 Ok(())
614}
615
616fn x400_country<'a>(parent: &Reader<'a>, wrapper: &Element<'a>, field: &'static str) -> Result<()> {
618 let fail = |code| Error::new(code, field, wrapper.span().start);
619 let mut inside = parent.enter(wrapper).field(field)?;
620 let value = inside
621 .next_element()
622 .field(field)?
623 .ok_or_else(|| fail(ErrorCode::MissingField))?;
624 if !inside.is_empty() {
625 return Err(fail(ErrorCode::TrailingData));
626 }
627 x400_bare_country(&value, field)
628}
629
630fn x400_choice<'a>(
633 parent: &Reader<'a>,
634 wrapper: &Element<'a>,
635 field: &'static str,
636 numeric: (usize, usize),
637 printable: (usize, usize),
638) -> Result<()> {
639 let fail = |code| Error::new(code, field, wrapper.span().start);
640 let mut inside = parent.enter(wrapper).field(field)?;
641 let value = inside
642 .next_element()
643 .field(field)?
644 .ok_or_else(|| fail(ErrorCode::MissingField))?;
645 if !inside.is_empty() {
646 return Err(fail(ErrorCode::TrailingData));
647 }
648 let size = match (value.tag().class(), value.tag().number()) {
649 (Class::Universal, Some(X400_NUMERIC_STRING)) => numeric,
650 (Class::Universal, Some(universal::PRINTABLE_STRING)) => printable,
651 _ => {
652 return Err(fail(ErrorCode::Encoding(
653 structured_asn1::ErrorCode::UnexpectedTag,
654 )));
655 }
656 };
657 x400_string(&value, field, size)
658}
659
660fn read_standard_attributes<'a>(
664 parent: &Reader<'a>,
665 element: &Element<'a>,
666 field: &'static str,
667) -> Result<()> {
668 let mut inside = parent.enter(element).field(field)?;
669 let mut last_rank = -1i8;
670 while let Some(member) = inside.next_element().field(field)? {
671 let bad = |code| Error::new(code, field, member.span().start);
672 let tag = member.tag();
673 let Some(number) = tag.number() else {
676 return Err(bad(ErrorCode::Encoding(
677 structured_asn1::ErrorCode::UnexpectedTag,
678 )));
679 };
680 let rank: i8 = match (tag.class(), number, tag.is_constructed()) {
681 (Class::Application, 1, true) => {
684 x400_country(&inside, &member, field)?;
685 0
686 }
687 (Class::Application, 2, true) => {
690 x400_choice(&inside, &member, field, (0, 16), (0, 16))?;
691 1
692 }
693 (Class::ContextSpecific, 0, false) => {
695 x400_implicit(&member, field, X400Repertoire::Numeric, 16)?;
696 2
697 }
698 (Class::ContextSpecific, 1, false) => {
700 x400_implicit(&member, field, X400Repertoire::Printable, 24)?;
701 3
702 }
703 (Class::ContextSpecific, 2, true) => {
705 x400_choice(&inside, &member, field, (1, 16), (1, 16))?;
706 4
707 }
708 (Class::ContextSpecific, 3, false) => {
710 x400_implicit(&member, field, X400Repertoire::Printable, 64)?;
711 5
712 }
713 (Class::ContextSpecific, 4, false) => {
715 x400_implicit(&member, field, X400Repertoire::Numeric, 32)?;
716 6
717 }
718 (Class::ContextSpecific, 5, true) => {
720 read_personal_name(&inside, &member, field, X400Repertoire::Printable)?;
721 7
722 }
723 (Class::ContextSpecific, 6, true) => {
727 let mut units = inside.enter(&member).field(field)?;
728 let mut count = 0usize;
729 while let Some(unit) = units.next_element().field(field)? {
730 x400_printable(&unit, field, (1, 32))?;
731 count += 1;
732 }
733 if !(1..=4).contains(&count) {
734 return Err(bad(ErrorCode::MalformedValue));
735 }
736 8
737 }
738 _ => {
739 return Err(bad(ErrorCode::Encoding(
740 structured_asn1::ErrorCode::UnexpectedTag,
741 )));
742 }
743 };
744 if rank <= last_rank {
748 return Err(bad(ErrorCode::UnexpectedField));
749 }
750 last_rank = rank;
751 }
752 Ok(())
753}
754
755fn read_personal_name<'a>(
759 parent: &Reader<'a>,
760 element: &Element<'a>,
761 field: &'static str,
762 repertoire: X400Repertoire,
763) -> Result<()> {
764 let fail = |code| Error::new(code, field, element.span().start);
765 let mut inside = parent.enter(element).field(field)?;
766 let mut seen = [false; 4];
767 let mut last: Option<usize> = None;
768 while let Some(part) = inside.next_element().field(field)? {
769 let bad = |code| Error::new(code, field, part.span().start);
770 let (number, most) = match (
771 part.tag().class(),
772 part.tag().number(),
773 part.tag().is_constructed(),
774 ) {
775 (Class::ContextSpecific, Some(0), false) => (0usize, 40),
776 (Class::ContextSpecific, Some(1), false) => (1, 16),
777 (Class::ContextSpecific, Some(2), false) => (2, 5),
778 (Class::ContextSpecific, Some(3), false) => (3, 3),
779 _ => {
780 return Err(bad(ErrorCode::Encoding(
781 structured_asn1::ErrorCode::UnexpectedTag,
782 )));
783 }
784 };
785 if seen[number] {
786 return Err(bad(ErrorCode::UnexpectedField));
787 }
788 if inside.encoding().is_der() && last.is_some_and(|last| number < last) {
792 return Err(bad(ErrorCode::UnexpectedField));
793 }
794 seen[number] = true;
795 last = Some(number);
796 x400_implicit(&part, field, repertoire, most)?;
797 }
798 if !seen[0] {
799 return Err(fail(ErrorCode::MissingField));
800 }
801 Ok(())
802}
803
804fn read_domain_defined<'a>(
807 parent: &Reader<'a>,
808 element: &Element<'a>,
809 field: &'static str,
810) -> Result<()> {
811 read_defined_pairs(parent, element, field, false)
812}
813
814fn read_defined_pairs<'a>(
817 parent: &Reader<'a>,
818 element: &Element<'a>,
819 field: &'static str,
820 teletex: bool,
821) -> Result<()> {
822 let fail = |code| Error::new(code, field, element.span().start);
823 if element.tag() != Tag::constructed(universal::SEQUENCE) {
824 return Err(fail(ErrorCode::Encoding(
825 structured_asn1::ErrorCode::UnexpectedTag,
826 )));
827 }
828 let held_string = |element: &Element<'_>, size: (usize, usize)| {
829 if teletex {
830 x400_teletex(element, field, size)
831 } else {
832 x400_printable(element, field, size)
835 }
836 };
837 let mut inside = parent.enter(element).field(field)?;
838 let mut count = 0usize;
839 while let Some(pair) = inside.next_element().field(field)? {
840 let bad = |code| Error::new(code, field, pair.span().start);
841 if pair.tag() != Tag::constructed(universal::SEQUENCE) {
842 return Err(bad(ErrorCode::Encoding(
843 structured_asn1::ErrorCode::UnexpectedTag,
844 )));
845 }
846 let mut two = inside.enter(&pair).field(field)?;
847 let kind = two
848 .next_element()
849 .field(field)?
850 .ok_or_else(|| bad(ErrorCode::MissingField))?;
851 held_string(&kind, (1, 8))?;
852 let value = two
853 .next_element()
854 .field(field)?
855 .ok_or_else(|| bad(ErrorCode::MissingField))?;
856 held_string(&value, (1, 128))?;
857 if !two.is_empty() {
858 return Err(bad(ErrorCode::TrailingData));
859 }
860 count += 1;
861 }
862 if !(1..=4).contains(&count) {
863 return Err(fail(ErrorCode::MalformedValue));
864 }
865 Ok(())
866}
867
868fn read_extension_attributes<'a>(
872 parent: &Reader<'a>,
873 element: &Element<'a>,
874 field: &'static str,
875) -> Result<()> {
876 let fail = |code| Error::new(code, field, element.span().start);
877 let mut inside = parent.enter(element).field(field)?;
878 let mut count = 0usize;
879 let mut previous: Option<&[u8]> = None;
880 while let Some(entry) = inside.next_element().field(field)? {
881 let bad = |code| Error::new(code, field, entry.span().start);
882 if entry.tag() != Tag::constructed(universal::SEQUENCE) {
883 return Err(bad(ErrorCode::Encoding(
884 structured_asn1::ErrorCode::UnexpectedTag,
885 )));
886 }
887 if inside.encoding().is_der()
893 && let Some(previous) = previous
894 {
895 inside
896 .charge(previous.len().max(entry.as_bytes().len()) as u64)
897 .field(field)?;
898 if entry.as_bytes() < previous {
899 return Err(bad(ErrorCode::UnexpectedField));
900 }
901 }
902 previous = Some(entry.as_bytes());
903 let mut two = inside.enter(&entry).field(field)?;
904 let kind = two
905 .next_element()
906 .field(field)?
907 .ok_or_else(|| bad(ErrorCode::MissingField))?;
908 if extension::context_of(kind.tag()) != Some((0, false)) {
912 return Err(bad(ErrorCode::Encoding(
913 structured_asn1::ErrorCode::UnexpectedTag,
914 )));
915 }
916 let number = two.integer(&kind).field(field)?;
917 if number.as_u32().is_none_or(|number| number > 256) {
918 return Err(bad(ErrorCode::MalformedValue));
919 }
920 let value = two
921 .next_element()
922 .field(field)?
923 .ok_or_else(|| bad(ErrorCode::MissingField))?;
924 if extension::context_of(value.tag()) != Some((1, true)) {
927 return Err(bad(ErrorCode::Encoding(
928 structured_asn1::ErrorCode::UnexpectedTag,
929 )));
930 }
931 let mut held = two.enter(&value).field(field)?;
932 let Some(declared) = held.next_element().field(field)? else {
933 return Err(bad(ErrorCode::MissingField));
934 };
935 let number = number
940 .as_u32()
941 .expect("bounded to 0..=256 above, which fits");
942 read_extension_value(&held, &declared, number, field)?;
943 if !held.is_empty() || !two.is_empty() {
944 return Err(bad(ErrorCode::TrailingData));
945 }
946 count += 1;
947 if count > 256 {
950 return Err(bad(ErrorCode::MalformedValue));
951 }
952 }
953 if count == 0 {
954 return Err(fail(ErrorCode::EmptySequence));
955 }
956 Ok(())
957}
958
959fn read_extension_value<'a>(
965 parent: &Reader<'a>,
966 value: &Element<'a>,
967 number: u32,
968 field: &'static str,
969) -> Result<()> {
970 let fail = |code| Error::new(code, field, value.span().start);
971 match number {
972 1 => x400_printable(value, field, (1, 64)),
975 2 | 3 => x400_teletex(value, field, (1, 64)),
977 4 => {
979 if value.tag() != Tag::constructed(universal::SET) {
980 return Err(fail(ErrorCode::Encoding(
981 structured_asn1::ErrorCode::UnexpectedTag,
982 )));
983 }
984 read_personal_name(parent, value, field, X400Repertoire::Teletex)
985 }
986 5 => {
988 if value.tag() != Tag::constructed(universal::SEQUENCE) {
989 return Err(fail(ErrorCode::Encoding(
990 structured_asn1::ErrorCode::UnexpectedTag,
991 )));
992 }
993 let mut units = parent.enter(value).field(field)?;
994 let mut count = 0usize;
995 while let Some(unit) = units.next_element().field(field)? {
996 x400_teletex(&unit, field, (1, 32))?;
997 count += 1;
998 }
999 if !(1..=4).contains(&count) {
1000 return Err(fail(ErrorCode::MalformedValue));
1001 }
1002 Ok(())
1003 }
1004 6 => read_defined_pairs(parent, value, field, true),
1006 7 => x400_printable(value, field, (1, 16)),
1008 8 => x400_bare_country(value, field),
1011 9 => x400_bare_choice(value, field, (1, 16), (1, 16)),
1013 10..=15 | 17..=21 => read_pds_parameter(parent, value, field, 30),
1016 16 => read_unformatted_address(parent, value, field),
1018 22 => read_extended_network_address(parent, value, field),
1020 23 => {
1022 if value.tag() != Tag::primitive(universal::INTEGER) {
1023 return Err(fail(ErrorCode::Encoding(
1024 structured_asn1::ErrorCode::UnexpectedTag,
1025 )));
1026 }
1027 let option = parent.integer(value).field(field)?;
1028 if option.as_u32().is_none_or(|option| option > 256) {
1029 return Err(fail(ErrorCode::MalformedValue));
1030 }
1031 Ok(())
1032 }
1033 _ => Err(fail(ErrorCode::MalformedValue)),
1034 }
1035}
1036
1037fn x400_bare_choice(
1040 value: &Element<'_>,
1041 field: &'static str,
1042 numeric: (usize, usize),
1043 printable: (usize, usize),
1044) -> Result<()> {
1045 let fail = |code| Error::new(code, field, value.span().start);
1046 let size = match (
1047 value.tag().class(),
1048 value.tag().number(),
1049 value.tag().is_constructed(),
1050 ) {
1051 (Class::Universal, Some(X400_NUMERIC_STRING), false) => numeric,
1052 (Class::Universal, Some(universal::PRINTABLE_STRING), false) => printable,
1053 _ => {
1054 return Err(fail(ErrorCode::Encoding(
1055 structured_asn1::ErrorCode::UnexpectedTag,
1056 )));
1057 }
1058 };
1059 x400_string(value, field, size)
1060}
1061
1062fn read_pds_parameter<'a>(
1065 parent: &Reader<'a>,
1066 value: &Element<'a>,
1067 field: &'static str,
1068 most: usize,
1069) -> Result<()> {
1070 let fail = |code| Error::new(code, field, value.span().start);
1071 if value.tag() != Tag::constructed(universal::SET) {
1072 return Err(fail(ErrorCode::Encoding(
1073 structured_asn1::ErrorCode::UnexpectedTag,
1074 )));
1075 }
1076 let mut inside = parent.enter(value).field(field)?;
1077 let mut seen_printable = false;
1078 let mut seen_teletex = false;
1079 while let Some(member) = inside.next_element().field(field)? {
1080 let bad = |code| Error::new(code, field, member.span().start);
1081 if member.tag() == Tag::primitive(universal::PRINTABLE_STRING) {
1082 if seen_printable || (seen_teletex && inside.encoding().is_der()) {
1087 return Err(bad(ErrorCode::UnexpectedField));
1088 }
1089 seen_printable = true;
1090 x400_string(&member, field, (1, most))?;
1091 } else if member.tag() == Tag::primitive(20) {
1092 if seen_teletex {
1093 return Err(bad(ErrorCode::UnexpectedField));
1094 }
1095 seen_teletex = true;
1096 x400_teletex(&member, field, (1, most))?;
1097 } else {
1098 return Err(bad(ErrorCode::Encoding(
1099 structured_asn1::ErrorCode::UnexpectedTag,
1100 )));
1101 }
1102 }
1103 Ok(())
1104}
1105
1106fn read_unformatted_address<'a>(
1109 parent: &Reader<'a>,
1110 value: &Element<'a>,
1111 field: &'static str,
1112) -> Result<()> {
1113 let fail = |code| Error::new(code, field, value.span().start);
1114 if value.tag() != Tag::constructed(universal::SET) {
1115 return Err(fail(ErrorCode::Encoding(
1116 structured_asn1::ErrorCode::UnexpectedTag,
1117 )));
1118 }
1119 let mut inside = parent.enter(value).field(field)?;
1120 let mut seen_lines = false;
1121 let mut seen_teletex = false;
1122 while let Some(member) = inside.next_element().field(field)? {
1123 let bad = |code| Error::new(code, field, member.span().start);
1124 if member.tag() == Tag::constructed(universal::SEQUENCE) {
1125 if seen_lines || (seen_teletex && inside.encoding().is_der()) {
1130 return Err(bad(ErrorCode::UnexpectedField));
1131 }
1132 seen_lines = true;
1133 let mut lines = inside.enter(&member).field(field)?;
1134 let mut count = 0usize;
1135 while let Some(line) = lines.next_element().field(field)? {
1136 x400_printable(&line, field, (1, 30))?;
1139 count += 1;
1140 }
1141 if !(1..=6).contains(&count) {
1142 return Err(bad(ErrorCode::MalformedValue));
1143 }
1144 } else if member.tag() == Tag::primitive(20) {
1145 if seen_teletex {
1146 return Err(bad(ErrorCode::UnexpectedField));
1147 }
1148 seen_teletex = true;
1149 x400_teletex(&member, field, (1, 180))?;
1150 } else {
1151 return Err(bad(ErrorCode::Encoding(
1152 structured_asn1::ErrorCode::UnexpectedTag,
1153 )));
1154 }
1155 }
1156 Ok(())
1157}
1158
1159fn read_e163_address<'a>(
1161 parent: &Reader<'a>,
1162 value: &Element<'a>,
1163 field: &'static str,
1164) -> Result<()> {
1165 let fail = |code| Error::new(code, field, value.span().start);
1166 let mut inside = parent.enter(value).field(field)?;
1167 let number = inside
1168 .next_element()
1169 .field(field)?
1170 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1171 if extension::context_of(number.tag()) != Some((0, false)) {
1172 return Err(fail(ErrorCode::Encoding(
1173 structured_asn1::ErrorCode::UnexpectedTag,
1174 )));
1175 }
1176 x400_implicit(&number, field, X400Repertoire::Numeric, 15)?;
1177 if let Some(sub) = inside.next_element().field(field)? {
1178 if extension::context_of(sub.tag()) != Some((1, false)) {
1179 return Err(fail(ErrorCode::Encoding(
1180 structured_asn1::ErrorCode::UnexpectedTag,
1181 )));
1182 }
1183 x400_implicit(&sub, field, X400Repertoire::Numeric, 40)?;
1184 }
1185 if !inside.is_empty() {
1186 return Err(fail(ErrorCode::TrailingData));
1187 }
1188 Ok(())
1189}
1190
1191fn read_extended_network_address<'a>(
1195 parent: &Reader<'a>,
1196 value: &Element<'a>,
1197 field: &'static str,
1198) -> Result<()> {
1199 let fail = |code| Error::new(code, field, value.span().start);
1200 if value.tag() == Tag::constructed(universal::SEQUENCE) {
1201 read_e163_address(parent, value, field)
1202 } else if extension::context_of(value.tag()) == Some((0, true)) {
1203 let mut inside = parent.enter(value).field(field)?;
1206 let mut last: i8 = -1;
1207 let mut saw_network = false;
1208 while let Some(member) = inside.next_element().field(field)? {
1209 let bad = |code| Error::new(code, field, member.span().start);
1210 let Some((number, true)) = extension::context_of(member.tag()) else {
1211 return Err(bad(ErrorCode::Encoding(
1212 structured_asn1::ErrorCode::UnexpectedTag,
1213 )));
1214 };
1215 let rank = i8::try_from(number).map_err(|_| {
1216 bad(ErrorCode::Encoding(
1217 structured_asn1::ErrorCode::UnexpectedTag,
1218 ))
1219 })?;
1220 if rank > 3 {
1221 return Err(bad(ErrorCode::Encoding(
1222 structured_asn1::ErrorCode::UnexpectedTag,
1223 )));
1224 }
1225 if rank <= last {
1226 return Err(bad(ErrorCode::UnexpectedField));
1227 }
1228 last = rank;
1229 let mut held = inside.enter(&member).field(field)?;
1230 if rank == 3 {
1231 let addresses = held
1233 .next_element()
1234 .field(field)?
1235 .ok_or_else(|| bad(ErrorCode::MissingField))?;
1236 if addresses.tag() != Tag::constructed(universal::SET) {
1237 return Err(bad(ErrorCode::Encoding(
1238 structured_asn1::ErrorCode::UnexpectedTag,
1239 )));
1240 }
1241 let mut each = held.enter(&addresses).field(field)?;
1242 let mut count = 0usize;
1243 let mut previous: Option<&[u8]> = None;
1244 while let Some(address) = each.next_element().field(field)? {
1245 if address.tag() != Tag::primitive(universal::OCTET_STRING) {
1246 return Err(bad(ErrorCode::Encoding(
1247 structured_asn1::ErrorCode::UnexpectedTag,
1248 )));
1249 }
1250 if each.encoding().is_der()
1256 && let Some(previous) = previous
1257 {
1258 each.charge(previous.len().max(address.as_bytes().len()) as u64)
1259 .field(field)?;
1260 if address.as_bytes() < previous {
1261 return Err(bad(ErrorCode::UnexpectedField));
1262 }
1263 }
1264 previous = Some(address.as_bytes());
1265 count += 1;
1266 }
1267 if count == 0 {
1268 return Err(bad(ErrorCode::EmptySequence));
1269 }
1270 saw_network = true;
1271 } else {
1272 let selector = held
1274 .next_element()
1275 .field(field)?
1276 .ok_or_else(|| bad(ErrorCode::MissingField))?;
1277 if selector.tag() != Tag::primitive(universal::OCTET_STRING) {
1278 return Err(bad(ErrorCode::Encoding(
1279 structured_asn1::ErrorCode::UnexpectedTag,
1280 )));
1281 }
1282 }
1283 if !held.is_empty() {
1284 return Err(bad(ErrorCode::TrailingData));
1285 }
1286 }
1287 if !saw_network {
1288 return Err(fail(ErrorCode::MissingField));
1289 }
1290 Ok(())
1291 } else {
1292 Err(fail(ErrorCode::Encoding(
1293 structured_asn1::ErrorCode::UnexpectedTag,
1294 )))
1295 }
1296}
1297
1298fn read_edi_party<'a>(
1303 parent: &Reader<'a>,
1304 element: &Element<'a>,
1305 field: &'static str,
1306) -> Result<()> {
1307 let fail = |code| Error::new(code, field, element.span().start);
1308
1309 let mut inside = parent.enter(element).field(field)?;
1310 let mut next = inside.next_element().field(field)?;
1311
1312 if let Some(assigner) = next
1313 && extension::context_of(assigner.tag()) == Some((0, true))
1314 {
1315 require_directory_string(&inside, &assigner, field)?;
1316 next = inside.next_element().field(field)?;
1317 }
1318
1319 let party = next.ok_or_else(|| fail(ErrorCode::MissingField))?;
1320 if extension::context_of(party.tag()) != Some((1, true)) {
1321 return Err(Error::new(
1322 ErrorCode::UnexpectedField,
1323 field,
1324 party.span().start,
1325 ));
1326 }
1327 require_directory_string(&inside, &party, field)?;
1328
1329 if !inside.is_empty() {
1330 return Err(fail(ErrorCode::TrailingData));
1331 }
1332 Ok(())
1333}
1334
1335fn require_directory_string<'a>(
1337 parent: &Reader<'a>,
1338 wrapper: &Element<'a>,
1339 field: &'static str,
1340) -> Result<()> {
1341 const MOST: usize = 32768;
1343 let fail = |code| Error::new(code, field, wrapper.span().start);
1344
1345 let mut inside = parent.enter(wrapper).field(field)?;
1346 let value = inside
1347 .next_element()
1348 .field(field)?
1349 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1350 if !inside.is_empty() {
1351 return Err(fail(ErrorCode::TrailingData));
1352 }
1353
1354 let tag = value.tag();
1359 let is_directory_string = tag.class() == Class::Universal
1360 && !tag.is_constructed()
1361 && matches!(tag.number(), Some(12 | 19 | 20 | 28 | 30));
1362 let ceiling = match tag.number() {
1367 Some(12 | 28) => MOST.saturating_mul(4),
1368 Some(30) => MOST.saturating_mul(2),
1369 _ => MOST,
1370 };
1371 if value.contents().len() > ceiling {
1372 return Err(fail(ErrorCode::MalformedValue));
1373 }
1374 parent.charge(value.contents().len() as u64).field(field)?;
1378 let decodes = match tag.number() {
1379 Some(12) => {
1380 core::str::from_utf8(value.contents()).is_ok_and(|text| text.chars().count() <= MOST)
1381 }
1382 Some(19) => crate::name::is_printable(value.contents()) && value.contents().len() <= MOST,
1383 Some(28) => {
1384 crate::name::wide_char_count(value.contents(), 4).is_some_and(|count| count <= MOST)
1385 }
1386 Some(30) => {
1387 crate::name::wide_char_count(value.contents(), 2).is_some_and(|count| count <= MOST)
1388 }
1389 _ => value.contents().len() <= MOST,
1393 };
1394 if !is_directory_string || value.contents().is_empty() || !decodes {
1395 return Err(fail(ErrorCode::MalformedValue));
1396 }
1397 Ok(())
1398}
1399
1400fn read_other<'a>(
1401 parent: &Reader<'a>,
1402 element: &Element<'a>,
1403 field: &'static str,
1404) -> Result<GeneralName<'a>> {
1405 let fail = |code| Error::new(code, field, element.span().start);
1406
1407 let mut inside = parent.enter(element).field(field)?;
1408 let type_id = inside.read_oid().field(field)?;
1409 let wrapper = inside
1410 .next_element()
1411 .field(field)?
1412 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1413
1414 if wrapper.tag() != Tag::context(true, 0) {
1417 return Err(fail(ErrorCode::Encoding(
1418 structured_asn1::ErrorCode::UnexpectedTag,
1419 )));
1420 }
1421 if !inside.is_empty() {
1422 return Err(fail(ErrorCode::TrailingData));
1423 }
1424
1425 let mut held = inside.enter(&wrapper).field(field)?;
1429 let value = held
1430 .next_element()
1431 .field(field)?
1432 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1433 if !held.is_empty() {
1434 return Err(fail(ErrorCode::TrailingData));
1435 }
1436
1437 crate::name::walk_der(&held, &value, field, crate::name::Strings::Checked)?;
1444
1445 Ok(GeneralName::Other {
1446 type_id,
1447 value: value.as_bytes(),
1448 })
1449}
1450
1451pub(crate) fn is_domain(text: &str) -> bool {
1457 text.len() <= 253
1463 && text.split('.').all(|label| {
1464 (1..=63).contains(&label.len())
1465 && label
1466 .bytes()
1467 .all(|byte| byte.is_ascii_alphanumeric() || byte == b'-')
1468 && !label.starts_with('-')
1469 && !label.ends_with('-')
1470 })
1471 && text
1472 .rsplit('.')
1473 .next()
1474 .is_some_and(|top| top.bytes().any(|byte| byte.is_ascii_alphabetic()))
1475}
1476
1477pub(crate) fn is_mailbox(text: &str) -> bool {
1489 structured_email_address::is_smtp_mailbox(text)
1490}
1491
1492pub(crate) fn is_absolute_uri(text: &str) -> bool {
1500 absolute_uri::<true>(text)
1501}
1502
1503fn absolute_uri<const CERTIFICATE_NAME: bool>(text: &str) -> bool {
1504 let Some((scheme, rest)) = text.split_once(':') else {
1505 return false;
1506 };
1507 let mut bytes = scheme.bytes();
1508 if !(bytes.next().is_some_and(|byte| byte.is_ascii_alphabetic())
1509 && bytes.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'+' | b'-' | b'.')))
1510 {
1511 return false;
1512 }
1513 if CERTIFICATE_NAME && rest.is_empty() {
1521 return false;
1522 }
1523
1524 let mut userinfo = "";
1530 let mut bare_host = "";
1531 let mut tail = rest;
1532 if let Some(after) = rest.strip_prefix("//") {
1533 let end = after.find(['/', '?']).unwrap_or(after.len());
1534 let authority = &after[..end];
1535 tail = &after[end..];
1536 let (before, host_port) = match authority.split_once('@') {
1537 Some((before, host_port)) => (before, host_port),
1538 None => ("", authority),
1539 };
1540 if host_port.contains('@') {
1543 return false;
1544 }
1545 userinfo = before;
1546 let port = if let Some(inside) = host_port.strip_prefix('[') {
1547 let Some((literal, past)) = inside.split_once(']') else {
1548 return false;
1549 };
1550 if !is_ip_literal(literal) {
1551 return false;
1552 }
1553 if past.is_empty() {
1555 None
1556 } else {
1557 let Some(digits) = past.strip_prefix(':') else {
1558 return false;
1559 };
1560 Some(digits)
1561 }
1562 } else {
1563 let port = if let Some((host, port)) = host_port.split_once(':') {
1566 bare_host = host;
1567 Some(port)
1568 } else {
1569 bare_host = host_port;
1570 None
1571 };
1572 let named = bare_host.strip_suffix('.').unwrap_or(bare_host);
1584 if CERTIFICATE_NAME && !is_domain(named) && bare_host.parse::<Ipv4Addr>().is_err() {
1585 return false;
1586 }
1587 port
1588 };
1589 if port.is_some_and(|digits| !digits.bytes().all(|byte| byte.is_ascii_digit())) {
1591 return false;
1592 }
1593 }
1594
1595 uri_alphabet(userinfo) && uri_alphabet(bare_host) && uri_alphabet(tail)
1596}
1597
1598fn uri_alphabet(segment: &str) -> bool {
1603 let mut bytes = segment.bytes();
1604 while let Some(byte) = bytes.next() {
1605 let permitted = byte.is_ascii_alphanumeric()
1606 || matches!(
1607 byte,
1608 b'-' | b'.'
1609 | b'_'
1610 | b'~'
1611 | b':'
1612 | b'/'
1613 | b'?'
1614 | b'@'
1615 | b'!'
1616 | b'$'
1617 | b'&'
1618 | b'\''
1619 | b'('
1620 | b')'
1621 | b'*'
1622 | b'+'
1623 | b','
1624 | b';'
1625 | b'='
1626 );
1627 if byte == b'%' {
1628 let mut pair = [bytes.next(), bytes.next()].into_iter();
1629 if !pair.all(|digit| digit.is_some_and(|digit| digit.is_ascii_hexdigit())) {
1630 return false;
1631 }
1632 } else if !permitted {
1633 return false;
1634 }
1635 }
1636 true
1637}
1638
1639pub(crate) fn is_uri(text: &str) -> bool {
1646 uri::<true>(text)
1647}
1648
1649pub(crate) fn is_cps_uri(text: &str) -> bool {
1653 uri::<false>(text)
1654}
1655
1656fn location_uri(
1657 parent: &Reader<'_>,
1658 element: &Element<'_>,
1659 text: &str,
1660 field: &'static str,
1661) -> Result<bool> {
1662 let work = u64::try_from(text.len())
1665 .ok()
1666 .and_then(|n| n.checked_mul(32))
1667 .and_then(|n| n.checked_add(256))
1668 .ok_or_else(|| {
1669 Error::resource(
1670 structured_asn1::memory::MemoryError::WorkExceeded,
1671 field,
1672 element.span().start,
1673 )
1674 })?;
1675 parent.charge(work).field(field)?;
1676 if !is_cps_uri(text) {
1677 return Ok(false);
1678 }
1679 if text
1680 .split_once(':')
1681 .is_some_and(|(scheme, _)| scheme.eq_ignore_ascii_case("ldap"))
1682 {
1683 return ldap::valid(parent, element, text, field);
1684 }
1685 Ok(known_location_authority_fits(text))
1686}
1687
1688fn known_location_authority_fits(text: &str) -> bool {
1689 let (scheme, rest) = text.split_once(':').expect("URI syntax checked");
1690 let ftp = scheme.eq_ignore_ascii_case("ftp");
1691 if !ftp && !scheme.eq_ignore_ascii_case("http") && !scheme.eq_ignore_ascii_case("https") {
1692 return true;
1698 }
1699 let Some(after) = rest.strip_prefix("//") else {
1705 return false;
1706 };
1707 let end = after.find(['/', '?', '#']).unwrap_or(after.len());
1708 let authority = &after[..end];
1709 let host_port = authority
1710 .rsplit_once('@')
1711 .map_or(authority, |(_, host)| host);
1712 if host_port.starts_with('[') {
1713 return true;
1715 }
1716 let host = host_port
1717 .split_once(':')
1718 .map_or(host_port, |(host, _)| host);
1719 if host.is_empty() {
1720 return false;
1721 }
1722 !ftp || is_domain(host.strip_suffix('.').unwrap_or(host)) || host.parse::<Ipv4Addr>().is_ok()
1723}
1724
1725fn uri<const CERTIFICATE_NAME: bool>(text: &str) -> bool {
1726 match text.split_once('#') {
1727 Some((rest, fragment)) => absolute_uri::<CERTIFICATE_NAME>(rest) && uri_alphabet(fragment),
1730 None => absolute_uri::<CERTIFICATE_NAME>(text),
1731 }
1732}
1733
1734fn is_ip_literal(text: &str) -> bool {
1739 if let Some(rest) = text.strip_prefix(['v', 'V']) {
1740 let Some((version, suffix)) = rest.split_once('.') else {
1742 return false;
1743 };
1744 return !version.is_empty()
1745 && version.bytes().all(|byte| byte.is_ascii_hexdigit())
1746 && !suffix.is_empty()
1747 && suffix.bytes().all(|byte| {
1748 byte.is_ascii_alphanumeric()
1749 || matches!(
1750 byte,
1751 b'-' | b'.'
1752 | b'_'
1753 | b'~'
1754 | b':'
1755 | b'!'
1756 | b'$'
1757 | b'&'
1758 | b'\''
1759 | b'('
1760 | b')'
1761 | b'*'
1762 | b'+'
1763 | b','
1764 | b';'
1765 | b'='
1766 )
1767 });
1768 }
1769 text.parse::<Ipv6Addr>().is_ok()
1770}
1771
1772fn is_contiguous_mask(mask: &[u8]) -> bool {
1773 let mut still_ones = true;
1774 for &byte in mask {
1775 if still_ones {
1776 if byte == 0xff {
1777 continue;
1778 }
1779 let ones = byte.leading_ones();
1781 let expected = if ones == 0 { 0 } else { 0xffu8 << (8 - ones) };
1782 if byte != expected {
1783 return false;
1784 }
1785 still_ones = false;
1786 } else if byte != 0 {
1787 return false;
1788 }
1789 }
1790 true
1791}
1792
1793fn text<'a>(
1794 parent: &Reader<'a>,
1795 contents: &'a [u8],
1796 field: &'static str,
1797 element: &Element<'a>,
1798) -> Result<&'a str> {
1799 parent.charge(contents.len() as u64).field(field)?;
1803 if contents.is_empty() {
1807 return Err(Error::new(
1808 ErrorCode::MalformedValue,
1809 field,
1810 element.span().start,
1811 ));
1812 }
1813 if !contents.is_ascii() {
1814 return Err(Error::new(
1819 ErrorCode::MalformedValue,
1820 field,
1821 element.span().start,
1822 ));
1823 }
1824 core::str::from_utf8(contents)
1825 .map_err(|_| Error::new(ErrorCode::MalformedValue, field, element.span().start))
1826}
1827
1828#[cfg(test)]
1829mod tests;