1mod class;
4mod mode;
5mod number;
6
7pub use self::{class::Class, mode::TagMode, number::TagNumber};
8
9use crate::{Decodable, Decoder, DerOrd, Encodable, Encoder, Error, ErrorKind, Length, Result};
10use core::{cmp::Ordering, fmt};
11
12const CONSTRUCTED_FLAG: u8 = 0b100000;
14
15pub trait FixedTag {
17 const TAG: Tag;
19}
20
21pub trait Tagged {
23 fn tag(&self) -> Tag;
25}
26
27impl<T: FixedTag> Tagged for T {
29 fn tag(&self) -> Tag {
30 T::TAG
31 }
32}
33
34#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
50#[non_exhaustive]
51pub enum Tag {
52 Boolean,
54
55 Integer,
57
58 BitString,
60
61 OctetString,
63
64 Null,
66
67 ObjectIdentifier,
69
70 Enumerated,
72
73 Utf8String,
75
76 Sequence,
78
79 Set,
81
82 NumericString,
84
85 PrintableString,
87
88 Ia5String,
90
91 UtcTime,
93
94 GeneralizedTime,
96
97 VisibleString,
99
100 BmpString,
102
103 Application {
105 constructed: bool,
107
108 number: TagNumber,
110 },
111
112 ContextSpecific {
114 constructed: bool,
116
117 number: TagNumber,
119 },
120
121 Private {
123 constructed: bool,
125
126 number: TagNumber,
128 },
129}
130
131impl Tag {
132 pub fn assert_eq(self, expected: Tag) -> Result<Tag> {
136 if self == expected {
137 Ok(self)
138 } else {
139 Err(self.unexpected_error(Some(expected)))
140 }
141 }
142
143 pub fn class(self) -> Class {
145 match self {
146 Tag::Application { .. } => Class::Application,
147 Tag::ContextSpecific { .. } => Class::ContextSpecific,
148 Tag::Private { .. } => Class::Private,
149 _ => Class::Universal,
150 }
151 }
152
153 pub fn number(self) -> TagNumber {
155 TagNumber(self.octet() & TagNumber::MASK)
156 }
157
158 pub fn is_constructed(self) -> bool {
160 self.octet() & CONSTRUCTED_FLAG != 0
161 }
162
163 pub fn is_application(self) -> bool {
165 self.class() == Class::Application
166 }
167
168 pub fn is_context_specific(self) -> bool {
170 self.class() == Class::ContextSpecific
171 }
172
173 pub fn is_private(self) -> bool {
175 self.class() == Class::Private
176 }
177
178 pub fn is_universal(self) -> bool {
180 self.class() == Class::Universal
181 }
182
183 pub fn octet(self) -> u8 {
185 match self {
186 Tag::Boolean => 0x01,
187 Tag::Integer => 0x02,
188 Tag::BitString => 0x03,
189 Tag::OctetString => 0x04,
190 Tag::Null => 0x05,
191 Tag::ObjectIdentifier => 0x06,
192 Tag::Enumerated => 0x0A,
193 Tag::Utf8String => 0x0C,
194 Tag::Sequence => 0x10 | CONSTRUCTED_FLAG,
195 Tag::Set => 0x11 | CONSTRUCTED_FLAG,
196 Tag::NumericString => 0x12,
197 Tag::PrintableString => 0x13,
198 Tag::Ia5String => 0x16,
199 Tag::UtcTime => 0x17,
200 Tag::GeneralizedTime => 0x18,
201 Tag::VisibleString => 0x1A,
202 Tag::BmpString => 0x1D,
203 Tag::Application {
204 constructed,
205 number,
206 }
207 | Tag::ContextSpecific {
208 constructed,
209 number,
210 }
211 | Tag::Private {
212 constructed,
213 number,
214 } => self.class().octet(constructed, number),
215 }
216 }
217
218 pub fn length_error(self) -> Error {
220 ErrorKind::Length { tag: self }.into()
221 }
222
223 pub fn non_canonical_error(self) -> Error {
226 ErrorKind::Noncanonical { tag: self }.into()
227 }
228
229 pub fn unexpected_error(self, expected: Option<Self>) -> Error {
232 ErrorKind::TagUnexpected {
233 expected,
234 actual: self,
235 }
236 .into()
237 }
238
239 pub fn value_error(self) -> Error {
242 ErrorKind::Value { tag: self }.into()
243 }
244}
245
246impl TryFrom<u8> for Tag {
247 type Error = Error;
248
249 fn try_from(byte: u8) -> Result<Tag> {
250 let constructed = byte & CONSTRUCTED_FLAG != 0;
251 let number = TagNumber::try_from(byte & TagNumber::MASK)?;
252
253 match byte {
254 0x01 => Ok(Tag::Boolean),
255 0x02 => Ok(Tag::Integer),
256 0x03 => Ok(Tag::BitString),
257 0x04 => Ok(Tag::OctetString),
258 0x05 => Ok(Tag::Null),
259 0x06 => Ok(Tag::ObjectIdentifier),
260 0x0A => Ok(Tag::Enumerated),
261 0x0C => Ok(Tag::Utf8String),
262 0x12 => Ok(Tag::NumericString),
263 0x13 => Ok(Tag::PrintableString),
264 0x16 => Ok(Tag::Ia5String),
265 0x17 => Ok(Tag::UtcTime),
266 0x18 => Ok(Tag::GeneralizedTime),
267 0x1A => Ok(Tag::VisibleString),
268 0x1d => Ok(Tag::BmpString),
269 0x30 => Ok(Tag::Sequence), 0x31 => Ok(Tag::Set), 0x40..=0x7E => Ok(Tag::Application {
272 constructed,
273 number,
274 }),
275 0x80..=0xBE => Ok(Tag::ContextSpecific {
276 constructed,
277 number,
278 }),
279 0xC0..=0xFE => Ok(Tag::Private {
280 constructed,
281 number,
282 }),
283 _ => Err(ErrorKind::TagUnknown { byte }.into()),
284 }
285 }
286}
287
288impl From<Tag> for u8 {
289 fn from(tag: Tag) -> u8 {
290 tag.octet()
291 }
292}
293
294impl From<&Tag> for u8 {
295 fn from(tag: &Tag) -> u8 {
296 u8::from(*tag)
297 }
298}
299
300impl Decodable<'_> for Tag {
301 fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
302 decoder.byte().and_then(Self::try_from)
303 }
304}
305
306impl Encodable for Tag {
307 fn encoded_len(&self) -> Result<Length> {
308 Ok(Length::ONE)
309 }
310
311 fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
312 encoder.byte(self.into())
313 }
314}
315
316impl DerOrd for Tag {
317 fn der_cmp(&self, other: &Self) -> Result<Ordering> {
318 Ok(self.octet().cmp(&other.octet()))
319 }
320}
321
322impl fmt::Display for Tag {
323 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
324 const FIELD_TYPE: [&str; 2] = ["primitive", "constructed"];
325
326 match *self {
327 Tag::Boolean => f.write_str("BOOLEAN"),
328 Tag::Integer => f.write_str("INTEGER"),
329 Tag::BitString => f.write_str("BIT STRING"),
330 Tag::OctetString => f.write_str("OCTET STRING"),
331 Tag::Null => f.write_str("NULL"),
332 Tag::ObjectIdentifier => f.write_str("OBJECT IDENTIFIER"),
333 Tag::Enumerated => f.write_str("ENUMERATED"),
334 Tag::Utf8String => f.write_str("UTF8String"),
335 Tag::Set => f.write_str("SET"),
336 Tag::NumericString => f.write_str("NumericString"),
337 Tag::PrintableString => f.write_str("PrintableString"),
338 Tag::Ia5String => f.write_str("IA5String"),
339 Tag::UtcTime => f.write_str("UTCTime"),
340 Tag::GeneralizedTime => f.write_str("GeneralizedTime"),
341 Tag::VisibleString => f.write_str("VisibleString"),
342 Tag::BmpString => f.write_str("BMPString"),
343 Tag::Sequence => f.write_str("SEQUENCE"),
344 Tag::Application {
345 constructed,
346 number,
347 } => write!(
348 f,
349 "APPLICATION [{}] ({})",
350 number, FIELD_TYPE[constructed as usize]
351 ),
352 Tag::ContextSpecific {
353 constructed,
354 number,
355 } => write!(
356 f,
357 "CONTEXT-SPECIFIC [{}] ({})",
358 number, FIELD_TYPE[constructed as usize]
359 ),
360 Tag::Private {
361 constructed,
362 number,
363 } => write!(
364 f,
365 "PRIVATE [{}] ({})",
366 number, FIELD_TYPE[constructed as usize]
367 ),
368 }
369 }
370}
371
372impl fmt::Debug for Tag {
373 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
374 write!(f, "Tag(0x{:02x}: {})", u8::from(*self), self)
375 }
376}
377
378#[cfg(test)]
379mod tests {
380 use super::TagNumber;
381 use super::{Class, Tag};
382
383 #[test]
384 fn tag_class() {
385 assert_eq!(Tag::Boolean.class(), Class::Universal);
386 assert_eq!(Tag::Integer.class(), Class::Universal);
387 assert_eq!(Tag::BitString.class(), Class::Universal);
388 assert_eq!(Tag::OctetString.class(), Class::Universal);
389 assert_eq!(Tag::Null.class(), Class::Universal);
390 assert_eq!(Tag::ObjectIdentifier.class(), Class::Universal);
391 assert_eq!(Tag::Enumerated.class(), Class::Universal);
392 assert_eq!(Tag::Utf8String.class(), Class::Universal);
393 assert_eq!(Tag::Set.class(), Class::Universal);
394 assert_eq!(Tag::NumericString.class(), Class::Universal);
395 assert_eq!(Tag::PrintableString.class(), Class::Universal);
396 assert_eq!(Tag::Ia5String.class(), Class::Universal);
397 assert_eq!(Tag::UtcTime.class(), Class::Universal);
398 assert_eq!(Tag::GeneralizedTime.class(), Class::Universal);
399 assert_eq!(Tag::Sequence.class(), Class::Universal);
400
401 for num in 0..=30 {
402 for &constructed in &[false, true] {
403 let number = TagNumber::new(num);
404
405 assert_eq!(
406 Tag::Application {
407 constructed,
408 number
409 }
410 .class(),
411 Class::Application
412 );
413
414 assert_eq!(
415 Tag::ContextSpecific {
416 constructed,
417 number
418 }
419 .class(),
420 Class::ContextSpecific
421 );
422
423 assert_eq!(
424 Tag::Private {
425 constructed,
426 number
427 }
428 .class(),
429 Class::Private
430 );
431 }
432 }
433 }
434}