• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! ASN.1 tags.
2 
3 mod class;
4 mod mode;
5 mod number;
6 
7 pub use self::{class::Class, mode::TagMode, number::TagNumber};
8 
9 use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Length, Reader, Result, Writer};
10 use core::{cmp::Ordering, fmt};
11 
12 /// Indicator bit for constructed form encoding (i.e. vs primitive form)
13 const CONSTRUCTED_FLAG: u8 = 0b100000;
14 
15 /// Types which have a constant ASN.1 [`Tag`].
16 pub trait FixedTag {
17     /// ASN.1 tag
18     const TAG: Tag;
19 }
20 
21 /// Types which have an ASN.1 [`Tag`].
22 pub trait Tagged {
23     /// Get the ASN.1 tag that this type is encoded with.
tag(&self) -> Tag24     fn tag(&self) -> Tag;
25 }
26 
27 /// Types which are [`FixedTag`] always have a known [`Tag`] type.
28 impl<T: FixedTag> Tagged for T {
tag(&self) -> Tag29     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]
51 pub 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 
140 impl Tag {
141     /// Assert that this [`Tag`] matches the provided expected tag.
142     ///
143     /// On mismatch, returns an [`Error`] with [`ErrorKind::TagUnexpected`].
assert_eq(self, expected: Tag) -> Result<Tag>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`].
class(self) -> Class153     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.
number(self) -> TagNumber163     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?
is_constructed(self) -> bool168     pub fn is_constructed(self) -> bool {
169         self.octet() & CONSTRUCTED_FLAG != 0
170     }
171 
172     /// Is this an application tag?
is_application(self) -> bool173     pub fn is_application(self) -> bool {
174         self.class() == Class::Application
175     }
176 
177     /// Is this a context-specific tag?
is_context_specific(self) -> bool178     pub fn is_context_specific(self) -> bool {
179         self.class() == Class::ContextSpecific
180     }
181 
182     /// Is this a private tag?
is_private(self) -> bool183     pub fn is_private(self) -> bool {
184         self.class() == Class::Private
185     }
186 
187     /// Is this a universal tag?
is_universal(self) -> bool188     pub fn is_universal(self) -> bool {
189         self.class() == Class::Universal
190     }
191 
192     /// Get the octet encoding for this [`Tag`].
octet(self) -> u8193     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`].
length_error(self) -> Error231     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.
non_canonical_error(self) -> Error237     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.
unexpected_error(self, expected: Option<Self>) -> Error243     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.
value_error(self) -> Error253     pub fn value_error(self) -> Error {
254         ErrorKind::Value { tag: self }.into()
255     }
256 }
257 
258 impl TryFrom<u8> for Tag {
259     type Error = Error;
260 
try_from(byte: u8) -> Result<Tag>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 
303 impl From<Tag> for u8 {
from(tag: Tag) -> u8304     fn from(tag: Tag) -> u8 {
305         tag.octet()
306     }
307 }
308 
309 impl From<&Tag> for u8 {
from(tag: &Tag) -> u8310     fn from(tag: &Tag) -> u8 {
311         u8::from(*tag)
312     }
313 }
314 
315 impl<'a> Decode<'a> for Tag {
decode<R: Reader<'a>>(reader: &mut R) -> Result<Self>316     fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> {
317         reader.read_byte().and_then(Self::try_from)
318     }
319 }
320 
321 impl Encode for Tag {
encoded_len(&self) -> Result<Length>322     fn encoded_len(&self) -> Result<Length> {
323         Ok(Length::ONE)
324     }
325 
encode(&self, writer: &mut dyn Writer) -> Result<()>326     fn encode(&self, writer: &mut dyn Writer) -> Result<()> {
327         writer.write_byte(self.into())
328     }
329 }
330 
331 impl DerOrd for Tag {
der_cmp(&self, other: &Self) -> Result<Ordering>332     fn der_cmp(&self, other: &Self) -> Result<Ordering> {
333         Ok(self.octet().cmp(&other.octet()))
334     }
335 }
336 
337 impl fmt::Display for Tag {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result338     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 
393 impl fmt::Debug for Tag {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result394     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)]
400 mod tests {
401     use super::TagNumber;
402     use super::{Class, Tag};
403 
404     #[test]
tag_class()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 }
459