asn1_rs/
tag.rs

1use crate::{Class, Error, InnerError, Result};
2#[cfg(not(feature = "std"))]
3use alloc::string::ToString;
4use rusticata_macros::newtype_enum;
5
6/// BER/DER Tag as defined in X.680 section 8.4
7///
8/// X.690 doesn't specify the maximum tag size so we're assuming that people
9/// aren't going to need anything more than a u32.
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
11pub struct Tag(pub u32);
12
13newtype_enum! {
14impl display Tag {
15    EndOfContent = 0,
16    Boolean = 1,
17    Integer = 2,
18    BitString = 3,
19    OctetString = 4,
20    Null = 5,
21    Oid = 6,
22    ObjectDescriptor = 7,
23    External = 8,
24    RealType = 9,
25    Enumerated = 10,
26    EmbeddedPdv = 11,
27    Utf8String = 12,
28    RelativeOid = 13,
29
30    Sequence = 16,
31    Set = 17,
32    NumericString = 18,
33    PrintableString = 19,
34    T61String = 20,
35    TeletexString = 20,
36    VideotexString = 21,
37
38    Ia5String = 22,
39    UtcTime = 23,
40    GeneralizedTime = 24,
41
42    GraphicString = 25,
43    VisibleString = 26,
44    GeneralString = 27,
45
46    UniversalString = 28,
47    CharacterString = 29,
48    BmpString = 30,
49}
50}
51
52impl Tag {
53    pub const fn assert_eq(&self, tag: Tag) -> Result<()> {
54        if self.0 == tag.0 {
55            Ok(())
56        } else {
57            Err(Error::UnexpectedTag {
58                expected: Some(tag),
59                actual: *self,
60            })
61        }
62    }
63
64    pub const fn assert_eq_inner(&self, tag: Tag) -> Result<(), InnerError> {
65        if self.0 == tag.0 {
66            Ok(())
67        } else {
68            Err(InnerError::UnexpectedTag {
69                expected: Some(tag),
70                actual: *self,
71            })
72        }
73    }
74
75    pub fn invalid_value(&self, msg: &str) -> Error {
76        Error::InvalidValue {
77            tag: *self,
78            msg: msg.to_string(),
79        }
80    }
81}
82
83impl From<u32> for Tag {
84    fn from(v: u32) -> Self {
85        Tag(v)
86    }
87}
88
89pub trait Tagged {
90    const CLASS: Class = Class::Universal;
91
92    const CONSTRUCTED: bool = false;
93
94    const TAG: Tag;
95}
96
97impl<T> Tagged for &'_ T
98where
99    T: Tagged,
100{
101    const CLASS: Class = T::CLASS;
102    const CONSTRUCTED: bool = T::CONSTRUCTED;
103    const TAG: Tag = T::TAG;
104}
105
106/// Common trait for all tagged objects
107pub trait DynTagged {
108    /// Return the class of the object
109    fn class(&self) -> Class {
110        Class::Universal
111    }
112
113    /// Return `true` if the object is constructed
114    fn constructed(&self) -> bool {
115        false
116    }
117
118    /// Return the tag number of the object
119    fn tag(&self) -> Tag;
120
121    /// Return true if the tag number is acceptable for this object
122    ///
123    /// For most types, this is a static test (`tag == Self::TAG`). Examples of exceptions:
124    /// - type `Any` (accepts all tag numbers)
125    /// - ASN.1 type `CHOICE` (accept multiple tags)
126    fn accept_tag(tag: Tag) -> bool;
127}
128
129impl<T> DynTagged for T
130where
131    T: Tagged,
132{
133    fn class(&self) -> Class {
134        T::CLASS
135    }
136
137    fn constructed(&self) -> bool {
138        T::CONSTRUCTED
139    }
140
141    fn tag(&self) -> Tag {
142        T::TAG
143    }
144
145    fn accept_tag(tag: Tag) -> bool {
146        tag == T::TAG
147    }
148}