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::{Decodable, Decoder, DerOrd, Encodable, Encoder, Error, ErrorKind, Length, Result};
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    /// `ENUMERATED` tag: `10`.
71    Enumerated,
72
73    /// `UTF8String` tag: `12`.
74    Utf8String,
75
76    /// `SEQUENCE` tag: `16`.
77    Sequence,
78
79    /// `SET` and `SET OF` tag: `17`.
80    Set,
81
82    /// `NumericString` tag: `18`.
83    NumericString,
84
85    /// `PrintableString` tag: `19`.
86    PrintableString,
87
88    /// `IA5String` tag: `22`.
89    Ia5String,
90
91    /// `UTCTime` tag: `23`.
92    UtcTime,
93
94    /// `GeneralizedTime` tag: `24`.
95    GeneralizedTime,
96
97    /// `VisibleString` tag: `26`.
98    VisibleString,
99
100    /// `BMPString` tag: `30`.
101    BmpString,
102
103    /// Application tag.
104    Application {
105        /// Is this tag constructed? (vs primitive).
106        constructed: bool,
107
108        /// Tag number.
109        number: TagNumber,
110    },
111
112    /// Context-specific tag.
113    ContextSpecific {
114        /// Is this tag constructed? (vs primitive).
115        constructed: bool,
116
117        /// Tag number.
118        number: TagNumber,
119    },
120
121    /// Private tag number.
122    Private {
123        /// Is this tag constructed? (vs primitive).
124        constructed: bool,
125
126        /// Tag number.
127        number: TagNumber,
128    },
129}
130
131impl Tag {
132    /// Assert that this [`Tag`] matches the provided expected tag.
133    ///
134    /// On mismatch, returns an [`Error`] with [`ErrorKind::TagUnexpected`].
135    pub fn assert_eq(self, expected: Tag) -> Result<Tag> {
136        if self == expected {
137            Ok(self)
138        } else {
139            Err(self.unexpected_error(Some(expected)))
140        }
141    }
142
143    /// Get the [`Class`] that corresponds to this [`Tag`].
144    pub fn class(self) -> Class {
145        match self {
146            Tag::Application { .. } => Class::Application,
147            Tag::ContextSpecific { .. } => Class::ContextSpecific,
148            Tag::Private { .. } => Class::Private,
149            _ => Class::Universal,
150        }
151    }
152
153    /// Get the [`TagNumber`] (lower 6-bits) for this tag.
154    pub fn number(self) -> TagNumber {
155        TagNumber(self.octet() & TagNumber::MASK)
156    }
157
158    /// Does this tag represent a constructed (as opposed to primitive) field?
159    pub fn is_constructed(self) -> bool {
160        self.octet() & CONSTRUCTED_FLAG != 0
161    }
162
163    /// Is this an application tag?
164    pub fn is_application(self) -> bool {
165        self.class() == Class::Application
166    }
167
168    /// Is this a context-specific tag?
169    pub fn is_context_specific(self) -> bool {
170        self.class() == Class::ContextSpecific
171    }
172
173    /// Is this a private tag?
174    pub fn is_private(self) -> bool {
175        self.class() == Class::Private
176    }
177
178    /// Is this a universal tag?
179    pub fn is_universal(self) -> bool {
180        self.class() == Class::Universal
181    }
182
183    /// Get the octet encoding for this [`Tag`].
184    pub fn octet(self) -> u8 {
185        match self {
186            Tag::Boolean => 0x01,
187            Tag::Integer => 0x02,
188            Tag::BitString => 0x03,
189            Tag::OctetString => 0x04,
190            Tag::Null => 0x05,
191            Tag::ObjectIdentifier => 0x06,
192            Tag::Enumerated => 0x0A,
193            Tag::Utf8String => 0x0C,
194            Tag::Sequence => 0x10 | CONSTRUCTED_FLAG,
195            Tag::Set => 0x11 | CONSTRUCTED_FLAG,
196            Tag::NumericString => 0x12,
197            Tag::PrintableString => 0x13,
198            Tag::Ia5String => 0x16,
199            Tag::UtcTime => 0x17,
200            Tag::GeneralizedTime => 0x18,
201            Tag::VisibleString => 0x1A,
202            Tag::BmpString => 0x1D,
203            Tag::Application {
204                constructed,
205                number,
206            }
207            | Tag::ContextSpecific {
208                constructed,
209                number,
210            }
211            | Tag::Private {
212                constructed,
213                number,
214            } => self.class().octet(constructed, number),
215        }
216    }
217
218    /// Create an [`Error`] for an invalid [`Length`].
219    pub fn length_error(self) -> Error {
220        ErrorKind::Length { tag: self }.into()
221    }
222
223    /// Create an [`Error`] for an non-canonical value with the ASN.1 type
224    /// identified by this tag.
225    pub fn non_canonical_error(self) -> Error {
226        ErrorKind::Noncanonical { tag: self }.into()
227    }
228
229    /// Create an [`Error`] because the current tag was unexpected, with an
230    /// optional expected tag.
231    pub fn unexpected_error(self, expected: Option<Self>) -> Error {
232        ErrorKind::TagUnexpected {
233            expected,
234            actual: self,
235        }
236        .into()
237    }
238
239    /// Create an [`Error`] for an invalid value with the ASN.1 type identified
240    /// by this tag.
241    pub fn value_error(self) -> Error {
242        ErrorKind::Value { tag: self }.into()
243    }
244}
245
246impl TryFrom<u8> for Tag {
247    type Error = Error;
248
249    fn try_from(byte: u8) -> Result<Tag> {
250        let constructed = byte & CONSTRUCTED_FLAG != 0;
251        let number = TagNumber::try_from(byte & TagNumber::MASK)?;
252
253        match byte {
254            0x01 => Ok(Tag::Boolean),
255            0x02 => Ok(Tag::Integer),
256            0x03 => Ok(Tag::BitString),
257            0x04 => Ok(Tag::OctetString),
258            0x05 => Ok(Tag::Null),
259            0x06 => Ok(Tag::ObjectIdentifier),
260            0x0A => Ok(Tag::Enumerated),
261            0x0C => Ok(Tag::Utf8String),
262            0x12 => Ok(Tag::NumericString),
263            0x13 => Ok(Tag::PrintableString),
264            0x16 => Ok(Tag::Ia5String),
265            0x17 => Ok(Tag::UtcTime),
266            0x18 => Ok(Tag::GeneralizedTime),
267            0x1A => Ok(Tag::VisibleString),
268            0x1d => Ok(Tag::BmpString),
269            0x30 => Ok(Tag::Sequence), // constructed
270            0x31 => Ok(Tag::Set),      // constructed
271            0x40..=0x7E => Ok(Tag::Application {
272                constructed,
273                number,
274            }),
275            0x80..=0xBE => Ok(Tag::ContextSpecific {
276                constructed,
277                number,
278            }),
279            0xC0..=0xFE => Ok(Tag::Private {
280                constructed,
281                number,
282            }),
283            _ => Err(ErrorKind::TagUnknown { byte }.into()),
284        }
285    }
286}
287
288impl From<Tag> for u8 {
289    fn from(tag: Tag) -> u8 {
290        tag.octet()
291    }
292}
293
294impl From<&Tag> for u8 {
295    fn from(tag: &Tag) -> u8 {
296        u8::from(*tag)
297    }
298}
299
300impl Decodable<'_> for Tag {
301    fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
302        decoder.byte().and_then(Self::try_from)
303    }
304}
305
306impl Encodable for Tag {
307    fn encoded_len(&self) -> Result<Length> {
308        Ok(Length::ONE)
309    }
310
311    fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
312        encoder.byte(self.into())
313    }
314}
315
316impl DerOrd for Tag {
317    fn der_cmp(&self, other: &Self) -> Result<Ordering> {
318        Ok(self.octet().cmp(&other.octet()))
319    }
320}
321
322impl fmt::Display for Tag {
323    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
324        const FIELD_TYPE: [&str; 2] = ["primitive", "constructed"];
325
326        match *self {
327            Tag::Boolean => f.write_str("BOOLEAN"),
328            Tag::Integer => f.write_str("INTEGER"),
329            Tag::BitString => f.write_str("BIT STRING"),
330            Tag::OctetString => f.write_str("OCTET STRING"),
331            Tag::Null => f.write_str("NULL"),
332            Tag::ObjectIdentifier => f.write_str("OBJECT IDENTIFIER"),
333            Tag::Enumerated => f.write_str("ENUMERATED"),
334            Tag::Utf8String => f.write_str("UTF8String"),
335            Tag::Set => f.write_str("SET"),
336            Tag::NumericString => f.write_str("NumericString"),
337            Tag::PrintableString => f.write_str("PrintableString"),
338            Tag::Ia5String => f.write_str("IA5String"),
339            Tag::UtcTime => f.write_str("UTCTime"),
340            Tag::GeneralizedTime => f.write_str("GeneralizedTime"),
341            Tag::VisibleString => f.write_str("VisibleString"),
342            Tag::BmpString => f.write_str("BMPString"),
343            Tag::Sequence => f.write_str("SEQUENCE"),
344            Tag::Application {
345                constructed,
346                number,
347            } => write!(
348                f,
349                "APPLICATION [{}] ({})",
350                number, FIELD_TYPE[constructed as usize]
351            ),
352            Tag::ContextSpecific {
353                constructed,
354                number,
355            } => write!(
356                f,
357                "CONTEXT-SPECIFIC [{}] ({})",
358                number, FIELD_TYPE[constructed as usize]
359            ),
360            Tag::Private {
361                constructed,
362                number,
363            } => write!(
364                f,
365                "PRIVATE [{}] ({})",
366                number, FIELD_TYPE[constructed as usize]
367            ),
368        }
369    }
370}
371
372impl fmt::Debug for Tag {
373    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
374        write!(f, "Tag(0x{:02x}: {})", u8::from(*self), self)
375    }
376}
377
378#[cfg(test)]
379mod tests {
380    use super::TagNumber;
381    use super::{Class, Tag};
382
383    #[test]
384    fn tag_class() {
385        assert_eq!(Tag::Boolean.class(), Class::Universal);
386        assert_eq!(Tag::Integer.class(), Class::Universal);
387        assert_eq!(Tag::BitString.class(), Class::Universal);
388        assert_eq!(Tag::OctetString.class(), Class::Universal);
389        assert_eq!(Tag::Null.class(), Class::Universal);
390        assert_eq!(Tag::ObjectIdentifier.class(), Class::Universal);
391        assert_eq!(Tag::Enumerated.class(), Class::Universal);
392        assert_eq!(Tag::Utf8String.class(), Class::Universal);
393        assert_eq!(Tag::Set.class(), Class::Universal);
394        assert_eq!(Tag::NumericString.class(), Class::Universal);
395        assert_eq!(Tag::PrintableString.class(), Class::Universal);
396        assert_eq!(Tag::Ia5String.class(), Class::Universal);
397        assert_eq!(Tag::UtcTime.class(), Class::Universal);
398        assert_eq!(Tag::GeneralizedTime.class(), Class::Universal);
399        assert_eq!(Tag::Sequence.class(), Class::Universal);
400
401        for num in 0..=30 {
402            for &constructed in &[false, true] {
403                let number = TagNumber::new(num);
404
405                assert_eq!(
406                    Tag::Application {
407                        constructed,
408                        number
409                    }
410                    .class(),
411                    Class::Application
412                );
413
414                assert_eq!(
415                    Tag::ContextSpecific {
416                        constructed,
417                        number
418                    }
419                    .class(),
420                    Class::ContextSpecific
421                );
422
423                assert_eq!(
424                    Tag::Private {
425                        constructed,
426                        number
427                    }
428                    .class(),
429                    Class::Private
430                );
431            }
432        }
433    }
434}