Skip to main content

der/
tag.rs

1//! ASN.1 tags.
2#![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
16/// Indicator bit for constructed form encoding (i.e. vs primitive form)
17const CONSTRUCTED_FLAG: u8 = 0b100000;
18
19/// Types which have a constant ASN.1 [`Tag`].
20///
21/// ## Example
22/// ```
23/// use der::{FixedTag, Tag};
24///
25/// struct MyOctetString;
26///
27/// impl FixedTag for MyOctetString {
28///     const TAG: Tag = Tag::OctetString;
29/// }
30/// ```
31pub trait FixedTag {
32    /// ASN.1 tag
33    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/// Types which have an ASN.1 [`Tag`].
46///
47/// ## Example
48/// ```
49/// use der::{Tag, Tagged};
50///
51/// /// Struct, which Tag depends on data
52/// struct MyOctetOrBitString(bool);
53///
54/// impl Tagged for MyOctetOrBitString {
55///     fn tag(&self) -> Tag {
56///         if self.0 {
57///             Tag::OctetString
58///         } else {
59///             Tag::BitString
60///         }
61///     }
62/// }
63/// ```
64#[diagnostic::on_unimplemented(note = "Consider adding impl of `FixedTag` to `{Self}`")]
65pub trait Tagged {
66    /// Get the ASN.1 tag that this type is encoded with.
67    fn tag(&self) -> Tag;
68}
69
70/// Types which are [`FixedTag`] always have a known [`Tag`] type.
71impl<T: FixedTag + ?Sized> Tagged for T {
72    fn tag(&self) -> Tag {
73        T::TAG
74    }
75}
76
77/// Types which have a constant ASN.1 constructed bit.
78///
79/// Auto-implemented on all types that implement [`FixedTag`].
80///
81/// ## Example
82/// ```
83/// use der::{asn1::ContextSpecific, DecodeValue, ErrorKind, Header, IsConstructed, Length, Reader, Result, SliceReader, TagNumber};
84///
85/// /// Type, which can be decoded for example as `CONTEXT-SPECIFIC [0] (primitive)`
86/// struct MyPrimitiveYear(u16);
87///
88/// impl IsConstructed for MyPrimitiveYear {
89///     const CONSTRUCTED: bool = false;
90/// }
91///
92/// impl<'a> DecodeValue<'a> for MyPrimitiveYear {
93///     type Error = der::Error;
94///
95///     fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
96///         let slice = reader.read_slice(Length::new(4))?;
97///         let year = std::str::from_utf8(slice).ok().and_then(|s| s.parse::<u16>().ok());
98///         if let Some(year) = year {
99///             Ok(Self(year))
100///         } else {
101///             Err(reader.error(ErrorKind::DateTime))
102///         }
103///     }
104/// }
105///
106/// let mut reader = SliceReader::new(b"\x80\x041670".as_slice()).unwrap();
107///
108/// let decoded = ContextSpecific::<MyPrimitiveYear>::decode_implicit(&mut reader, TagNumber(0)).unwrap().unwrap();
109///
110/// assert_eq!(decoded.value.0, 1670);
111/// ```
112#[diagnostic::on_unimplemented(note = "Consider adding impl of `FixedTag` to `{Self}`")]
113pub trait IsConstructed {
114    /// ASN.1 constructed bit
115    const CONSTRUCTED: bool;
116}
117
118/// Types which are [`FixedTag`] always known if they are constructed (or primitive).
119impl<T: FixedTag + ?Sized> IsConstructed for T {
120    const CONSTRUCTED: bool = T::TAG.is_constructed();
121}
122
123/// ASN.1 tags.
124///
125/// Tags are the leading identifier octet of the Tag-Length-Value encoding
126/// used by ASN.1 DER and identify the type of the subsequent value.
127///
128/// They are described in X.690 Section 8.1.2: Identifier octets, and
129/// structured as follows:
130///
131/// ```text
132/// | Class | P/C | Tag Number |
133/// ```
134///
135/// - Bits 8/7: [`Class`]
136/// - Bit 6: primitive (0) or constructed (1)
137/// - Bits 5-1: tag number
138///
139/// ## Examples
140/// ```
141/// use der::{Decode, Tag, SliceReader};
142///
143/// let mut reader = SliceReader::new(&[0x30]).unwrap();
144/// let tag = Tag::decode(&mut reader).expect("valid tag");
145///
146/// assert_eq!(tag, Tag::Sequence);
147/// ```
148///
149/// Invalid tags produce an error:
150/// ```
151/// use der::{Decode, Tag};
152///
153/// // 0x21 is an invalid CONSTRUCTED BOOLEAN
154/// Tag::from_der(&[0x21]).expect_err("invalid tag");
155/// ```
156///
157/// `APPLICATION`, `CONTEXT-SPECIFIC` and `PRIVATE` tags are supported:
158/// ```
159/// use der::{Decode, Tag, TagNumber};
160///
161/// // `APPLICATION [33] (constructed)`
162/// let tag = Tag::from_der(&[0x7F, 0x21]).expect("valid tag");
163///
164/// assert_eq!(tag, Tag::Application { constructed: true, number: TagNumber(33) });
165/// ```
166#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
167#[derive(Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
168#[non_exhaustive]
169pub enum Tag {
170    /// `BOOLEAN` tag: `1`.
171    Boolean,
172
173    /// `INTEGER` tag: `2`.
174    Integer,
175
176    /// `BIT STRING` tag: `3`.
177    BitString,
178
179    /// `OCTET STRING` tag: `4`.
180    OctetString,
181
182    /// `NULL` tag: `5`.
183    Null,
184
185    /// `OBJECT IDENTIFIER` tag: `6`.
186    ObjectIdentifier,
187
188    /// `REAL` tag: `9`.
189    Real,
190
191    /// `ENUMERATED` tag: `10`.
192    Enumerated,
193
194    /// `UTF8String` tag: `12`.
195    Utf8String,
196
197    /// `RELATIVE OID` tag: `13`.
198    RelativeOid,
199
200    /// `SEQUENCE` tag: `16`.
201    Sequence,
202
203    /// `SET` and `SET OF` tag: `17`.
204    Set,
205
206    /// `NumericString` tag: `18`.
207    NumericString,
208
209    /// `PrintableString` tag: `19`.
210    PrintableString,
211
212    /// `TeletexString` tag: `20`.
213    TeletexString,
214
215    /// `VideotexString` tag: `21`.
216    VideotexString,
217
218    /// `IA5String` tag: `22`.
219    Ia5String,
220
221    /// `UTCTime` tag: `23`.
222    UtcTime,
223
224    /// `GeneralizedTime` tag: `24`.
225    GeneralizedTime,
226
227    /// `VisibleString` tag: `26`.
228    VisibleString,
229
230    /// `GeneralString` tag: `27`.
231    GeneralString,
232
233    /// `BMPString` tag: `30`.
234    BmpString,
235
236    /// Application tag.
237    Application {
238        /// Is this tag constructed? (vs primitive).
239        constructed: bool,
240
241        /// Tag number.
242        number: TagNumber,
243    },
244
245    /// Context-specific tag.
246    ContextSpecific {
247        /// Is this tag constructed? (vs primitive).
248        constructed: bool,
249
250        /// Tag number.
251        number: TagNumber,
252    },
253
254    /// Private tag number.
255    Private {
256        /// Is this tag constructed? (vs primitive).
257        constructed: bool,
258
259        /// Tag number.
260        number: TagNumber,
261    },
262}
263
264impl Tag {
265    /// Maximum number of octets in a DER encoding of a [`Tag`] using the
266    /// rules implemented by this crate.
267    pub(crate) const MAX_SIZE: usize = 6;
268
269    /// Decode a [`Tag`] in addition to returning the value of the constructed bit.
270    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, // constructed
300            0x31 => Tag::Set,      // constructed
301            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            // universal tag in long form
326            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    /// Peek at the next byte in the reader and attempt to decode it as a [`Tag`] value.
334    ///
335    /// Does not modify the reader's state.
336    ///
337    /// # Errors
338    /// If a decoding error occurred.
339    pub fn peek<'a>(reader: &impl Reader<'a>) -> Result<Self> {
340        Self::decode(&mut reader.clone())
341    }
342
343    /// Returns true if given context-specific (or any given class) tag number matches the peeked tag.
344    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    /// Assert that this [`Tag`] matches the provided expected tag.
358    ///
359    /// # Errors
360    /// Returns an [`Error`] with [`ErrorKind::TagUnexpected`] on mismatch.
361    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    /// Get the [`Class`] that corresponds to this [`Tag`].
370    #[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    /// Get the [`TagNumber`] for this tag.
381    #[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    /// Does this tag represent a constructed (as opposed to primitive) field?
413    #[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    /// Is this an application tag?
425    #[must_use]
426    pub const fn is_application(self) -> bool {
427        matches!(self.class(), Class::Application)
428    }
429
430    /// Is this a context-specific tag?
431    #[must_use]
432    pub const fn is_context_specific(self) -> bool {
433        matches!(self.class(), Class::ContextSpecific)
434    }
435
436    /// Is this a private tag?
437    #[must_use]
438    pub const fn is_private(self) -> bool {
439        matches!(self.class(), Class::Private)
440    }
441
442    /// Is this a universal tag?
443    #[must_use]
444    pub const fn is_universal(self) -> bool {
445        matches!(self.class(), Class::Universal)
446    }
447
448    /// Create an [`Error`] for an invalid [`Length`].
449    #[must_use]
450    pub fn length_error(self) -> ErrorKind {
451        ErrorKind::Length { tag: self }
452    }
453
454    /// Create an [`Error`] for an non-canonical value with the ASN.1 type
455    /// identified by this tag.
456    #[must_use]
457    pub fn non_canonical_error(self) -> ErrorKind {
458        ErrorKind::Noncanonical { tag: self }
459    }
460
461    /// Create an [`Error`] because the current tag was unexpected, with an
462    /// optional expected tag.
463    #[must_use]
464    pub fn unexpected_error(self, expected: Option<Self>) -> ErrorKind {
465        ErrorKind::TagUnexpected {
466            expected,
467            actual: self,
468        }
469    }
470
471    /// Create an [`Error`] for an invalid value with the ASN.1 type identified
472    /// by this tag.
473    #[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            // 8.1.2.4.2c says "bits 7 to 1 of the first subsequent octet shall not all be zero"
509            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    // missing terminator byte
520    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> {
568        Ok((self.class().cmp(&other.class()))
569            .then_with(|| self.number().cmp(&other.number()))
570            .then_with(|| self.is_constructed().cmp(&other.is_constructed())))
571    }
572}
573
574impl fmt::Display for Tag {
575    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
576        const FIELD_TYPE: [&str; 2] = ["primitive", "constructed"];
577
578        match *self {
579            Tag::Boolean => f.write_str("BOOLEAN"),
580            Tag::Integer => f.write_str("INTEGER"),
581            Tag::BitString => f.write_str("BIT STRING"),
582            Tag::OctetString => f.write_str("OCTET STRING"),
583            Tag::Null => f.write_str("NULL"),
584            Tag::ObjectIdentifier => f.write_str("OBJECT IDENTIFIER"),
585            Tag::Real => f.write_str("REAL"),
586            Tag::Enumerated => f.write_str("ENUMERATED"),
587            Tag::Utf8String => f.write_str("UTF8String"),
588            Tag::RelativeOid => f.write_str("RELATIVE OID"),
589            Tag::Set => f.write_str("SET"),
590            Tag::NumericString => f.write_str("NumericString"),
591            Tag::PrintableString => f.write_str("PrintableString"),
592            Tag::TeletexString => f.write_str("TeletexString"),
593            Tag::VideotexString => f.write_str("VideotexString"),
594            Tag::Ia5String => f.write_str("IA5String"),
595            Tag::UtcTime => f.write_str("UTCTime"),
596            Tag::GeneralizedTime => f.write_str("GeneralizedTime"),
597            Tag::VisibleString => f.write_str("VisibleString"),
598            Tag::GeneralString => f.write_str("GeneralString"),
599            Tag::BmpString => f.write_str("BMPString"),
600            Tag::Sequence => f.write_str("SEQUENCE"),
601            Tag::Application {
602                constructed,
603                number,
604            } => write!(
605                f,
606                "APPLICATION [{}] ({})",
607                number,
608                FIELD_TYPE[usize::from(constructed)]
609            ),
610            Tag::ContextSpecific {
611                constructed,
612                number,
613            } => write!(
614                f,
615                "CONTEXT-SPECIFIC [{}] ({})",
616                number,
617                FIELD_TYPE[usize::from(constructed)]
618            ),
619            Tag::Private {
620                constructed,
621                number,
622            } => write!(
623                f,
624                "PRIVATE [{}] ({})",
625                number,
626                FIELD_TYPE[usize::from(constructed)]
627            ),
628        }
629    }
630}
631
632impl fmt::Debug for Tag {
633    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
634        write!(f, "Tag(0x{:02x}: {})", self.number().value(), self)
635    }
636}
637
638#[cfg(test)]
639mod tests {
640    use core::cmp::Ordering;
641
642    use hex_literal::hex;
643
644    use super::{Class, Tag, TagNumber};
645    use crate::{Decode, DerOrd, ErrorKind, Length, Reader, SliceReader};
646
647    #[test]
648    fn tag_class() {
649        assert_eq!(Tag::Boolean.class(), Class::Universal);
650        assert_eq!(Tag::Integer.class(), Class::Universal);
651        assert_eq!(Tag::BitString.class(), Class::Universal);
652        assert_eq!(Tag::OctetString.class(), Class::Universal);
653        assert_eq!(Tag::Null.class(), Class::Universal);
654        assert_eq!(Tag::ObjectIdentifier.class(), Class::Universal);
655        assert_eq!(Tag::Real.class(), Class::Universal);
656        assert_eq!(Tag::Enumerated.class(), Class::Universal);
657        assert_eq!(Tag::Utf8String.class(), Class::Universal);
658        assert_eq!(Tag::RelativeOid.class(), Class::Universal);
659        assert_eq!(Tag::Set.class(), Class::Universal);
660        assert_eq!(Tag::NumericString.class(), Class::Universal);
661        assert_eq!(Tag::PrintableString.class(), Class::Universal);
662        assert_eq!(Tag::TeletexString.class(), Class::Universal);
663        assert_eq!(Tag::VideotexString.class(), Class::Universal);
664        assert_eq!(Tag::Ia5String.class(), Class::Universal);
665        assert_eq!(Tag::UtcTime.class(), Class::Universal);
666        assert_eq!(Tag::GeneralizedTime.class(), Class::Universal);
667        assert_eq!(Tag::Sequence.class(), Class::Universal);
668
669        for num in 0..=30 {
670            for &constructed in &[false, true] {
671                let number = TagNumber(num);
672
673                assert_eq!(
674                    Tag::Application {
675                        constructed,
676                        number
677                    }
678                    .class(),
679                    Class::Application
680                );
681
682                assert_eq!(
683                    Tag::ContextSpecific {
684                        constructed,
685                        number
686                    }
687                    .class(),
688                    Class::ContextSpecific
689                );
690
691                assert_eq!(
692                    Tag::Private {
693                        constructed,
694                        number
695                    }
696                    .class(),
697                    Class::Private
698                );
699            }
700        }
701    }
702
703    #[test]
704    fn decoding() {
705        assert_eq!(
706            Tag::Application {
707                constructed: false,
708                number: TagNumber(0x4001)
709            },
710            Tag::from_der(&hex!("5F818001")).expect("bits 7 to 1 are zero")
711        );
712        assert_eq!(
713            Tag::ContextSpecific {
714                constructed: false,
715                number: TagNumber(0x200001)
716            },
717            Tag::from_der(&hex!("9F81808001")).expect("bits 7 to 1 are zero two times")
718        );
719        assert_eq!(
720            Tag::Private {
721                constructed: false,
722                number: TagNumber(u32::MAX)
723            },
724            Tag::from_der(&hex!("DF8FFFFFFF7F")).expect("private tag 2^32-1")
725        );
726        assert_eq!(
727            ErrorKind::TagNumberInvalid,
728            Tag::from_der(&hex!("FF03"))
729                .expect_err("valid tag number but must be in short form")
730                .kind()
731        );
732        assert_eq!(
733            ErrorKind::TagNumberInvalid,
734            Tag::from_der(&hex!("1FFF"))
735                .expect_err("universal tag with long form")
736                .kind()
737        );
738        assert_eq!(
739            ErrorKind::TagNumberInvalid,
740            Tag::from_der(&hex!("5F8020"))
741                .expect_err("leading zeros in long form")
742                .kind()
743        );
744        assert_eq!(
745            ErrorKind::TagNumberInvalid,
746            Tag::from_der(&hex!("DF9F8F8F8F0F"))
747                .expect_err("tag number larger than 32 bits")
748                .kind()
749        );
750        assert_eq!(
751            ErrorKind::Incomplete {
752                expected_len: Length::new(3),
753                actual_len: Length::new(2)
754            },
755            Tag::from_der(&hex!("5F9E"))
756                .expect_err("incomplete tag in long form")
757                .kind()
758        );
759    }
760
761    #[test]
762    fn tag_order() {
763        // T-REC-X.680-202102
764        // 8.6 The canonical order for tags is based on the outermost tag of each type and is defined as follows:
765        // a) those elements or alternatives with universal class tags shall appear first, followed by those with
766        // application class tags, followed by those with context-specific tags, followed by those with private class
767        // tags;
768        // b) within each class of tags, the elements or alternatives shall appear in ascending order of their tag
769        // numbers.
770        assert_eq!(Tag::Boolean.der_cmp(&Tag::Integer), Ok(Ordering::Less));
771        assert_eq!(Tag::Integer.der_cmp(&Tag::Null), Ok(Ordering::Less));
772        assert_eq!(Tag::Null.der_cmp(&Tag::Sequence), Ok(Ordering::Less));
773        assert_eq!(Tag::Sequence.der_cmp(&Tag::Ia5String), Ok(Ordering::Less));
774        assert_eq!(Tag::Ia5String.der_cmp(&Tag::BmpString), Ok(Ordering::Less));
775
776        // universal class, then application class
777        assert_eq!(
778            Tag::BmpString.der_cmp(&Tag::Application {
779                constructed: true,
780                number: TagNumber(0)
781            }),
782            Ok(Ordering::Less)
783        );
784        // ascending tag numbers
785        assert_eq!(
786            Tag::Application {
787                constructed: true,
788                number: TagNumber(0)
789            }
790            .der_cmp(&Tag::Application {
791                constructed: true,
792                number: TagNumber(1)
793            }),
794            Ok(Ordering::Less)
795        );
796
797        // ignore constructed bit
798        assert_eq!(
799            Tag::Application {
800                constructed: true,
801                number: TagNumber(1)
802            }
803            .der_cmp(&Tag::Application {
804                constructed: false,
805                number: TagNumber(2)
806            }),
807            Ok(Ordering::Less)
808        );
809
810        // for same tag numbers, order by constructed bit
811        assert_eq!(
812            Tag::Application {
813                constructed: false,
814                number: TagNumber(2)
815            }
816            .der_cmp(&Tag::Application {
817                constructed: true,
818                number: TagNumber(2)
819            }),
820            Ok(Ordering::Less)
821        );
822
823        // application class is before context-specific class
824        assert_eq!(
825            Tag::Application {
826                constructed: true,
827                number: TagNumber(2)
828            }
829            .der_cmp(&Tag::ContextSpecific {
830                constructed: true,
831                number: TagNumber(0)
832            }),
833            Ok(Ordering::Less)
834        );
835
836        // context-specific class is before private class
837        assert_eq!(
838            Tag::ContextSpecific {
839                constructed: true,
840                number: TagNumber(10)
841            }
842            .der_cmp(&Tag::Private {
843                constructed: true,
844                number: TagNumber(0)
845            }),
846            Ok(Ordering::Less)
847        );
848    }
849
850    #[test]
851    fn peek() {
852        let reader = SliceReader::new(&[0x02]).expect("valid reader");
853        assert_eq!(reader.position(), Length::ZERO);
854        assert_eq!(Tag::peek(&reader).expect("peeked tag"), Tag::Integer);
855        assert_eq!(reader.position(), Length::ZERO); // Position unchanged
856    }
857
858    #[test]
859    fn peek_long_tags() {
860        let reader = SliceReader::new(&hex!("DF8FFFFFFF7F")).expect("valid reader");
861        let tag = Tag::peek(&reader).expect("peeked tag");
862        assert!(!tag.is_context_specific());
863        assert!(!tag.is_application());
864        assert!(tag.is_private());
865        assert_eq!(
866            tag,
867            Tag::Private {
868                constructed: false,
869                number: TagNumber(u32::MAX)
870            }
871        );
872    }
873
874    #[test]
875    fn negative_peek_long_tags() {
876        let reader = SliceReader::new(&hex!("DF8FFFFFFFFF")).expect("valid reader");
877        assert_eq!(
878            Tag::peek(&reader)
879                .expect_err("tag ends in 0xFF, so 7+ bytes needed")
880                .kind(),
881            ErrorKind::TagNumberInvalid,
882        );
883    }
884}