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    /// Compare the identifier octets as octet strings (X.690 11.6: `SET OF` components are
568    /// ordered by their encodings). The constructed bit is part of the first octet, so it
569    /// orders before the tag number within a class.
570    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        // T-REC-X.680-202102
769        // 8.6 The canonical order for tags is based on the outermost tag of each type and is defined as follows:
770        // a) those elements or alternatives with universal class tags shall appear first, followed by those with
771        // application class tags, followed by those with context-specific tags, followed by those with private class
772        // tags;
773        // b) within each class of tags, the elements or alternatives shall appear in ascending order of their tag
774        // numbers.
775        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        // SEQUENCE is constructed: 0x30 > 0x16
779        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        // universal class, then application class
786        assert_eq!(
787            Tag::BmpString.der_cmp(&Tag::Application {
788                constructed: true,
789                number: TagNumber(0)
790            }),
791            Ok(Ordering::Less)
792        );
793        // ascending tag numbers
794        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        // the constructed bit (0x20) is compared before the tag number: 0x42 < 0x61
807        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        // PrintableString (0x13) before SEQUENCE (0x30)
819        assert_eq!(
820            Tag::PrintableString.der_cmp(&Tag::Sequence),
821            Ok(Ordering::Less)
822        );
823        // long form: [16383] = 9F FF 7F, [16384] = 9F 81 80 00
824        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        // for same tag numbers, order by constructed bit
837        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        // application class is before context-specific class
850        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        // context-specific class is before private class
863        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); // Position unchanged
882    }
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}