1 //! ASN.1 tags.
2 #![cfg_attr(feature = "arbitrary", allow(clippy::integer_arithmetic))]
3 
4 mod class;
5 mod mode;
6 mod number;
7 
8 pub use self::{class::Class, mode::TagMode, number::TagNumber};
9 
10 use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Length, Reader, Result, Writer};
11 use core::{cmp::Ordering, fmt};
12 
13 /// Indicator bit for constructed form encoding (i.e. vs primitive form)
14 const CONSTRUCTED_FLAG: u8 = 0b100000;
15 
16 /// Types which have a constant ASN.1 [`Tag`].
17 pub trait FixedTag {
18     /// ASN.1 tag
19     const TAG: Tag;
20 }
21 
22 /// Types which have an ASN.1 [`Tag`].
23 pub trait Tagged {
24     /// Get the ASN.1 tag that this type is encoded with.
tag(&self) -> Tag25     fn tag(&self) -> Tag;
26 }
27 
28 /// Types which are [`FixedTag`] always have a known [`Tag`] type.
29 impl<T: FixedTag> Tagged for T {
tag(&self) -> Tag30     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]
53 pub 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 
142 impl Tag {
143     /// Assert that this [`Tag`] matches the provided expected tag.
144     ///
145     /// On mismatch, returns an [`Error`] with [`ErrorKind::TagUnexpected`].
assert_eq(self, expected: Tag) -> Result<Tag>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`].
class(self) -> Class155     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.
number(self) -> TagNumber165     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?
is_constructed(self) -> bool170     pub fn is_constructed(self) -> bool {
171         self.octet() & CONSTRUCTED_FLAG != 0
172     }
173 
174     /// Is this an application tag?
is_application(self) -> bool175     pub fn is_application(self) -> bool {
176         self.class() == Class::Application
177     }
178 
179     /// Is this a context-specific tag?
is_context_specific(self) -> bool180     pub fn is_context_specific(self) -> bool {
181         self.class() == Class::ContextSpecific
182     }
183 
184     /// Is this a private tag?
is_private(self) -> bool185     pub fn is_private(self) -> bool {
186         self.class() == Class::Private
187     }
188 
189     /// Is this a universal tag?
is_universal(self) -> bool190     pub fn is_universal(self) -> bool {
191         self.class() == Class::Universal
192     }
193 
194     /// Get the octet encoding for this [`Tag`].
octet(self) -> u8195     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`].
length_error(self) -> Error233     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.
non_canonical_error(self) -> Error239     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.
unexpected_error(self, expected: Option<Self>) -> Error245     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.
value_error(self) -> Error255     pub fn value_error(self) -> Error {
256         ErrorKind::Value { tag: self }.into()
257     }
258 }
259 
260 impl TryFrom<u8> for Tag {
261     type Error = Error;
262 
try_from(byte: u8) -> Result<Tag>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 
305 impl From<Tag> for u8 {
from(tag: Tag) -> u8306     fn from(tag: Tag) -> u8 {
307         tag.octet()
308     }
309 }
310 
311 impl From<&Tag> for u8 {
from(tag: &Tag) -> u8312     fn from(tag: &Tag) -> u8 {
313         u8::from(*tag)
314     }
315 }
316 
317 impl<'a> Decode<'a> for Tag {
decode<R: Reader<'a>>(reader: &mut R) -> Result<Self>318     fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> {
319         reader.read_byte().and_then(Self::try_from)
320     }
321 }
322 
323 impl Encode for Tag {
encoded_len(&self) -> Result<Length>324     fn encoded_len(&self) -> Result<Length> {
325         Ok(Length::ONE)
326     }
327 
encode(&self, writer: &mut impl Writer) -> Result<()>328     fn encode(&self, writer: &mut impl Writer) -> Result<()> {
329         writer.write_byte(self.into())
330     }
331 }
332 
333 impl DerOrd for Tag {
der_cmp(&self, other: &Self) -> Result<Ordering>334     fn der_cmp(&self, other: &Self) -> Result<Ordering> {
335         Ok(self.octet().cmp(&other.octet()))
336     }
337 }
338 
339 impl fmt::Display for Tag {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result340     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 
395 impl fmt::Debug for Tag {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result396     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)]
402 mod tests {
403     use super::TagNumber;
404     use super::{Class, Tag};
405 
406     #[test]
tag_class()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 }
461