1use crate::{
2 Decodable, Decoder, Encodable, Encoder, Error, ErrorKind, Length, Result, TaggedValue,
3};
4use core::{
5 convert::{TryFrom, TryInto},
6 fmt,
7};
8
9const CLASS_OFFSET: usize = 6;
10const CONSTRUCTED_OFFSET: usize = 5;
11
12const CONSTRUCTED_FLAG: u8 = 1u8 << CONSTRUCTED_OFFSET;
14
15const NOT_LAST_TAG_OCTET_FLAG: u8 = 1u8 << 7;
17
18#[derive(Clone, Copy, Debug, Eq, PartialEq)]
19#[repr(u8)]
20pub enum Class {
22 Universal = 0b00,
23 Application = 0b01,
24 Context = 0b10,
25 Private = 0b11,
26}
27
28impl TryFrom<u8> for Class {
29 type Error = Error;
30 fn try_from(value: u8) -> Result<Self> {
31 use Class::*;
32 Ok(match value {
33 0b00 => Universal,
34 0b01 => Application,
35 0b10 => Context,
36 0b11 => Private,
37 _ => return Err(ErrorKind::InvalidClass { value }.into()),
38 })
39 }
40}
41
42#[derive(Clone, Copy, Eq, PartialEq)]
44pub struct Tag {
45 pub class: Class,
46 pub constructed: bool,
47 pub number: u16,
48}
49
50impl Tag {
51 pub const BOOLEAN: Self = Self::universal(0x1);
52 pub const INTEGER: Self = Self::universal(0x1);
53 pub const BIT_STRING: Self = Self::universal(0x3);
54 pub const OCTET_STRING: Self = Self::universal(0x4);
55 pub const NULL: Self = Self::universal(0x5);
56 pub const OBJECT_IDENTIFIER: Self = Self::universal(0x6);
57 pub const UTF8_STRING: Self = Self::universal(0xC);
58 pub const PRINTABLE_STRING: Self = Self::universal(0x13);
59 pub const UTC_TIME: Self = Self::universal(0x17);
60 pub const GENERALIZED_TIME: Self = Self::universal(0x18);
61 pub const SEQUENCE: Self = Self::universal(0x10).constructed();
62 pub const SET: Self = Self::universal(0x11).constructed();
63
64 pub fn from(class: Class, constructed: bool, number: u16) -> Self {
65 Self {
66 class,
67 constructed,
68 number,
69 }
70 }
71 pub const fn universal(number: u16) -> Self {
72 Self {
73 class: Class::Universal,
74 constructed: false,
75 number,
76 }
77 }
78
79 pub const fn application(number: u16) -> Self {
80 Self {
81 class: Class::Application,
82 constructed: false,
83 number,
84 }
85 }
86
87 pub const fn context(number: u16) -> Self {
88 Self {
89 class: Class::Context,
90 constructed: false,
91 number,
92 }
93 }
94
95 pub const fn private(number: u16) -> Self {
96 Self {
97 class: Class::Private,
98 constructed: false,
99 number,
100 }
101 }
102
103 pub const fn constructed(self) -> Self {
104 let Self {
105 class,
106 constructed: _,
107 number,
108 } = self;
109 Self {
110 class,
111 constructed: true,
112 number,
113 }
114 }
115}
116
117impl TryFrom<&'_ [u8]> for Tag {
118 type Error = Error;
119 fn try_from(encoding: &[u8]) -> Result<Self> {
120 let mut decoder = Decoder::new(encoding);
121 decoder.decode()
122 }
123}
124
125impl TryFrom<u8> for Tag {
126 type Error = Error;
127 fn try_from(encoded_value: u8) -> Result<Self> {
128 [encoded_value].as_ref().try_into()
129 }
130}
131
132pub trait TagLike: Copy + PartialEq + Sized {
135 fn embedding(self) -> Tag;
138
139 fn assert_eq(self, expected: Self) -> Result<Self> {
143 if self == expected {
144 Ok(self)
145 } else {
146 Err(ErrorKind::UnexpectedTag {
147 expected: Some(expected.embedding()),
148 actual: self.embedding(),
149 }
150 .into())
151 }
152 }
153
154 fn with_value<V>(self, value: V) -> TaggedValue<V, Self> {
156 TaggedValue::new(self, value)
157 }
158}
159
160impl TagLike for Tag {
161 fn embedding(self) -> Tag {
162 self
163 }
164}
165
166impl fmt::Display for Tag {
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 core::fmt::Debug::fmt(self, f)
171 }
172}
173
174impl fmt::Debug for Tag {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 let mut buf = [0u8; 3];
177 let mut encoder = Encoder::new(&mut buf);
178 encoder.encode(self).unwrap();
179 write!(
180 f,
181 "Tag(class = {:?}, constructed = {}, number = {})",
182 self.class, self.constructed, self.number
183 )
184 }
185}
186
187impl Encodable for Tag {
188 fn encoded_length(&self) -> Result<Length> {
189 match self.number {
190 0..=0x1E => Ok(Length(1)),
191 0x1F..=0x7F => Ok(Length(2)),
192 0x80..=0x3FFF => Ok(Length(3)),
193 0x4000..=0xFFFF => Ok(Length(4)),
194 }
195 }
196
197 fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
198 let first_byte =
199 ((self.class as u8) << CLASS_OFFSET) | ((self.constructed as u8) << CONSTRUCTED_OFFSET);
200
201 match self.number {
202 0..=0x1E => encoder.byte(first_byte | (self.number as u8)),
203 0x1F..=0x7F => {
204 encoder.byte(first_byte | 0x1F)?;
205 encoder.byte(self.number as u8)
206 }
207 0x80..=0x3FFF => {
208 encoder.byte(first_byte | 0x1F)?;
209 encoder.byte(NOT_LAST_TAG_OCTET_FLAG | (self.number >> 7) as u8)?;
210 encoder.byte((self.number & 0x7F) as u8)
211 }
212 0x4000..=0xFFFF => Err(Error::from(ErrorKind::UnsupportedTagSize)),
213 }
214 }
215}
216
217impl Decodable<'_> for Tag {
218 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
219 let first_byte = decoder.byte()?;
220 let class = (first_byte >> 6).try_into()?;
221 let constructed = first_byte & CONSTRUCTED_FLAG != 0;
222 let first_byte_masked = first_byte & ((1 << 5) - 1);
224
225 let number = match first_byte_masked {
226 number @ 0..=0x1E => number as u16,
227 _ => {
228 let second_byte = decoder.byte()?;
229 if second_byte & NOT_LAST_TAG_OCTET_FLAG == 0 {
230 let number = second_byte;
231 number as u16
232 } else {
233 let number = second_byte & (!NOT_LAST_TAG_OCTET_FLAG);
234 let third_byte = decoder.byte()?;
235 if third_byte & NOT_LAST_TAG_OCTET_FLAG == 0 {
236 ((number as u16) << 7) | (third_byte as u16)
237 } else {
238 return Err(Error::from(ErrorKind::InvalidLength));
240 }
241 }
242 }
243 };
244 Ok(Self {
245 class,
246 constructed,
247 number,
248 })
249 }
250}
251
252#[cfg(test)]
253mod tests {
254 use crate::{Decodable, Encodable, Tag};
255
256 #[test]
257 fn reconstruct() {
258 let mut buf = [0u8; 32];
259
260 let tag = Tag::universal(30);
261 let encoded = tag.encode_to_slice(&mut buf).unwrap();
262 assert_eq!(encoded, &[0x1E]);
263 let tag2 = Tag::from_bytes(encoded).unwrap();
264 assert_eq!(tag, tag2);
265
266 let tag = Tag::universal(31);
267 let encoded = tag.encode_to_slice(&mut buf).unwrap();
268 assert_eq!(encoded, &[0x1F, 0x1F]);
269 let tag2 = Tag::from_bytes(encoded).unwrap();
270 assert_eq!(tag, tag2);
271
272 let tag = Tag::universal(0xAA);
273 let encoded = tag.encode_to_slice(&mut buf).unwrap();
274 assert_eq!(encoded, &[0x1F, 0x81, 0x2A]);
275 let tag2 = Tag::from_bytes(encoded).unwrap();
276 assert_eq!(tag, tag2);
277
278 let tag = Tag::universal(0x10).constructed();
279 let encoded = tag.encode_to_slice(&mut buf).unwrap();
280 assert_eq!(encoded, &[super::CONSTRUCTED_FLAG + 0x10]);
282 let tag2 = Tag::from_bytes(encoded).unwrap();
283 assert_eq!(tag, tag2);
284 }
285}