1#![cfg_attr(feature = "arbitrary", allow(clippy::arithmetic_side_effects))]
3
4mod class;
5mod mode;
6mod number;
7
8pub use self::{class::Class, mode::TagMode, number::TagNumber};
9
10use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Length, Reader, Result, Writer};
11use core::{cmp::Ordering, fmt};
12
13#[cfg(feature = "alloc")]
14use alloc::borrow::{Cow, ToOwned};
15
16const CONSTRUCTED_FLAG: u8 = 0b100000;
18
19pub trait FixedTag {
32 const TAG: Tag;
34}
35
36#[cfg(feature = "alloc")]
37impl<'a, T> FixedTag for Cow<'a, T>
38where
39 T: ToOwned + ?Sized,
40 &'a T: FixedTag,
41{
42 const TAG: Tag = <&'a T>::TAG;
43}
44
45#[diagnostic::on_unimplemented(note = "Consider adding impl of `FixedTag` to `{Self}`")]
65pub trait Tagged {
66 fn tag(&self) -> Tag;
68}
69
70impl<T: FixedTag + ?Sized> Tagged for T {
72 fn tag(&self) -> Tag {
73 T::TAG
74 }
75}
76
77#[diagnostic::on_unimplemented(note = "Consider adding impl of `FixedTag` to `{Self}`")]
113pub trait IsConstructed {
114 const CONSTRUCTED: bool;
116}
117
118impl<T: FixedTag + ?Sized> IsConstructed for T {
120 const CONSTRUCTED: bool = T::TAG.is_constructed();
121}
122
123#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
167#[derive(Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
168#[non_exhaustive]
169pub enum Tag {
170 Boolean,
172
173 Integer,
175
176 BitString,
178
179 OctetString,
181
182 Null,
184
185 ObjectIdentifier,
187
188 Real,
190
191 Enumerated,
193
194 Utf8String,
196
197 RelativeOid,
199
200 Sequence,
202
203 Set,
205
206 NumericString,
208
209 PrintableString,
211
212 TeletexString,
214
215 VideotexString,
217
218 Ia5String,
220
221 UtcTime,
223
224 GeneralizedTime,
226
227 VisibleString,
229
230 GeneralString,
232
233 BmpString,
235
236 Application {
238 constructed: bool,
240
241 number: TagNumber,
243 },
244
245 ContextSpecific {
247 constructed: bool,
249
250 number: TagNumber,
252 },
253
254 Private {
256 constructed: bool,
258
259 number: TagNumber,
261 },
262}
263
264impl Tag {
265 pub(crate) const MAX_SIZE: usize = 6;
268
269 pub(crate) fn decode_with_constructed_bit<'a>(
271 reader: &mut impl Reader<'a>,
272 ) -> Result<(Self, bool)> {
273 let first_byte = reader.read_byte()?;
274 let is_constructed = first_byte & CONSTRUCTED_FLAG != 0;
275
276 let tag = match first_byte {
277 0x01 => Tag::Boolean,
278 0x02 => Tag::Integer,
279 0x03 => Tag::BitString,
280 0x04 => Tag::OctetString,
281 0x05 => Tag::Null,
282 0x06 => Tag::ObjectIdentifier,
283 0x09 => Tag::Real,
284 0x0A => Tag::Enumerated,
285 0x0C => Tag::Utf8String,
286 0x0D => Tag::RelativeOid,
287 0x12 => Tag::NumericString,
288 0x13 => Tag::PrintableString,
289 0x14 => Tag::TeletexString,
290 0x15 => Tag::VideotexString,
291 0x16 => Tag::Ia5String,
292 0x17 => Tag::UtcTime,
293 0x18 => Tag::GeneralizedTime,
294 0x1A => Tag::VisibleString,
295 0x1B => Tag::GeneralString,
296 0x1E => Tag::BmpString,
297 #[cfg(feature = "ber")]
298 0x24 if reader.encoding_rules().is_ber() => Tag::OctetString,
299 0x30 => Tag::Sequence, 0x31 => Tag::Set, 0x40..=0x7F => {
302 let (constructed, number) = parse_parts(first_byte, reader)?;
303
304 Tag::Application {
305 constructed,
306 number,
307 }
308 }
309 0x80..=0xBF => {
310 let (constructed, number) = parse_parts(first_byte, reader)?;
311
312 Tag::ContextSpecific {
313 constructed,
314 number,
315 }
316 }
317 0xC0..=0xFF => {
318 let (constructed, number) = parse_parts(first_byte, reader)?;
319
320 Tag::Private {
321 constructed,
322 number,
323 }
324 }
325 0x1F => return Err(reader.error(ErrorKind::TagNumberInvalid)),
327 byte => return Err(reader.error(ErrorKind::TagUnknown { byte })),
328 };
329
330 Ok((tag, is_constructed))
331 }
332
333 pub fn peek<'a>(reader: &impl Reader<'a>) -> Result<Self> {
340 Self::decode(&mut reader.clone())
341 }
342
343 pub(crate) fn peek_matches<'a, R: Reader<'a>>(
345 reader: &mut R,
346 expected_class: Class,
347 expected_tag_number: TagNumber,
348 ) -> Result<bool> {
349 if reader.is_finished() {
350 return Ok(false);
351 }
352
353 let tag = Self::peek(reader)?;
354 Ok(tag.class() == expected_class && tag.number() == expected_tag_number)
355 }
356
357 pub fn assert_eq(self, expected: Tag) -> Result<Tag> {
362 if self == expected {
363 Ok(self)
364 } else {
365 Err(self.unexpected_error(Some(expected)).into())
366 }
367 }
368
369 #[must_use]
371 pub const fn class(self) -> Class {
372 match self {
373 Tag::Application { .. } => Class::Application,
374 Tag::ContextSpecific { .. } => Class::ContextSpecific,
375 Tag::Private { .. } => Class::Private,
376 _ => Class::Universal,
377 }
378 }
379
380 #[must_use]
382 pub const fn number(self) -> TagNumber {
383 match self {
384 Tag::Boolean => TagNumber(1),
385 Tag::Integer => TagNumber(2),
386 Tag::BitString => TagNumber(3),
387 Tag::OctetString => TagNumber(4),
388 Tag::Null => TagNumber(5),
389 Tag::ObjectIdentifier => TagNumber(6),
390 Tag::Real => TagNumber(9),
391 Tag::Enumerated => TagNumber(10),
392 Tag::Utf8String => TagNumber(12),
393 Tag::RelativeOid => TagNumber(13),
394 Tag::Sequence => TagNumber(16),
395 Tag::Set => TagNumber(17),
396 Tag::NumericString => TagNumber(18),
397 Tag::PrintableString => TagNumber(19),
398 Tag::TeletexString => TagNumber(20),
399 Tag::VideotexString => TagNumber(21),
400 Tag::Ia5String => TagNumber(22),
401 Tag::UtcTime => TagNumber(23),
402 Tag::GeneralizedTime => TagNumber(24),
403 Tag::VisibleString => TagNumber(26),
404 Tag::GeneralString => TagNumber(27),
405 Tag::BmpString => TagNumber(30),
406 Tag::Application { number, .. } => number,
407 Tag::ContextSpecific { number, .. } => number,
408 Tag::Private { number, .. } => number,
409 }
410 }
411
412 #[must_use]
414 pub const fn is_constructed(self) -> bool {
415 match self {
416 Tag::Sequence | Tag::Set => true,
417 Tag::Application { constructed, .. }
418 | Tag::ContextSpecific { constructed, .. }
419 | Tag::Private { constructed, .. } => constructed,
420 _ => false,
421 }
422 }
423
424 #[must_use]
426 pub const fn is_application(self) -> bool {
427 matches!(self.class(), Class::Application)
428 }
429
430 #[must_use]
432 pub const fn is_context_specific(self) -> bool {
433 matches!(self.class(), Class::ContextSpecific)
434 }
435
436 #[must_use]
438 pub const fn is_private(self) -> bool {
439 matches!(self.class(), Class::Private)
440 }
441
442 #[must_use]
444 pub const fn is_universal(self) -> bool {
445 matches!(self.class(), Class::Universal)
446 }
447
448 #[must_use]
450 pub fn length_error(self) -> ErrorKind {
451 ErrorKind::Length { tag: self }
452 }
453
454 #[must_use]
457 pub fn non_canonical_error(self) -> ErrorKind {
458 ErrorKind::Noncanonical { tag: self }
459 }
460
461 #[must_use]
464 pub fn unexpected_error(self, expected: Option<Self>) -> ErrorKind {
465 ErrorKind::TagUnexpected {
466 expected,
467 actual: self,
468 }
469 }
470
471 #[must_use]
474 pub fn value_error(self) -> ErrorKind {
475 ErrorKind::Value { tag: self }
476 }
477}
478
479impl<'a> Decode<'a> for Tag {
480 type Error = Error;
481
482 fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> {
483 Self::decode_with_constructed_bit(reader).map(|(tag, _)| tag)
484 }
485}
486
487fn parse_parts<'a, R: Reader<'a>>(first_byte: u8, reader: &mut R) -> Result<(bool, TagNumber)> {
488 let constructed = first_byte & CONSTRUCTED_FLAG != 0;
489 let first_number_part = first_byte & TagNumber::MASK;
490
491 if first_number_part != TagNumber::MASK {
492 return Ok((constructed, TagNumber(first_number_part.into())));
493 }
494
495 let mut multi_byte_tag_number = 0;
496
497 for i in 0..Tag::MAX_SIZE - 1 {
498 let byte = reader.read_byte()?;
499 multi_byte_tag_number |= u32::from(byte & 0x7F);
500
501 if byte & 0x80 == 0 {
502 if multi_byte_tag_number < u32::from(TagNumber::MASK) {
503 return Err(reader.error(ErrorKind::TagNumberInvalid));
504 }
505
506 return Ok((constructed, TagNumber(multi_byte_tag_number)));
507 } else if i == 0 && multi_byte_tag_number == 0 {
508 return Err(reader.error(ErrorKind::TagNumberInvalid));
510 }
511
512 if multi_byte_tag_number.leading_zeros() < 7 {
513 return Err(reader.error(ErrorKind::TagNumberInvalid));
514 }
515
516 multi_byte_tag_number <<= 7;
517 }
518
519 Err(reader.error(ErrorKind::TagNumberInvalid))
521}
522
523impl Encode for Tag {
524 #[allow(clippy::cast_possible_truncation)]
525 fn encoded_len(&self) -> Result<Length> {
526 let number = self.number().value();
527
528 let length = if number <= 30 {
529 Length::ONE
530 } else {
531 Length::new(number.ilog2() / 7 + 2)
532 };
533
534 Ok(length)
535 }
536
537 fn encode(&self, writer: &mut impl Writer) -> Result<()> {
538 let mut first_byte = (self.class() as u8) | (u8::from(self.is_constructed()) << 5);
539
540 let number = self.number().value();
541
542 if number < u32::from(TagNumber::MASK) {
543 first_byte |= (number & 0x1F) as u8;
544 writer.write_byte(first_byte)?;
545 } else {
546 first_byte |= TagNumber::MASK;
547 writer.write_byte(first_byte)?;
548
549 let extra_bytes = number.ilog2() / 7 + 1;
550
551 for shift in (0..extra_bytes).rev() {
552 let mut byte = ((number >> (shift * 7)) & 0x7f) as u8;
553
554 if shift != 0 {
555 byte |= 0x80;
556 }
557
558 writer.write_byte(byte)?;
559 }
560 }
561
562 Ok(())
563 }
564}
565
566impl DerOrd for Tag {
567 fn der_cmp(&self, other: &Self) -> Result<Ordering> {
571 let mut buf1 = [0u8; Tag::MAX_SIZE];
572 let mut buf2 = [0u8; Tag::MAX_SIZE];
573 let a = self.encode_to_slice(&mut buf1)?;
574 let b = other.encode_to_slice(&mut buf2)?;
575 Ok(a.cmp(b))
576 }
577}
578
579impl fmt::Display for Tag {
580 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
581 const FIELD_TYPE: [&str; 2] = ["primitive", "constructed"];
582
583 match *self {
584 Tag::Boolean => f.write_str("BOOLEAN"),
585 Tag::Integer => f.write_str("INTEGER"),
586 Tag::BitString => f.write_str("BIT STRING"),
587 Tag::OctetString => f.write_str("OCTET STRING"),
588 Tag::Null => f.write_str("NULL"),
589 Tag::ObjectIdentifier => f.write_str("OBJECT IDENTIFIER"),
590 Tag::Real => f.write_str("REAL"),
591 Tag::Enumerated => f.write_str("ENUMERATED"),
592 Tag::Utf8String => f.write_str("UTF8String"),
593 Tag::RelativeOid => f.write_str("RELATIVE OID"),
594 Tag::Set => f.write_str("SET"),
595 Tag::NumericString => f.write_str("NumericString"),
596 Tag::PrintableString => f.write_str("PrintableString"),
597 Tag::TeletexString => f.write_str("TeletexString"),
598 Tag::VideotexString => f.write_str("VideotexString"),
599 Tag::Ia5String => f.write_str("IA5String"),
600 Tag::UtcTime => f.write_str("UTCTime"),
601 Tag::GeneralizedTime => f.write_str("GeneralizedTime"),
602 Tag::VisibleString => f.write_str("VisibleString"),
603 Tag::GeneralString => f.write_str("GeneralString"),
604 Tag::BmpString => f.write_str("BMPString"),
605 Tag::Sequence => f.write_str("SEQUENCE"),
606 Tag::Application {
607 constructed,
608 number,
609 } => write!(
610 f,
611 "APPLICATION [{}] ({})",
612 number,
613 FIELD_TYPE[usize::from(constructed)]
614 ),
615 Tag::ContextSpecific {
616 constructed,
617 number,
618 } => write!(
619 f,
620 "CONTEXT-SPECIFIC [{}] ({})",
621 number,
622 FIELD_TYPE[usize::from(constructed)]
623 ),
624 Tag::Private {
625 constructed,
626 number,
627 } => write!(
628 f,
629 "PRIVATE [{}] ({})",
630 number,
631 FIELD_TYPE[usize::from(constructed)]
632 ),
633 }
634 }
635}
636
637impl fmt::Debug for Tag {
638 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
639 write!(f, "Tag(0x{:02x}: {})", self.number().value(), self)
640 }
641}
642
643#[cfg(test)]
644mod tests {
645 use core::cmp::Ordering;
646
647 use hex_literal::hex;
648
649 use super::{Class, Tag, TagNumber};
650 use crate::{Decode, DerOrd, ErrorKind, Length, Reader, SliceReader};
651
652 #[test]
653 fn tag_class() {
654 assert_eq!(Tag::Boolean.class(), Class::Universal);
655 assert_eq!(Tag::Integer.class(), Class::Universal);
656 assert_eq!(Tag::BitString.class(), Class::Universal);
657 assert_eq!(Tag::OctetString.class(), Class::Universal);
658 assert_eq!(Tag::Null.class(), Class::Universal);
659 assert_eq!(Tag::ObjectIdentifier.class(), Class::Universal);
660 assert_eq!(Tag::Real.class(), Class::Universal);
661 assert_eq!(Tag::Enumerated.class(), Class::Universal);
662 assert_eq!(Tag::Utf8String.class(), Class::Universal);
663 assert_eq!(Tag::RelativeOid.class(), Class::Universal);
664 assert_eq!(Tag::Set.class(), Class::Universal);
665 assert_eq!(Tag::NumericString.class(), Class::Universal);
666 assert_eq!(Tag::PrintableString.class(), Class::Universal);
667 assert_eq!(Tag::TeletexString.class(), Class::Universal);
668 assert_eq!(Tag::VideotexString.class(), Class::Universal);
669 assert_eq!(Tag::Ia5String.class(), Class::Universal);
670 assert_eq!(Tag::UtcTime.class(), Class::Universal);
671 assert_eq!(Tag::GeneralizedTime.class(), Class::Universal);
672 assert_eq!(Tag::Sequence.class(), Class::Universal);
673
674 for num in 0..=30 {
675 for &constructed in &[false, true] {
676 let number = TagNumber(num);
677
678 assert_eq!(
679 Tag::Application {
680 constructed,
681 number
682 }
683 .class(),
684 Class::Application
685 );
686
687 assert_eq!(
688 Tag::ContextSpecific {
689 constructed,
690 number
691 }
692 .class(),
693 Class::ContextSpecific
694 );
695
696 assert_eq!(
697 Tag::Private {
698 constructed,
699 number
700 }
701 .class(),
702 Class::Private
703 );
704 }
705 }
706 }
707
708 #[test]
709 fn decoding() {
710 assert_eq!(
711 Tag::Application {
712 constructed: false,
713 number: TagNumber(0x4001)
714 },
715 Tag::from_der(&hex!("5F818001")).expect("bits 7 to 1 are zero")
716 );
717 assert_eq!(
718 Tag::ContextSpecific {
719 constructed: false,
720 number: TagNumber(0x200001)
721 },
722 Tag::from_der(&hex!("9F81808001")).expect("bits 7 to 1 are zero two times")
723 );
724 assert_eq!(
725 Tag::Private {
726 constructed: false,
727 number: TagNumber(u32::MAX)
728 },
729 Tag::from_der(&hex!("DF8FFFFFFF7F")).expect("private tag 2^32-1")
730 );
731 assert_eq!(
732 ErrorKind::TagNumberInvalid,
733 Tag::from_der(&hex!("FF03"))
734 .expect_err("valid tag number but must be in short form")
735 .kind()
736 );
737 assert_eq!(
738 ErrorKind::TagNumberInvalid,
739 Tag::from_der(&hex!("1FFF"))
740 .expect_err("universal tag with long form")
741 .kind()
742 );
743 assert_eq!(
744 ErrorKind::TagNumberInvalid,
745 Tag::from_der(&hex!("5F8020"))
746 .expect_err("leading zeros in long form")
747 .kind()
748 );
749 assert_eq!(
750 ErrorKind::TagNumberInvalid,
751 Tag::from_der(&hex!("DF9F8F8F8F0F"))
752 .expect_err("tag number larger than 32 bits")
753 .kind()
754 );
755 assert_eq!(
756 ErrorKind::Incomplete {
757 expected_len: Length::new(3),
758 actual_len: Length::new(2)
759 },
760 Tag::from_der(&hex!("5F9E"))
761 .expect_err("incomplete tag in long form")
762 .kind()
763 );
764 }
765
766 #[test]
767 fn tag_order() {
768 assert_eq!(Tag::Boolean.der_cmp(&Tag::Integer), Ok(Ordering::Less));
776 assert_eq!(Tag::Integer.der_cmp(&Tag::Null), Ok(Ordering::Less));
777 assert_eq!(Tag::Null.der_cmp(&Tag::Sequence), Ok(Ordering::Less));
778 assert_eq!(
780 Tag::Sequence.der_cmp(&Tag::Ia5String),
781 Ok(Ordering::Greater)
782 );
783 assert_eq!(Tag::Ia5String.der_cmp(&Tag::BmpString), Ok(Ordering::Less));
784
785 assert_eq!(
787 Tag::BmpString.der_cmp(&Tag::Application {
788 constructed: true,
789 number: TagNumber(0)
790 }),
791 Ok(Ordering::Less)
792 );
793 assert_eq!(
795 Tag::Application {
796 constructed: true,
797 number: TagNumber(0)
798 }
799 .der_cmp(&Tag::Application {
800 constructed: true,
801 number: TagNumber(1)
802 }),
803 Ok(Ordering::Less)
804 );
805
806 assert_eq!(
808 Tag::Application {
809 constructed: true,
810 number: TagNumber(1)
811 }
812 .der_cmp(&Tag::Application {
813 constructed: false,
814 number: TagNumber(2)
815 }),
816 Ok(Ordering::Greater)
817 );
818 assert_eq!(
820 Tag::PrintableString.der_cmp(&Tag::Sequence),
821 Ok(Ordering::Less)
822 );
823 assert_eq!(
825 Tag::ContextSpecific {
826 constructed: false,
827 number: TagNumber(16383)
828 }
829 .der_cmp(&Tag::ContextSpecific {
830 constructed: false,
831 number: TagNumber(16384)
832 }),
833 Ok(Ordering::Greater)
834 );
835
836 assert_eq!(
838 Tag::Application {
839 constructed: false,
840 number: TagNumber(2)
841 }
842 .der_cmp(&Tag::Application {
843 constructed: true,
844 number: TagNumber(2)
845 }),
846 Ok(Ordering::Less)
847 );
848
849 assert_eq!(
851 Tag::Application {
852 constructed: true,
853 number: TagNumber(2)
854 }
855 .der_cmp(&Tag::ContextSpecific {
856 constructed: true,
857 number: TagNumber(0)
858 }),
859 Ok(Ordering::Less)
860 );
861
862 assert_eq!(
864 Tag::ContextSpecific {
865 constructed: true,
866 number: TagNumber(10)
867 }
868 .der_cmp(&Tag::Private {
869 constructed: true,
870 number: TagNumber(0)
871 }),
872 Ok(Ordering::Less)
873 );
874 }
875
876 #[test]
877 fn peek() {
878 let reader = SliceReader::new(&[0x02]).expect("valid reader");
879 assert_eq!(reader.position(), Length::ZERO);
880 assert_eq!(Tag::peek(&reader).expect("peeked tag"), Tag::Integer);
881 assert_eq!(reader.position(), Length::ZERO); }
883
884 #[test]
885 fn peek_long_tags() {
886 let reader = SliceReader::new(&hex!("DF8FFFFFFF7F")).expect("valid reader");
887 let tag = Tag::peek(&reader).expect("peeked tag");
888 assert!(!tag.is_context_specific());
889 assert!(!tag.is_application());
890 assert!(tag.is_private());
891 assert_eq!(
892 tag,
893 Tag::Private {
894 constructed: false,
895 number: TagNumber(u32::MAX)
896 }
897 );
898 }
899
900 #[test]
901 fn negative_peek_long_tags() {
902 let reader = SliceReader::new(&hex!("DF8FFFFFFFFF")).expect("valid reader");
903 assert_eq!(
904 Tag::peek(&reader)
905 .expect_err("tag ends in 0xFF, so 7+ bytes needed")
906 .kind(),
907 ErrorKind::TagNumberInvalid,
908 );
909 }
910}