1use serde::de;
2use std::fmt;
3
4#[derive(Debug, Clone, Copy, Eq, PartialEq)]
5pub enum Encoding {
6 Primitive,
7 Constructed,
8}
9
10impl fmt::Display for Encoding {
11 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
12 match self {
13 Self::Primitive => write!(f, "PRIMITIVE"),
14 Self::Constructed => write!(f, "CONSTRUCTED"),
15 }
16 }
17}
18
19#[derive(Debug, Clone, Copy, Eq, PartialEq)]
20pub enum TagClass {
21 Universal,
22 Application,
23 ContextSpecific,
24 Private,
25}
26
27impl fmt::Display for TagClass {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 match self {
30 Self::Universal => write!(f, "UNIVERSAL"),
31 Self::Application => write!(f, "APPLICATION"),
32 Self::ContextSpecific => write!(f, "CONTEXT_SPECIFIC"),
33 Self::Private => write!(f, "PRIVATE"),
34 }
35 }
36}
37
38#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
39pub struct Tag(u8);
40
41impl Tag {
42 pub const BOOLEAN: Self = Tag(0x01);
43 pub const INTEGER: Self = Tag(0x02);
44 pub const BIT_STRING: Self = Tag(0x03);
45 pub const OCTET_STRING: Self = Tag(0x04);
46 pub const NULL: Self = Tag(0x05);
47 pub const OID: Self = Tag(0x06);
48 pub const REAL: Self = Tag(0x09);
49 pub const UTF8_STRING: Self = Tag(0x0C);
50 pub const RELATIVE_OID: Self = Tag(0xD);
51 pub const NUMERIC_STRING: Self = Tag(0x12);
52 pub const PRINTABLE_STRING: Self = Tag(0x13);
53 pub const TELETEX_STRING: Self = Tag(0x14);
54 pub const VIDEOTEX_STRING: Self = Tag(0x15);
55 pub const IA5_STRING: Self = Tag(0x16);
56 pub const BMP_STRING: Self = Tag(0x1E);
57 pub const UTC_TIME: Self = Tag(0x17);
58 pub const GENERALIZED_TIME: Self = Tag(0x18);
59 pub const SEQUENCE: Self = Tag(0x30);
60 pub const SET: Self = Tag(0x31);
61 pub const GENERAL_STRING: Self = Tag(0x1b);
62
63 #[inline]
64 pub const fn application_primitive(number: u8) -> Self {
65 Tag(number & 0x1F | 0x40)
66 }
67
68 #[inline]
69 pub const fn application_constructed(number: u8) -> Self {
70 Tag(number & 0x1F | 0x60)
71 }
72
73 #[inline]
74 pub const fn context_specific_primitive(number: u8) -> Self {
75 Tag(number & 0x1F | 0x80)
76 }
77
78 #[inline]
79 pub const fn context_specific_constructed(number: u8) -> Self {
80 Tag(number & 0x1F | 0xA0)
81 }
82
83 #[inline]
85 pub const fn inner(self) -> u8 {
86 self.0
87 }
88
89 #[inline]
91 pub const fn number(self) -> u8 {
92 self.0 & 0x1F
93 }
94
95 pub fn class(self) -> TagClass {
97 match self.0 & 0xC0 {
98 0x00 => TagClass::Universal,
99 0x40 => TagClass::Application,
100 0x80 => TagClass::ContextSpecific,
101 _ => TagClass::Private,
102 }
103 }
104
105 pub fn class_and_number(self) -> (TagClass, u8) {
107 (self.class(), self.number())
108 }
109
110 pub fn components(self) -> (TagClass, Encoding, u8) {
112 (self.class(), self.encoding(), self.number())
113 }
114
115 #[inline]
116 pub const fn is_application(self) -> bool {
117 self.0 & 0xC0 == 0x40
118 }
119
120 #[inline]
121 pub const fn is_context_specific(self) -> bool {
122 self.0 & 0xC0 == 0x80
123 }
124
125 #[inline]
126 pub const fn is_universal(self) -> bool {
127 self.0 & 0xC0 == 0x00
128 }
129
130 #[inline]
131 pub const fn is_private(self) -> bool {
132 self.0 & 0xC0 == 0xC0
133 }
134
135 #[inline]
136 pub const fn is_constructed(self) -> bool {
137 self.0 & 0x20 == 0x20
138 }
139
140 #[inline]
141 pub const fn is_primitive(self) -> bool {
142 !self.is_constructed()
143 }
144
145 #[inline]
147 pub fn encoding(self) -> Encoding {
148 if self.is_constructed() {
149 Encoding::Constructed
150 } else {
151 Encoding::Primitive
152 }
153 }
154}
155
156impl From<u8> for Tag {
157 fn from(tag: u8) -> Self {
158 Self(tag)
159 }
160}
161
162impl fmt::Display for Tag {
163 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164 match *self {
165 Tag::BOOLEAN => write!(f, "BOOLEAN"),
166 Tag::INTEGER => write!(f, "INTEGER"),
167 Tag::BIT_STRING => write!(f, "BIT STRING"),
168 Tag::OCTET_STRING => write!(f, "OCTET STRING"),
169 Tag::NULL => write!(f, "NULL"),
170 Tag::OID => write!(f, "OBJECT IDENTIFIER"),
171 Tag::REAL => write!(f, "REAL"),
172 Tag::UTF8_STRING => write!(f, "UTF8String"),
173 Tag::RELATIVE_OID => write!(f, "RELATIVE-OID"),
174 Tag::NUMERIC_STRING => write!(f, "NumericString"),
175 Tag::PRINTABLE_STRING => write!(f, "PrintableString"),
176 Tag::TELETEX_STRING => write!(f, "TeletexString"),
177 Tag::VIDEOTEX_STRING => write!(f, "VideotexString"),
178 Tag::IA5_STRING => write!(f, "IA5String"),
179 Tag::BMP_STRING => write!(f, "BMPString"),
180 Tag::UTC_TIME => write!(f, "UTCTime"),
181 Tag::GENERALIZED_TIME => write!(f, "GeneralizedTime"),
182 Tag::SEQUENCE => write!(f, "SEQUENCE"),
183 Tag::SET => write!(f, "SET"),
184 Tag::GENERAL_STRING => write!(f, "GeneralString"),
185 other => write!(f, "{}({:02X}) {}", other.class(), other.number(), other.encoding()),
186 }
187 }
188}
189
190impl fmt::Debug for Tag {
191 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
192 write!(f, "Tag({}[{:02X}])", self, self.0)
193 }
194}
195
196#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
263pub struct TagPeeker {
264 pub next_tag: Tag,
265}
266
267impl<'de> de::Deserialize<'de> for TagPeeker {
268 fn deserialize<D>(deserializer: D) -> Result<TagPeeker, D::Error>
269 where
270 D: de::Deserializer<'de>,
271 {
272 struct Visitor;
273
274 impl<'de> de::Visitor<'de> for Visitor {
275 type Value = TagPeeker;
276
277 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
278 formatter.write_str("a valid ASN.1 tag")
279 }
280
281 fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
282 where
283 E: de::Error,
284 {
285 Ok(TagPeeker { next_tag: v.into() })
286 }
287 }
288
289 deserializer.deserialize_identifier(Visitor)
290 }
291}