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
16#[derive(Debug)]
18#[non_exhaustive]
19pub enum GeneralName<'a> {
20 Other {
22 type_id: Oid<'a>,
24 value: &'a [u8],
26 },
27 Email(&'a str),
29 Dns(&'a str),
31 X400(&'a [u8]),
33 Directory(Name<'a>),
35 EdiParty(&'a [u8]),
37 Uri(&'a str),
39 IpAddress(&'a [u8]),
42 RegisteredId(Oid<'a>),
44}
45
46pub(crate) fn read_all<'a>(
48 parent: &Reader<'a>,
49 element: &Element<'a>,
50 field: &'static str,
51) -> Result<OwnedVec<GeneralName<'a>>> {
52 let mut inside = parent.enter(element).field(field)?;
53 read_list(&mut inside, field, element.span().start)
54}
55
56pub(crate) fn read_list<'a>(
58 inside: &mut Reader<'a>,
59 field: &'static str,
60 offset: u64,
61) -> Result<OwnedVec<GeneralName<'a>>> {
62 let mut names = inside.memory().vector();
63 while let Some(entry) = inside.next_element().field(field)? {
64 names
65 .try_push(read(inside, &entry, field)?)
66 .map_err(|reason| Error::resource(reason, field, entry.span().start))?;
67 }
68
69 if names.is_empty() {
72 return Err(Error::new(ErrorCode::EmptySequence, field, offset));
73 }
74 Ok(names)
75}
76
77pub fn read_alternative<'a>(
80 extension: &Extension<'a>,
81 execution: &Memory,
82) -> Result<OwnedVec<GeneralName<'a>>> {
83 let field = if extension.kind() == crate::oid::ISSUER_ALT_NAME {
84 "extensions.issuerAltName"
85 } else {
86 "extensions.subjectAltName"
87 };
88
89 let mut inside = extension::sequence(extension, field, execution)?;
90 read_list(&mut inside, field, extension.span().start)
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100pub(crate) enum AddressForm {
101 Single,
103 WithMask,
106}
107
108impl AddressForm {
109 fn permits(self, length: usize) -> bool {
110 match self {
111 Self::Single => length == 4 || length == 16,
112 Self::WithMask => length == 8 || length == 32,
113 }
114 }
115}
116
117pub fn read<'a>(
128 parent: &Reader<'a>,
129 element: &Element<'a>,
130 field: &'static str,
131) -> Result<GeneralName<'a>> {
132 read_as(parent, element, field, AddressForm::Single)
133}
134
135fn mailbox_fits(text: &str, address_form: AddressForm) -> bool {
141 match address_form {
142 AddressForm::Single => is_mailbox(text),
143 AddressForm::WithMask => {
144 is_mailbox(text) || is_domain(text) || text.strip_prefix('.').is_some_and(is_domain)
145 }
146 }
147}
148
149fn domain_fits(text: &str, address_form: AddressForm) -> bool {
166 match address_form {
167 AddressForm::Single => is_domain(text),
168 AddressForm::WithMask => is_domain(text) || text.strip_prefix('.').is_some_and(is_domain),
169 }
170}
171
172pub(crate) fn read_as<'a>(
173 parent: &Reader<'a>,
174 element: &Element<'a>,
175 field: &'static str,
176 address_form: AddressForm,
177) -> Result<GeneralName<'a>> {
178 let fail = |code| Error::new(code, field, element.span().start);
179 let tag = element.tag();
180
181 if tag.class() != Class::ContextSpecific {
182 return Err(fail(ErrorCode::Encoding(
183 structured_asn1::ErrorCode::UnexpectedTag,
184 )));
185 }
186
187 let Some(number) = tag.number() else {
194 return Err(fail(ErrorCode::Encoding(
195 structured_asn1::ErrorCode::UnexpectedTag,
196 )));
197 };
198 match (number, tag.is_constructed()) {
199 (0, true) => read_other(parent, element, field),
200 (1, false) => {
201 let email = text(parent, element.contents(), field, element)?;
202 if !mailbox_fits(email, address_form) {
203 return Err(fail(ErrorCode::MalformedValue));
204 }
205 Ok(GeneralName::Email(email))
206 }
207 (2, false) => {
208 let domain = text(parent, element.contents(), field, element)?;
209 if !domain_fits(domain, address_form) {
210 return Err(fail(ErrorCode::MalformedValue));
211 }
212 Ok(GeneralName::Dns(domain))
213 }
214 (3, true) => {
215 read_x400(parent, element, field)?;
216 Ok(GeneralName::X400(element.contents()))
217 }
218 (4, true) => {
219 let mut inside = parent.enter(element).field(field)?;
222 let inner = inside
223 .next_element()
224 .field(field)?
225 .ok_or_else(|| fail(ErrorCode::MissingField))?;
226 let name = name::read(&inside, &inner, field)?;
227 if address_form == AddressForm::Single && name.is_empty() {
240 return Err(fail(ErrorCode::MalformedValue));
241 }
242 for attribute in name.attributes() {
243 if !name::well_formed_in(attribute, &inside, field)? {
244 return Err(fail(ErrorCode::MalformedValue));
245 }
246 }
247 if !inside.is_empty() {
248 return Err(fail(ErrorCode::TrailingData));
249 }
250 Ok(GeneralName::Directory(name))
251 }
252 (5, true) => {
253 read_edi_party(parent, element, field)?;
254 Ok(GeneralName::EdiParty(element.contents()))
255 }
256 (6, false) => {
257 let location = text(parent, element.contents(), field, element)?;
258 let fits = match address_form {
267 AddressForm::Single => {
268 parent.charge(location.len() as u64).field(field)?;
271 is_uri(location)
272 }
273 AddressForm::WithMask => {
274 is_domain(location) || location.strip_prefix('.').is_some_and(is_domain)
275 }
276 };
277 if !fits {
278 return Err(fail(ErrorCode::MalformedValue));
279 }
280 Ok(GeneralName::Uri(location))
281 }
282 (7, false) => {
283 let contents = element.contents();
284 if !address_form.permits(contents.len()) {
285 return Err(fail(ErrorCode::MalformedValue));
286 }
287 if address_form == AddressForm::WithMask
291 && !is_contiguous_mask(&contents[contents.len() / 2..])
292 {
293 return Err(fail(ErrorCode::MalformedValue));
294 }
295 Ok(GeneralName::IpAddress(contents))
296 }
297 (8, false) => parent
298 .oid(element)
299 .field(field)
300 .map(GeneralName::RegisteredId),
301 _ => Err(fail(ErrorCode::Encoding(
302 structured_asn1::ErrorCode::UnexpectedTag,
303 ))),
304 }
305}
306
307fn read_x400<'a>(parent: &Reader<'a>, element: &Element<'a>, field: &'static str) -> Result<()> {
315 let fail = |code| Error::new(code, field, element.span().start);
316
317 let mut inside = parent.enter(element).field(field)?;
318 let standard = inside
319 .next_element()
320 .field(field)?
321 .ok_or_else(|| fail(ErrorCode::MissingField))?;
322 if standard.tag() != Tag::constructed(universal::SEQUENCE) {
323 return Err(fail(ErrorCode::Encoding(
324 structured_asn1::ErrorCode::UnexpectedTag,
325 )));
326 }
327 read_standard_attributes(&inside, &standard, field)?;
328
329 let mut next = inside.next_element().field(field)?;
331 if let Some(domain_defined) = next
332 && domain_defined.tag() == Tag::constructed(universal::SEQUENCE)
333 {
334 read_domain_defined(&inside, &domain_defined, field)?;
335 next = inside.next_element().field(field)?;
336 }
337 if let Some(extensions) = next {
338 if extensions.tag() != Tag::constructed(universal::SET) {
339 return Err(fail(ErrorCode::Encoding(
340 structured_asn1::ErrorCode::UnexpectedTag,
341 )));
342 }
343 read_extension_attributes(&inside, &extensions, field)?;
344 if !inside.is_empty() {
345 return Err(fail(ErrorCode::TrailingData));
346 }
347 }
348 Ok(())
349}
350
351const X400_NUMERIC_STRING: u32 = 18;
354
355fn x400_string(element: &Element<'_>, field: &'static str, size: (usize, usize)) -> Result<()> {
359 let fail = |code| Error::new(code, field, element.span().start);
360 let contents = element.contents();
361 let fits = match (
364 element.tag().class(),
365 element.tag().number(),
366 element.tag().is_constructed(),
367 ) {
368 (Class::Universal, Some(X400_NUMERIC_STRING), false) => crate::name::is_numeric(contents),
369 (Class::Universal, Some(universal::PRINTABLE_STRING), false) => {
370 crate::name::is_printable(contents)
371 }
372 _ => {
373 return Err(fail(ErrorCode::Encoding(
374 structured_asn1::ErrorCode::UnexpectedTag,
375 )));
376 }
377 };
378 if !fits || contents.len() < size.0 || contents.len() > size.1 {
379 return Err(fail(ErrorCode::MalformedValue));
380 }
381 Ok(())
382}
383
384fn x400_printable(element: &Element<'_>, field: &'static str, size: (usize, usize)) -> Result<()> {
387 let fail = |code| Error::new(code, field, element.span().start);
388 let tag = element.tag();
389 if tag.class() != Class::Universal
390 || tag.number() != Some(universal::PRINTABLE_STRING)
391 || tag.is_constructed()
392 {
393 return Err(fail(ErrorCode::Encoding(
394 structured_asn1::ErrorCode::UnexpectedTag,
395 )));
396 }
397 let contents = element.contents();
398 if !crate::name::is_printable(contents) || contents.len() < size.0 || contents.len() > size.1 {
399 return Err(fail(ErrorCode::MalformedValue));
400 }
401 Ok(())
402}
403
404#[derive(Clone, Copy)]
408enum X400Repertoire {
409 Numeric,
410 Printable,
411 Teletex,
412}
413
414fn x400_implicit(
417 element: &Element<'_>,
418 field: &'static str,
419 repertoire: X400Repertoire,
420 most: usize,
421) -> Result<()> {
422 let fail = |code| Error::new(code, field, element.span().start);
423 let contents = element.contents();
424 if contents.is_empty() || contents.len() > most {
431 return Err(fail(ErrorCode::MalformedValue));
432 }
433 let fits = match repertoire {
434 X400Repertoire::Numeric => crate::name::is_numeric(contents),
435 X400Repertoire::Printable => crate::name::is_printable(contents),
436 X400Repertoire::Teletex => true,
437 };
438 if !fits {
439 return Err(fail(ErrorCode::MalformedValue));
440 }
441 Ok(())
442}
443
444fn x400_teletex(element: &Element<'_>, field: &'static str, size: (usize, usize)) -> Result<()> {
446 let fail = |code| Error::new(code, field, element.span().start);
447 if element.tag() != Tag::primitive(20) {
450 return Err(fail(ErrorCode::Encoding(
451 structured_asn1::ErrorCode::UnexpectedTag,
452 )));
453 }
454 let length = element.contents().len();
455 if length < size.0 || length > size.1 {
456 return Err(fail(ErrorCode::MalformedValue));
457 }
458 Ok(())
459}
460
461fn x400_bare_country(value: &Element<'_>, field: &'static str) -> Result<()> {
465 let fail = |code| Error::new(code, field, value.span().start);
466 let contents = value.contents();
467 let fits = match (
468 value.tag().class(),
469 value.tag().number(),
470 value.tag().is_constructed(),
471 ) {
472 (Class::Universal, Some(X400_NUMERIC_STRING), false) => {
473 contents.len() == 3 && contents.iter().all(u8::is_ascii_digit)
474 }
475 (Class::Universal, Some(universal::PRINTABLE_STRING), false) => {
476 contents.len() == 2 && contents.iter().all(u8::is_ascii_uppercase)
477 }
478 _ => {
479 return Err(fail(ErrorCode::Encoding(
480 structured_asn1::ErrorCode::UnexpectedTag,
481 )));
482 }
483 };
484 if !fits {
485 return Err(fail(ErrorCode::MalformedValue));
486 }
487 Ok(())
488}
489
490fn x400_country<'a>(parent: &Reader<'a>, wrapper: &Element<'a>, field: &'static str) -> Result<()> {
492 let fail = |code| Error::new(code, field, wrapper.span().start);
493 let mut inside = parent.enter(wrapper).field(field)?;
494 let value = inside
495 .next_element()
496 .field(field)?
497 .ok_or_else(|| fail(ErrorCode::MissingField))?;
498 if !inside.is_empty() {
499 return Err(fail(ErrorCode::TrailingData));
500 }
501 x400_bare_country(&value, field)
502}
503
504fn x400_choice<'a>(
507 parent: &Reader<'a>,
508 wrapper: &Element<'a>,
509 field: &'static str,
510 numeric: (usize, usize),
511 printable: (usize, usize),
512) -> Result<()> {
513 let fail = |code| Error::new(code, field, wrapper.span().start);
514 let mut inside = parent.enter(wrapper).field(field)?;
515 let value = inside
516 .next_element()
517 .field(field)?
518 .ok_or_else(|| fail(ErrorCode::MissingField))?;
519 if !inside.is_empty() {
520 return Err(fail(ErrorCode::TrailingData));
521 }
522 let size = match (value.tag().class(), value.tag().number()) {
523 (Class::Universal, Some(X400_NUMERIC_STRING)) => numeric,
524 (Class::Universal, Some(universal::PRINTABLE_STRING)) => printable,
525 _ => {
526 return Err(fail(ErrorCode::Encoding(
527 structured_asn1::ErrorCode::UnexpectedTag,
528 )));
529 }
530 };
531 x400_string(&value, field, size)
532}
533
534fn read_standard_attributes<'a>(
538 parent: &Reader<'a>,
539 element: &Element<'a>,
540 field: &'static str,
541) -> Result<()> {
542 let mut inside = parent.enter(element).field(field)?;
543 let mut last_rank = -1i8;
544 while let Some(member) = inside.next_element().field(field)? {
545 let bad = |code| Error::new(code, field, member.span().start);
546 let tag = member.tag();
547 let Some(number) = tag.number() else {
550 return Err(bad(ErrorCode::Encoding(
551 structured_asn1::ErrorCode::UnexpectedTag,
552 )));
553 };
554 let rank: i8 = match (tag.class(), number, tag.is_constructed()) {
555 (Class::Application, 1, true) => {
558 x400_country(&inside, &member, field)?;
559 0
560 }
561 (Class::Application, 2, true) => {
564 x400_choice(&inside, &member, field, (0, 16), (0, 16))?;
565 1
566 }
567 (Class::ContextSpecific, 0, false) => {
569 x400_implicit(&member, field, X400Repertoire::Numeric, 16)?;
570 2
571 }
572 (Class::ContextSpecific, 1, false) => {
574 x400_implicit(&member, field, X400Repertoire::Printable, 24)?;
575 3
576 }
577 (Class::ContextSpecific, 2, true) => {
579 x400_choice(&inside, &member, field, (1, 16), (1, 16))?;
580 4
581 }
582 (Class::ContextSpecific, 3, false) => {
584 x400_implicit(&member, field, X400Repertoire::Printable, 64)?;
585 5
586 }
587 (Class::ContextSpecific, 4, false) => {
589 x400_implicit(&member, field, X400Repertoire::Numeric, 32)?;
590 6
591 }
592 (Class::ContextSpecific, 5, true) => {
594 read_personal_name(&inside, &member, field, X400Repertoire::Printable)?;
595 7
596 }
597 (Class::ContextSpecific, 6, true) => {
601 let mut units = inside.enter(&member).field(field)?;
602 let mut count = 0usize;
603 while let Some(unit) = units.next_element().field(field)? {
604 x400_printable(&unit, field, (1, 32))?;
605 count += 1;
606 }
607 if !(1..=4).contains(&count) {
608 return Err(bad(ErrorCode::MalformedValue));
609 }
610 8
611 }
612 _ => {
613 return Err(bad(ErrorCode::Encoding(
614 structured_asn1::ErrorCode::UnexpectedTag,
615 )));
616 }
617 };
618 if rank <= last_rank {
622 return Err(bad(ErrorCode::UnexpectedField));
623 }
624 last_rank = rank;
625 }
626 Ok(())
627}
628
629fn read_personal_name<'a>(
633 parent: &Reader<'a>,
634 element: &Element<'a>,
635 field: &'static str,
636 repertoire: X400Repertoire,
637) -> Result<()> {
638 let fail = |code| Error::new(code, field, element.span().start);
639 let mut inside = parent.enter(element).field(field)?;
640 let mut seen = [false; 4];
641 let mut last: Option<usize> = None;
642 while let Some(part) = inside.next_element().field(field)? {
643 let bad = |code| Error::new(code, field, part.span().start);
644 let (number, most) = match (
645 part.tag().class(),
646 part.tag().number(),
647 part.tag().is_constructed(),
648 ) {
649 (Class::ContextSpecific, Some(0), false) => (0usize, 40),
650 (Class::ContextSpecific, Some(1), false) => (1, 16),
651 (Class::ContextSpecific, Some(2), false) => (2, 5),
652 (Class::ContextSpecific, Some(3), false) => (3, 3),
653 _ => {
654 return Err(bad(ErrorCode::Encoding(
655 structured_asn1::ErrorCode::UnexpectedTag,
656 )));
657 }
658 };
659 if seen[number] {
660 return Err(bad(ErrorCode::UnexpectedField));
661 }
662 if inside.encoding().is_der() && last.is_some_and(|last| number < last) {
666 return Err(bad(ErrorCode::UnexpectedField));
667 }
668 seen[number] = true;
669 last = Some(number);
670 x400_implicit(&part, field, repertoire, most)?;
671 }
672 if !seen[0] {
673 return Err(fail(ErrorCode::MissingField));
674 }
675 Ok(())
676}
677
678fn read_domain_defined<'a>(
681 parent: &Reader<'a>,
682 element: &Element<'a>,
683 field: &'static str,
684) -> Result<()> {
685 read_defined_pairs(parent, element, field, false)
686}
687
688fn read_defined_pairs<'a>(
691 parent: &Reader<'a>,
692 element: &Element<'a>,
693 field: &'static str,
694 teletex: bool,
695) -> Result<()> {
696 let fail = |code| Error::new(code, field, element.span().start);
697 if element.tag() != Tag::constructed(universal::SEQUENCE) {
698 return Err(fail(ErrorCode::Encoding(
699 structured_asn1::ErrorCode::UnexpectedTag,
700 )));
701 }
702 let held_string = |element: &Element<'_>, size: (usize, usize)| {
703 if teletex {
704 x400_teletex(element, field, size)
705 } else {
706 x400_printable(element, field, size)
709 }
710 };
711 let mut inside = parent.enter(element).field(field)?;
712 let mut count = 0usize;
713 while let Some(pair) = inside.next_element().field(field)? {
714 let bad = |code| Error::new(code, field, pair.span().start);
715 if pair.tag() != Tag::constructed(universal::SEQUENCE) {
716 return Err(bad(ErrorCode::Encoding(
717 structured_asn1::ErrorCode::UnexpectedTag,
718 )));
719 }
720 let mut two = inside.enter(&pair).field(field)?;
721 let kind = two
722 .next_element()
723 .field(field)?
724 .ok_or_else(|| bad(ErrorCode::MissingField))?;
725 held_string(&kind, (1, 8))?;
726 let value = two
727 .next_element()
728 .field(field)?
729 .ok_or_else(|| bad(ErrorCode::MissingField))?;
730 held_string(&value, (1, 128))?;
731 if !two.is_empty() {
732 return Err(bad(ErrorCode::TrailingData));
733 }
734 count += 1;
735 }
736 if !(1..=4).contains(&count) {
737 return Err(fail(ErrorCode::MalformedValue));
738 }
739 Ok(())
740}
741
742fn read_extension_attributes<'a>(
746 parent: &Reader<'a>,
747 element: &Element<'a>,
748 field: &'static str,
749) -> Result<()> {
750 let fail = |code| Error::new(code, field, element.span().start);
751 let mut inside = parent.enter(element).field(field)?;
752 let mut count = 0usize;
753 let mut previous: Option<&[u8]> = None;
754 while let Some(entry) = inside.next_element().field(field)? {
755 let bad = |code| Error::new(code, field, entry.span().start);
756 if entry.tag() != Tag::constructed(universal::SEQUENCE) {
757 return Err(bad(ErrorCode::Encoding(
758 structured_asn1::ErrorCode::UnexpectedTag,
759 )));
760 }
761 if inside.encoding().is_der()
767 && let Some(previous) = previous
768 {
769 inside
770 .charge(previous.len().max(entry.as_bytes().len()) as u64)
771 .field(field)?;
772 if entry.as_bytes() < previous {
773 return Err(bad(ErrorCode::UnexpectedField));
774 }
775 }
776 previous = Some(entry.as_bytes());
777 let mut two = inside.enter(&entry).field(field)?;
778 let kind = two
779 .next_element()
780 .field(field)?
781 .ok_or_else(|| bad(ErrorCode::MissingField))?;
782 if extension::context_of(kind.tag()) != Some((0, false)) {
786 return Err(bad(ErrorCode::Encoding(
787 structured_asn1::ErrorCode::UnexpectedTag,
788 )));
789 }
790 let number = two.integer(&kind).field(field)?;
791 if number.as_u32().is_none_or(|number| number > 256) {
792 return Err(bad(ErrorCode::MalformedValue));
793 }
794 let value = two
795 .next_element()
796 .field(field)?
797 .ok_or_else(|| bad(ErrorCode::MissingField))?;
798 if extension::context_of(value.tag()) != Some((1, true)) {
801 return Err(bad(ErrorCode::Encoding(
802 structured_asn1::ErrorCode::UnexpectedTag,
803 )));
804 }
805 let mut held = two.enter(&value).field(field)?;
806 let Some(declared) = held.next_element().field(field)? else {
807 return Err(bad(ErrorCode::MissingField));
808 };
809 let number = number
814 .as_u32()
815 .expect("bounded to 0..=256 above, which fits");
816 read_extension_value(&held, &declared, number, field)?;
817 if !held.is_empty() || !two.is_empty() {
818 return Err(bad(ErrorCode::TrailingData));
819 }
820 count += 1;
821 if count > 256 {
824 return Err(bad(ErrorCode::MalformedValue));
825 }
826 }
827 if count == 0 {
828 return Err(fail(ErrorCode::EmptySequence));
829 }
830 Ok(())
831}
832
833fn read_extension_value<'a>(
839 parent: &Reader<'a>,
840 value: &Element<'a>,
841 number: u32,
842 field: &'static str,
843) -> Result<()> {
844 let fail = |code| Error::new(code, field, value.span().start);
845 match number {
846 1 => x400_printable(value, field, (1, 64)),
849 2 | 3 => x400_teletex(value, field, (1, 64)),
851 4 => {
853 if value.tag() != Tag::constructed(universal::SET) {
854 return Err(fail(ErrorCode::Encoding(
855 structured_asn1::ErrorCode::UnexpectedTag,
856 )));
857 }
858 read_personal_name(parent, value, field, X400Repertoire::Teletex)
859 }
860 5 => {
862 if value.tag() != Tag::constructed(universal::SEQUENCE) {
863 return Err(fail(ErrorCode::Encoding(
864 structured_asn1::ErrorCode::UnexpectedTag,
865 )));
866 }
867 let mut units = parent.enter(value).field(field)?;
868 let mut count = 0usize;
869 while let Some(unit) = units.next_element().field(field)? {
870 x400_teletex(&unit, field, (1, 32))?;
871 count += 1;
872 }
873 if !(1..=4).contains(&count) {
874 return Err(fail(ErrorCode::MalformedValue));
875 }
876 Ok(())
877 }
878 6 => read_defined_pairs(parent, value, field, true),
880 7 => x400_printable(value, field, (1, 16)),
882 8 => x400_bare_country(value, field),
885 9 => x400_bare_choice(value, field, (1, 16), (1, 16)),
887 10..=15 | 17..=21 => read_pds_parameter(parent, value, field, 30),
890 16 => read_unformatted_address(parent, value, field),
892 22 => read_extended_network_address(parent, value, field),
894 23 => {
896 if value.tag() != Tag::primitive(universal::INTEGER) {
897 return Err(fail(ErrorCode::Encoding(
898 structured_asn1::ErrorCode::UnexpectedTag,
899 )));
900 }
901 let option = parent.integer(value).field(field)?;
902 if option.as_u32().is_none_or(|option| option > 256) {
903 return Err(fail(ErrorCode::MalformedValue));
904 }
905 Ok(())
906 }
907 _ => Err(fail(ErrorCode::MalformedValue)),
908 }
909}
910
911fn x400_bare_choice(
914 value: &Element<'_>,
915 field: &'static str,
916 numeric: (usize, usize),
917 printable: (usize, usize),
918) -> Result<()> {
919 let fail = |code| Error::new(code, field, value.span().start);
920 let size = match (
921 value.tag().class(),
922 value.tag().number(),
923 value.tag().is_constructed(),
924 ) {
925 (Class::Universal, Some(X400_NUMERIC_STRING), false) => numeric,
926 (Class::Universal, Some(universal::PRINTABLE_STRING), false) => printable,
927 _ => {
928 return Err(fail(ErrorCode::Encoding(
929 structured_asn1::ErrorCode::UnexpectedTag,
930 )));
931 }
932 };
933 x400_string(value, field, size)
934}
935
936fn read_pds_parameter<'a>(
939 parent: &Reader<'a>,
940 value: &Element<'a>,
941 field: &'static str,
942 most: usize,
943) -> Result<()> {
944 let fail = |code| Error::new(code, field, value.span().start);
945 if value.tag() != Tag::constructed(universal::SET) {
946 return Err(fail(ErrorCode::Encoding(
947 structured_asn1::ErrorCode::UnexpectedTag,
948 )));
949 }
950 let mut inside = parent.enter(value).field(field)?;
951 let mut seen_printable = false;
952 let mut seen_teletex = false;
953 while let Some(member) = inside.next_element().field(field)? {
954 let bad = |code| Error::new(code, field, member.span().start);
955 if member.tag() == Tag::primitive(universal::PRINTABLE_STRING) {
956 if seen_printable || (seen_teletex && inside.encoding().is_der()) {
961 return Err(bad(ErrorCode::UnexpectedField));
962 }
963 seen_printable = true;
964 x400_string(&member, field, (1, most))?;
965 } else if member.tag() == Tag::primitive(20) {
966 if seen_teletex {
967 return Err(bad(ErrorCode::UnexpectedField));
968 }
969 seen_teletex = true;
970 x400_teletex(&member, field, (1, most))?;
971 } else {
972 return Err(bad(ErrorCode::Encoding(
973 structured_asn1::ErrorCode::UnexpectedTag,
974 )));
975 }
976 }
977 Ok(())
978}
979
980fn read_unformatted_address<'a>(
983 parent: &Reader<'a>,
984 value: &Element<'a>,
985 field: &'static str,
986) -> Result<()> {
987 let fail = |code| Error::new(code, field, value.span().start);
988 if value.tag() != Tag::constructed(universal::SET) {
989 return Err(fail(ErrorCode::Encoding(
990 structured_asn1::ErrorCode::UnexpectedTag,
991 )));
992 }
993 let mut inside = parent.enter(value).field(field)?;
994 let mut seen_lines = false;
995 let mut seen_teletex = false;
996 while let Some(member) = inside.next_element().field(field)? {
997 let bad = |code| Error::new(code, field, member.span().start);
998 if member.tag() == Tag::constructed(universal::SEQUENCE) {
999 if seen_lines || (seen_teletex && inside.encoding().is_der()) {
1004 return Err(bad(ErrorCode::UnexpectedField));
1005 }
1006 seen_lines = true;
1007 let mut lines = inside.enter(&member).field(field)?;
1008 let mut count = 0usize;
1009 while let Some(line) = lines.next_element().field(field)? {
1010 x400_printable(&line, field, (1, 30))?;
1013 count += 1;
1014 }
1015 if !(1..=6).contains(&count) {
1016 return Err(bad(ErrorCode::MalformedValue));
1017 }
1018 } else if member.tag() == Tag::primitive(20) {
1019 if seen_teletex {
1020 return Err(bad(ErrorCode::UnexpectedField));
1021 }
1022 seen_teletex = true;
1023 x400_teletex(&member, field, (1, 180))?;
1024 } else {
1025 return Err(bad(ErrorCode::Encoding(
1026 structured_asn1::ErrorCode::UnexpectedTag,
1027 )));
1028 }
1029 }
1030 Ok(())
1031}
1032
1033fn read_e163_address<'a>(
1035 parent: &Reader<'a>,
1036 value: &Element<'a>,
1037 field: &'static str,
1038) -> Result<()> {
1039 let fail = |code| Error::new(code, field, value.span().start);
1040 let mut inside = parent.enter(value).field(field)?;
1041 let number = inside
1042 .next_element()
1043 .field(field)?
1044 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1045 if extension::context_of(number.tag()) != Some((0, false)) {
1046 return Err(fail(ErrorCode::Encoding(
1047 structured_asn1::ErrorCode::UnexpectedTag,
1048 )));
1049 }
1050 x400_implicit(&number, field, X400Repertoire::Numeric, 15)?;
1051 if let Some(sub) = inside.next_element().field(field)? {
1052 if extension::context_of(sub.tag()) != Some((1, false)) {
1053 return Err(fail(ErrorCode::Encoding(
1054 structured_asn1::ErrorCode::UnexpectedTag,
1055 )));
1056 }
1057 x400_implicit(&sub, field, X400Repertoire::Numeric, 40)?;
1058 }
1059 if !inside.is_empty() {
1060 return Err(fail(ErrorCode::TrailingData));
1061 }
1062 Ok(())
1063}
1064
1065fn read_extended_network_address<'a>(
1069 parent: &Reader<'a>,
1070 value: &Element<'a>,
1071 field: &'static str,
1072) -> Result<()> {
1073 let fail = |code| Error::new(code, field, value.span().start);
1074 if value.tag() == Tag::constructed(universal::SEQUENCE) {
1075 read_e163_address(parent, value, field)
1076 } else if extension::context_of(value.tag()) == Some((0, true)) {
1077 let mut inside = parent.enter(value).field(field)?;
1080 let mut last: i8 = -1;
1081 let mut saw_network = false;
1082 while let Some(member) = inside.next_element().field(field)? {
1083 let bad = |code| Error::new(code, field, member.span().start);
1084 let Some((number, true)) = extension::context_of(member.tag()) else {
1085 return Err(bad(ErrorCode::Encoding(
1086 structured_asn1::ErrorCode::UnexpectedTag,
1087 )));
1088 };
1089 let rank = i8::try_from(number).map_err(|_| {
1090 bad(ErrorCode::Encoding(
1091 structured_asn1::ErrorCode::UnexpectedTag,
1092 ))
1093 })?;
1094 if rank > 3 {
1095 return Err(bad(ErrorCode::Encoding(
1096 structured_asn1::ErrorCode::UnexpectedTag,
1097 )));
1098 }
1099 if rank <= last {
1100 return Err(bad(ErrorCode::UnexpectedField));
1101 }
1102 last = rank;
1103 let mut held = inside.enter(&member).field(field)?;
1104 if rank == 3 {
1105 let addresses = held
1107 .next_element()
1108 .field(field)?
1109 .ok_or_else(|| bad(ErrorCode::MissingField))?;
1110 if addresses.tag() != Tag::constructed(universal::SET) {
1111 return Err(bad(ErrorCode::Encoding(
1112 structured_asn1::ErrorCode::UnexpectedTag,
1113 )));
1114 }
1115 let mut each = held.enter(&addresses).field(field)?;
1116 let mut count = 0usize;
1117 let mut previous: Option<&[u8]> = None;
1118 while let Some(address) = each.next_element().field(field)? {
1119 if address.tag() != Tag::primitive(universal::OCTET_STRING) {
1120 return Err(bad(ErrorCode::Encoding(
1121 structured_asn1::ErrorCode::UnexpectedTag,
1122 )));
1123 }
1124 if each.encoding().is_der()
1130 && let Some(previous) = previous
1131 {
1132 each.charge(previous.len().max(address.as_bytes().len()) as u64)
1133 .field(field)?;
1134 if address.as_bytes() < previous {
1135 return Err(bad(ErrorCode::UnexpectedField));
1136 }
1137 }
1138 previous = Some(address.as_bytes());
1139 count += 1;
1140 }
1141 if count == 0 {
1142 return Err(bad(ErrorCode::EmptySequence));
1143 }
1144 saw_network = true;
1145 } else {
1146 let selector = held
1148 .next_element()
1149 .field(field)?
1150 .ok_or_else(|| bad(ErrorCode::MissingField))?;
1151 if selector.tag() != Tag::primitive(universal::OCTET_STRING) {
1152 return Err(bad(ErrorCode::Encoding(
1153 structured_asn1::ErrorCode::UnexpectedTag,
1154 )));
1155 }
1156 }
1157 if !held.is_empty() {
1158 return Err(bad(ErrorCode::TrailingData));
1159 }
1160 }
1161 if !saw_network {
1162 return Err(fail(ErrorCode::MissingField));
1163 }
1164 Ok(())
1165 } else {
1166 Err(fail(ErrorCode::Encoding(
1167 structured_asn1::ErrorCode::UnexpectedTag,
1168 )))
1169 }
1170}
1171
1172fn read_edi_party<'a>(
1177 parent: &Reader<'a>,
1178 element: &Element<'a>,
1179 field: &'static str,
1180) -> Result<()> {
1181 let fail = |code| Error::new(code, field, element.span().start);
1182
1183 let mut inside = parent.enter(element).field(field)?;
1184 let mut next = inside.next_element().field(field)?;
1185
1186 if let Some(assigner) = next
1187 && extension::context_of(assigner.tag()) == Some((0, true))
1188 {
1189 require_directory_string(&inside, &assigner, field)?;
1190 next = inside.next_element().field(field)?;
1191 }
1192
1193 let party = next.ok_or_else(|| fail(ErrorCode::MissingField))?;
1194 if extension::context_of(party.tag()) != Some((1, true)) {
1195 return Err(Error::new(
1196 ErrorCode::UnexpectedField,
1197 field,
1198 party.span().start,
1199 ));
1200 }
1201 require_directory_string(&inside, &party, field)?;
1202
1203 if !inside.is_empty() {
1204 return Err(fail(ErrorCode::TrailingData));
1205 }
1206 Ok(())
1207}
1208
1209fn require_directory_string<'a>(
1211 parent: &Reader<'a>,
1212 wrapper: &Element<'a>,
1213 field: &'static str,
1214) -> Result<()> {
1215 const MOST: usize = 32768;
1217 let fail = |code| Error::new(code, field, wrapper.span().start);
1218
1219 let mut inside = parent.enter(wrapper).field(field)?;
1220 let value = inside
1221 .next_element()
1222 .field(field)?
1223 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1224 if !inside.is_empty() {
1225 return Err(fail(ErrorCode::TrailingData));
1226 }
1227
1228 let tag = value.tag();
1233 let is_directory_string = tag.class() == Class::Universal
1234 && !tag.is_constructed()
1235 && matches!(tag.number(), Some(12 | 19 | 20 | 28 | 30));
1236 let ceiling = match tag.number() {
1241 Some(12 | 28) => MOST.saturating_mul(4),
1242 Some(30) => MOST.saturating_mul(2),
1243 _ => MOST,
1244 };
1245 if value.contents().len() > ceiling {
1246 return Err(fail(ErrorCode::MalformedValue));
1247 }
1248 parent.charge(value.contents().len() as u64).field(field)?;
1252 let decodes = match tag.number() {
1253 Some(12) => {
1254 core::str::from_utf8(value.contents()).is_ok_and(|text| text.chars().count() <= MOST)
1255 }
1256 Some(19) => crate::name::is_printable(value.contents()) && value.contents().len() <= MOST,
1257 Some(28) => {
1258 crate::name::wide_char_count(value.contents(), 4).is_some_and(|count| count <= MOST)
1259 }
1260 Some(30) => {
1261 crate::name::wide_char_count(value.contents(), 2).is_some_and(|count| count <= MOST)
1262 }
1263 _ => value.contents().len() <= MOST,
1267 };
1268 if !is_directory_string || value.contents().is_empty() || !decodes {
1269 return Err(fail(ErrorCode::MalformedValue));
1270 }
1271 Ok(())
1272}
1273
1274fn read_other<'a>(
1275 parent: &Reader<'a>,
1276 element: &Element<'a>,
1277 field: &'static str,
1278) -> Result<GeneralName<'a>> {
1279 let fail = |code| Error::new(code, field, element.span().start);
1280
1281 let mut inside = parent.enter(element).field(field)?;
1282 let type_id = inside.read_oid().field(field)?;
1283 let wrapper = inside
1284 .next_element()
1285 .field(field)?
1286 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1287
1288 if wrapper.tag() != Tag::context(true, 0) {
1291 return Err(fail(ErrorCode::Encoding(
1292 structured_asn1::ErrorCode::UnexpectedTag,
1293 )));
1294 }
1295 if !inside.is_empty() {
1296 return Err(fail(ErrorCode::TrailingData));
1297 }
1298
1299 let mut held = inside.enter(&wrapper).field(field)?;
1303 let value = held
1304 .next_element()
1305 .field(field)?
1306 .ok_or_else(|| fail(ErrorCode::MissingField))?;
1307 if !held.is_empty() {
1308 return Err(fail(ErrorCode::TrailingData));
1309 }
1310
1311 crate::name::walk_der(&held, &value, field, crate::name::Strings::Checked)?;
1318
1319 Ok(GeneralName::Other {
1320 type_id,
1321 value: value.as_bytes(),
1322 })
1323}
1324
1325pub(crate) fn is_domain(text: &str) -> bool {
1331 text.len() <= 253
1337 && text.split('.').all(|label| {
1338 (1..=63).contains(&label.len())
1339 && label
1340 .bytes()
1341 .all(|byte| byte.is_ascii_alphanumeric() || byte == b'-')
1342 && !label.starts_with('-')
1343 && !label.ends_with('-')
1344 })
1345 && text
1346 .rsplit('.')
1347 .next()
1348 .is_some_and(|top| top.bytes().any(|byte| byte.is_ascii_alphabetic()))
1349}
1350
1351pub(crate) fn is_mailbox(text: &str) -> bool {
1363 structured_email_address::is_smtp_mailbox(text)
1364}
1365
1366pub(crate) fn is_absolute_uri(text: &str) -> bool {
1374 absolute_uri::<true>(text)
1375}
1376
1377fn absolute_uri<const CERTIFICATE_NAME: bool>(text: &str) -> bool {
1378 let Some((scheme, rest)) = text.split_once(':') else {
1379 return false;
1380 };
1381 let mut bytes = scheme.bytes();
1382 if !(bytes.next().is_some_and(|byte| byte.is_ascii_alphabetic())
1383 && bytes.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'+' | b'-' | b'.')))
1384 {
1385 return false;
1386 }
1387 if CERTIFICATE_NAME && rest.is_empty() {
1395 return false;
1396 }
1397
1398 let mut userinfo = "";
1404 let mut bare_host = "";
1405 let mut tail = rest;
1406 if let Some(after) = rest.strip_prefix("//") {
1407 let end = after.find(['/', '?']).unwrap_or(after.len());
1408 let authority = &after[..end];
1409 tail = &after[end..];
1410 let (before, host_port) = match authority.split_once('@') {
1411 Some((before, host_port)) => (before, host_port),
1412 None => ("", authority),
1413 };
1414 if host_port.contains('@') {
1417 return false;
1418 }
1419 userinfo = before;
1420 let port = if let Some(inside) = host_port.strip_prefix('[') {
1421 let Some((literal, past)) = inside.split_once(']') else {
1422 return false;
1423 };
1424 if !is_ip_literal(literal) {
1425 return false;
1426 }
1427 if past.is_empty() {
1429 None
1430 } else {
1431 let Some(digits) = past.strip_prefix(':') else {
1432 return false;
1433 };
1434 Some(digits)
1435 }
1436 } else {
1437 let port = if let Some((host, port)) = host_port.split_once(':') {
1440 bare_host = host;
1441 Some(port)
1442 } else {
1443 bare_host = host_port;
1444 None
1445 };
1446 let named = bare_host.strip_suffix('.').unwrap_or(bare_host);
1458 if CERTIFICATE_NAME && !is_domain(named) && bare_host.parse::<Ipv4Addr>().is_err() {
1459 return false;
1460 }
1461 port
1462 };
1463 if port.is_some_and(|digits| !digits.bytes().all(|byte| byte.is_ascii_digit())) {
1465 return false;
1466 }
1467 }
1468
1469 uri_alphabet(userinfo) && uri_alphabet(bare_host) && uri_alphabet(tail)
1470}
1471
1472fn uri_alphabet(segment: &str) -> bool {
1477 let mut bytes = segment.bytes();
1478 while let Some(byte) = bytes.next() {
1479 let permitted = byte.is_ascii_alphanumeric()
1480 || matches!(
1481 byte,
1482 b'-' | b'.'
1483 | b'_'
1484 | b'~'
1485 | b':'
1486 | b'/'
1487 | b'?'
1488 | b'@'
1489 | b'!'
1490 | b'$'
1491 | b'&'
1492 | b'\''
1493 | b'('
1494 | b')'
1495 | b'*'
1496 | b'+'
1497 | b','
1498 | b';'
1499 | b'='
1500 );
1501 if byte == b'%' {
1502 let mut pair = [bytes.next(), bytes.next()].into_iter();
1503 if !pair.all(|digit| digit.is_some_and(|digit| digit.is_ascii_hexdigit())) {
1504 return false;
1505 }
1506 } else if !permitted {
1507 return false;
1508 }
1509 }
1510 true
1511}
1512
1513pub(crate) fn is_uri(text: &str) -> bool {
1520 uri::<true>(text)
1521}
1522
1523pub(crate) fn is_cps_uri(text: &str) -> bool {
1527 uri::<false>(text)
1528}
1529
1530fn uri<const CERTIFICATE_NAME: bool>(text: &str) -> bool {
1531 match text.split_once('#') {
1532 Some((rest, fragment)) => absolute_uri::<CERTIFICATE_NAME>(rest) && uri_alphabet(fragment),
1535 None => absolute_uri::<CERTIFICATE_NAME>(text),
1536 }
1537}
1538
1539fn is_ip_literal(text: &str) -> bool {
1544 if let Some(rest) = text.strip_prefix(['v', 'V']) {
1545 let Some((version, suffix)) = rest.split_once('.') else {
1547 return false;
1548 };
1549 return !version.is_empty()
1550 && version.bytes().all(|byte| byte.is_ascii_hexdigit())
1551 && !suffix.is_empty()
1552 && suffix.bytes().all(|byte| {
1553 byte.is_ascii_alphanumeric()
1554 || matches!(
1555 byte,
1556 b'-' | b'.'
1557 | b'_'
1558 | b'~'
1559 | b':'
1560 | b'!'
1561 | b'$'
1562 | b'&'
1563 | b'\''
1564 | b'('
1565 | b')'
1566 | b'*'
1567 | b'+'
1568 | b','
1569 | b';'
1570 | b'='
1571 )
1572 });
1573 }
1574 text.parse::<Ipv6Addr>().is_ok()
1575}
1576
1577fn is_contiguous_mask(mask: &[u8]) -> bool {
1578 let mut still_ones = true;
1579 for &byte in mask {
1580 if still_ones {
1581 if byte == 0xff {
1582 continue;
1583 }
1584 let ones = byte.leading_ones();
1586 let expected = if ones == 0 { 0 } else { 0xffu8 << (8 - ones) };
1587 if byte != expected {
1588 return false;
1589 }
1590 still_ones = false;
1591 } else if byte != 0 {
1592 return false;
1593 }
1594 }
1595 true
1596}
1597
1598fn text<'a>(
1599 parent: &Reader<'a>,
1600 contents: &'a [u8],
1601 field: &'static str,
1602 element: &Element<'a>,
1603) -> Result<&'a str> {
1604 parent.charge(contents.len() as u64).field(field)?;
1608 if contents.is_empty() {
1612 return Err(Error::new(
1613 ErrorCode::MalformedValue,
1614 field,
1615 element.span().start,
1616 ));
1617 }
1618 if !contents.is_ascii() {
1619 return Err(Error::new(
1624 ErrorCode::MalformedValue,
1625 field,
1626 element.span().start,
1627 ));
1628 }
1629 core::str::from_utf8(contents)
1630 .map_err(|_| Error::new(ErrorCode::MalformedValue, field, element.span().start))
1631}
1632
1633#[cfg(test)]
1634mod tests;