der/
tag.rs

1//! ASN.1 tags.
2#![cfg_attr(feature = "arbitrary", allow(clippy::integer_arithmetic))]
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/// Indicator bit for constructed form encoding (i.e. vs primitive form)
14const CONSTRUCTED_FLAG: u8 = 0b100000;
15
16/// Types which have a constant ASN.1 [`Tag`].
17pub trait FixedTag {
18    /// ASN.1 tag
19    const TAG: Tag;
20}
21
22/// Types which have an ASN.1 [`Tag`].
23pub trait Tagged {
24    /// Get the ASN.1 tag that this type is encoded with.
25    fn tag(&self) -> Tag;
26}
27
28/// Types which are [`FixedTag`] always have a known [`Tag`] type.
29impl<T: FixedTag> Tagged for T {
30    fn tag(&self) -> Tag {
31        T::TAG
32    }
33}
34
35/// ASN.1 tags.
36///
37/// Tags are the leading identifier octet of the Tag-Length-Value encoding
38/// used by ASN.1 DER and identify the type of the subsequent value.
39///
40/// They are described in X.690 Section 8.1.2: Identifier octets, and
41/// structured as follows:
42///
43/// ```text
44/// | Class | P/C | Tag Number |
45/// ```
46///
47/// - Bits 8/7: [`Class`]
48/// - Bit 6: primitive (0) or constructed (1)
49/// - Bits 5-1: tag number
50#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
51#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
52#[non_exhaustive]
53pub enum Tag {
54    /// `BOOLEAN` tag: `1`.
55    Boolean,
56
57    /// `INTEGER` tag: `2`.
58    Integer,
59
60    /// `BIT STRING` tag: `3`.
61    BitString,
62
63    /// `OCTET STRING` tag: `4`.
64    OctetString,
65
66    /// `NULL` tag: `5`.
67    Null,
68
69    /// `OBJECT IDENTIFIER` tag: `6`.
70    ObjectIdentifier,
71
72    /// `REAL` tag: `9`.
73    Real,
74
75    /// `ENUMERATED` tag: `10`.
76    Enumerated,
77
78    /// `UTF8String` tag: `12`.
79    Utf8String,
80
81    /// `SEQUENCE` tag: `16`.
82    Sequence,
83
84    /// `SET` and `SET OF` tag: `17`.
85    Set,
86
87    /// `NumericString` tag: `18`.
88    NumericString,
89
90    /// `PrintableString` tag: `19`.
91    PrintableString,
92
93    /// `TeletexString` tag: `20`.
94    TeletexString,
95
96    /// `VideotexString` tag: `21`.
97    VideotexString,
98
99    /// `IA5String` tag: `22`.
100    Ia5String,
101
102    /// `UTCTime` tag: `23`.
103    UtcTime,
104
105    /// `GeneralizedTime` tag: `24`.
106    GeneralizedTime,
107
108    /// `VisibleString` tag: `26`.
109    VisibleString,
110
111    /// `BMPString` tag: `30`.
112    BmpString,
113
114    /// Application tag.
115    Application {
116        /// Is this tag constructed? (vs primitive).
117        constructed: bool,
118
119        /// Tag number.
120        number: TagNumber,
121    },
122
123    /// Context-specific tag.
124    ContextSpecific {
125        /// Is this tag constructed? (vs primitive).
126        constructed: bool,
127
128        /// Tag number.
129        number: TagNumber,
130    },
131
132    /// Private tag number.
133    Private {
134        /// Is this tag constructed? (vs primitive).
135        constructed: bool,
136
137        /// Tag number.
138        number: TagNumber,
139    },
140}
141
142impl Tag {
143    /// Assert that this [`Tag`] matches the provided expected tag.
144    ///
145    /// On mismatch, returns an [`Error`] with [`ErrorKind::TagUnexpected`].
146    pub fn assert_eq(self, expected: Tag) -> Result<Tag> {
147        if self == expected {
148            Ok(self)
149        } else {
150            Err(self.unexpected_error(Some(expected)))
151        }
152    }
153
154    /// Get the [`Class`] that corresponds to this [`Tag`].
155    pub fn class(self) -> Class {
156        match self {
157            Tag::Application { .. } => Class::Application,
158            Tag::ContextSpecific { .. } => Class::ContextSpecific,
159            Tag::Private { .. } => Class::Private,
160            _ => Class::Universal,
161        }
162    }
163
164    /// Get the [`TagNumber`] (lower 6-bits) for this tag.
165    pub fn number(self) -> TagNumber {
166        TagNumber(self.octet() & TagNumber::MASK)
167    }
168
169    /// Does this tag represent a constructed (as opposed to primitive) field?
170    pub fn is_constructed(self) -> bool {
171        self.octet() & CONSTRUCTED_FLAG != 0
172    }
173
174    /// Is this an application tag?
175    pub fn is_application(self) -> bool {
176        self.class() == Class::Application
177    }
178
179    /// Is this a context-specific tag?
180    pub fn is_context_specific(self) -> bool {
181        self.class() == Class::ContextSpecific
182    }
183
184    /// Is this a private tag?
185    pub fn is_private(self) -> bool {
186        self.class() == Class::Private
187    }
188
189    /// Is this a universal tag?
190    pub fn is_universal(self) -> bool {
191        self.class() == Class::Universal
192    }
193
194    /// Get the octet encoding for this [`Tag`].
195    pub fn octet(self) -> u8 {
196        match self {
197            Tag::Boolean => 0x01,
198            Tag::Integer => 0x02,
199            Tag::BitString => 0x03,
200            Tag::OctetString => 0x04,
201            Tag::Null => 0x05,
202            Tag::ObjectIdentifier => 0x06,
203            Tag::Real => 0x09,
204            Tag::Enumerated => 0x0A,
205            Tag::Utf8String => 0x0C,
206            Tag::Sequence => 0x10 | CONSTRUCTED_FLAG,
207            Tag::Set => 0x11 | CONSTRUCTED_FLAG,
208            Tag::NumericString => 0x12,
209            Tag::PrintableString => 0x13,
210            Tag::TeletexString => 0x14,
211            Tag::VideotexString => 0x15,
212            Tag::Ia5String => 0x16,
213            Tag::UtcTime => 0x17,
214            Tag::GeneralizedTime => 0x18,
215            Tag::VisibleString => 0x1A,
216            Tag::BmpString => 0x1E,
217            Tag::Application {
218                constructed,
219                number,
220            }
221            | Tag::ContextSpecific {
222                constructed,
223                number,
224            }
225            | Tag::Private {
226                constructed,
227                number,
228            } => self.class().octet(constructed, number),
229        }
230    }
231
232    /// Create an [`Error`] for an invalid [`Length`].
233    pub fn length_error(self) -> Error {
234        ErrorKind::Length { tag: self }.into()
235    }
236
237    /// Create an [`Error`] for an non-canonical value with the ASN.1 type
238    /// identified by this tag.
239    pub fn non_canonical_error(self) -> Error {
240        ErrorKind::Noncanonical { tag: self }.into()
241    }
242
243    /// Create an [`Error`] because the current tag was unexpected, with an
244    /// optional expected tag.
245    pub fn unexpected_error(self, expected: Option<Self>) -> Error {
246        ErrorKind::TagUnexpected {
247            expected,
248            actual: self,
249        }
250        .into()
251    }
252
253    /// Create an [`Error`] for an invalid value with the ASN.1 type identified
254    /// by this tag.
255    pub fn value_error(self) -> Error {
256        ErrorKind::Value { tag: self }.into()
257    }
258}
259
260impl TryFrom<u8> for Tag {
261    type Error = Error;
262
263    fn try_from(byte: u8) -> Result<Tag> {
264        let constructed = byte & CONSTRUCTED_FLAG != 0;
265        let number = TagNumber::try_from(byte & TagNumber::MASK)?;
266
267        match byte {
268            0x01 => Ok(Tag::Boolean),
269            0x02 => Ok(Tag::Integer),
270            0x03 => Ok(Tag::BitString),
271            0x04 => Ok(Tag::OctetString),
272            0x05 => Ok(Tag::Null),
273            0x06 => Ok(Tag::ObjectIdentifier),
274            0x09 => Ok(Tag::Real),
275            0x0A => Ok(Tag::Enumerated),
276            0x0C => Ok(Tag::Utf8String),
277            0x12 => Ok(Tag::NumericString),
278            0x13 => Ok(Tag::PrintableString),
279            0x14 => Ok(Tag::TeletexString),
280            0x15 => Ok(Tag::VideotexString),
281            0x16 => Ok(Tag::Ia5String),
282            0x17 => Ok(Tag::UtcTime),
283            0x18 => Ok(Tag::GeneralizedTime),
284            0x1A => Ok(Tag::VisibleString),
285            0x1E => Ok(Tag::BmpString),
286            0x30 => Ok(Tag::Sequence), // constructed
287            0x31 => Ok(Tag::Set),      // constructed
288            0x40..=0x7E => Ok(Tag::Application {
289                constructed,
290                number,
291            }),
292            0x80..=0xBE => Ok(Tag::ContextSpecific {
293                constructed,
294                number,
295            }),
296            0xC0..=0xFE => Ok(Tag::Private {
297                constructed,
298                number,
299            }),
300            _ => Err(ErrorKind::TagUnknown { byte }.into()),
301        }
302    }
303}
304
305impl From<Tag> for u8 {
306    fn from(tag: Tag) -> u8 {
307        tag.octet()
308    }
309}
310
311impl From<&Tag> for u8 {
312    fn from(tag: &Tag) -> u8 {
313        u8::from(*tag)
314    }
315}
316
317impl<'a> Decode<'a> for Tag {
318    fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> {
319        reader.read_byte().and_then(Self::try_from)
320    }
321}
322
323impl Encode for Tag {
324    fn encoded_len(&self) -> Result<Length> {
325        Ok(Length::ONE)
326    }
327
328    fn encode(&self, writer: &mut impl Writer) -> Result<()> {
329        writer.write_byte(self.into())
330    }
331}
332
333impl DerOrd for Tag {
334    fn der_cmp(&self, other: &Self) -> Result<Ordering> {
335        Ok(self.octet().cmp(&other.octet()))
336    }
337}
338
339impl fmt::Display for Tag {
340    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
341        const FIELD_TYPE: [&str; 2] = ["primitive", "constructed"];
342
343        match *self {
344            Tag::Boolean => f.write_str("BOOLEAN"),
345            Tag::Integer => f.write_str("INTEGER"),
346            Tag::BitString => f.write_str("BIT STRING"),
347            Tag::OctetString => f.write_str("OCTET STRING"),
348            Tag::Null => f.write_str("NULL"),
349            Tag::ObjectIdentifier => f.write_str("OBJECT IDENTIFIER"),
350            Tag::Real => f.write_str("REAL"),
351            Tag::Enumerated => f.write_str("ENUMERATED"),
352            Tag::Utf8String => f.write_str("UTF8String"),
353            Tag::Set => f.write_str("SET"),
354            Tag::NumericString => f.write_str("NumericString"),
355            Tag::PrintableString => f.write_str("PrintableString"),
356            Tag::TeletexString => f.write_str("TeletexString"),
357            Tag::VideotexString => f.write_str("VideotexString"),
358            Tag::Ia5String => f.write_str("IA5String"),
359            Tag::UtcTime => f.write_str("UTCTime"),
360            Tag::GeneralizedTime => f.write_str("GeneralizedTime"),
361            Tag::VisibleString => f.write_str("VisibleString"),
362            Tag::BmpString => f.write_str("BMPString"),
363            Tag::Sequence => f.write_str("SEQUENCE"),
364            Tag::Application {
365                constructed,
366                number,
367            } => write!(
368                f,
369                "APPLICATION [{}] ({})",
370                number,
371                FIELD_TYPE[usize::from(constructed)]
372            ),
373            Tag::ContextSpecific {
374                constructed,
375                number,
376            } => write!(
377                f,
378                "CONTEXT-SPECIFIC [{}] ({})",
379                number,
380                FIELD_TYPE[usize::from(constructed)]
381            ),
382            Tag::Private {
383                constructed,
384                number,
385            } => write!(
386                f,
387                "PRIVATE [{}] ({})",
388                number,
389                FIELD_TYPE[usize::from(constructed)]
390            ),
391        }
392    }
393}
394
395impl fmt::Debug for Tag {
396    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
397        write!(f, "Tag(0x{:02x}: {})", u8::from(*self), self)
398    }
399}
400
401#[cfg(test)]
402mod tests {
403    use super::TagNumber;
404    use super::{Class, Tag};
405
406    #[test]
407    fn tag_class() {
408        assert_eq!(Tag::Boolean.class(), Class::Universal);
409        assert_eq!(Tag::Integer.class(), Class::Universal);
410        assert_eq!(Tag::BitString.class(), Class::Universal);
411        assert_eq!(Tag::OctetString.class(), Class::Universal);
412        assert_eq!(Tag::Null.class(), Class::Universal);
413        assert_eq!(Tag::ObjectIdentifier.class(), Class::Universal);
414        assert_eq!(Tag::Real.class(), Class::Universal);
415        assert_eq!(Tag::Enumerated.class(), Class::Universal);
416        assert_eq!(Tag::Utf8String.class(), Class::Universal);
417        assert_eq!(Tag::Set.class(), Class::Universal);
418        assert_eq!(Tag::NumericString.class(), Class::Universal);
419        assert_eq!(Tag::PrintableString.class(), Class::Universal);
420        assert_eq!(Tag::TeletexString.class(), Class::Universal);
421        assert_eq!(Tag::VideotexString.class(), Class::Universal);
422        assert_eq!(Tag::Ia5String.class(), Class::Universal);
423        assert_eq!(Tag::UtcTime.class(), Class::Universal);
424        assert_eq!(Tag::GeneralizedTime.class(), Class::Universal);
425        assert_eq!(Tag::Sequence.class(), Class::Universal);
426
427        for num in 0..=30 {
428            for &constructed in &[false, true] {
429                let number = TagNumber::new(num);
430
431                assert_eq!(
432                    Tag::Application {
433                        constructed,
434                        number
435                    }
436                    .class(),
437                    Class::Application
438                );
439
440                assert_eq!(
441                    Tag::ContextSpecific {
442                        constructed,
443                        number
444                    }
445                    .class(),
446                    Class::ContextSpecific
447                );
448
449                assert_eq!(
450                    Tag::Private {
451                        constructed,
452                        number
453                    }
454                    .class(),
455                    Class::Private
456                );
457            }
458        }
459    }
460}