der/
tag.rs

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