1#![cfg_attr(feature = "arbitrary", allow(clippy::integer_arithmetic))]
3
4mod class;
5mod mode;
6mod number;
7
8pub use self::{class::Class, mode::TagMode, number::TagNumber};
9
10use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Length, Reader, Result, Writer};
11use core::{cmp::Ordering, fmt};
12
13const CONSTRUCTED_FLAG: u8 = 0b100000;
15
16pub trait FixedTag {
18 const TAG: Tag;
20}
21
22pub trait Tagged {
24 fn tag(&self) -> Tag;
26}
27
28impl<T: FixedTag> Tagged for T {
30 fn tag(&self) -> Tag {
31 T::TAG
32 }
33}
34
35#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
51#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
52#[non_exhaustive]
53pub enum Tag {
54 Boolean,
56
57 Integer,
59
60 BitString,
62
63 OctetString,
65
66 Null,
68
69 ObjectIdentifier,
71
72 Real,
74
75 Enumerated,
77
78 Utf8String,
80
81 Sequence,
83
84 Set,
86
87 NumericString,
89
90 PrintableString,
92
93 TeletexString,
95
96 VideotexString,
98
99 Ia5String,
101
102 UtcTime,
104
105 GeneralizedTime,
107
108 VisibleString,
110
111 BmpString,
113
114 Application {
116 constructed: bool,
118
119 number: TagNumber,
121 },
122
123 ContextSpecific {
125 constructed: bool,
127
128 number: TagNumber,
130 },
131
132 Private {
134 constructed: bool,
136
137 number: TagNumber,
139 },
140}
141
142impl Tag {
143 pub fn assert_eq(self, expected: Tag) -> Result<Tag> {
147 if self == expected {
148 Ok(self)
149 } else {
150 Err(self.unexpected_error(Some(expected)))
151 }
152 }
153
154 pub fn class(self) -> Class {
156 match self {
157 Tag::Application { .. } => Class::Application,
158 Tag::ContextSpecific { .. } => Class::ContextSpecific,
159 Tag::Private { .. } => Class::Private,
160 _ => Class::Universal,
161 }
162 }
163
164 pub fn number(self) -> TagNumber {
166 TagNumber(self.octet() & TagNumber::MASK)
167 }
168
169 pub fn is_constructed(self) -> bool {
171 self.octet() & CONSTRUCTED_FLAG != 0
172 }
173
174 pub fn is_application(self) -> bool {
176 self.class() == Class::Application
177 }
178
179 pub fn is_context_specific(self) -> bool {
181 self.class() == Class::ContextSpecific
182 }
183
184 pub fn is_private(self) -> bool {
186 self.class() == Class::Private
187 }
188
189 pub fn is_universal(self) -> bool {
191 self.class() == Class::Universal
192 }
193
194 pub fn octet(self) -> u8 {
196 match self {
197 Tag::Boolean => 0x01,
198 Tag::Integer => 0x02,
199 Tag::BitString => 0x03,
200 Tag::OctetString => 0x04,
201 Tag::Null => 0x05,
202 Tag::ObjectIdentifier => 0x06,
203 Tag::Real => 0x09,
204 Tag::Enumerated => 0x0A,
205 Tag::Utf8String => 0x0C,
206 Tag::Sequence => 0x10 | CONSTRUCTED_FLAG,
207 Tag::Set => 0x11 | CONSTRUCTED_FLAG,
208 Tag::NumericString => 0x12,
209 Tag::PrintableString => 0x13,
210 Tag::TeletexString => 0x14,
211 Tag::VideotexString => 0x15,
212 Tag::Ia5String => 0x16,
213 Tag::UtcTime => 0x17,
214 Tag::GeneralizedTime => 0x18,
215 Tag::VisibleString => 0x1A,
216 Tag::BmpString => 0x1E,
217 Tag::Application {
218 constructed,
219 number,
220 }
221 | Tag::ContextSpecific {
222 constructed,
223 number,
224 }
225 | Tag::Private {
226 constructed,
227 number,
228 } => self.class().octet(constructed, number),
229 }
230 }
231
232 pub fn length_error(self) -> Error {
234 ErrorKind::Length { tag: self }.into()
235 }
236
237 pub fn non_canonical_error(self) -> Error {
240 ErrorKind::Noncanonical { tag: self }.into()
241 }
242
243 pub fn unexpected_error(self, expected: Option<Self>) -> Error {
246 ErrorKind::TagUnexpected {
247 expected,
248 actual: self,
249 }
250 .into()
251 }
252
253 pub fn value_error(self) -> Error {
256 ErrorKind::Value { tag: self }.into()
257 }
258}
259
260impl TryFrom<u8> for Tag {
261 type Error = Error;
262
263 fn try_from(byte: u8) -> Result<Tag> {
264 let constructed = byte & CONSTRUCTED_FLAG != 0;
265 let number = TagNumber::try_from(byte & TagNumber::MASK)?;
266
267 match byte {
268 0x01 => Ok(Tag::Boolean),
269 0x02 => Ok(Tag::Integer),
270 0x03 => Ok(Tag::BitString),
271 0x04 => Ok(Tag::OctetString),
272 0x05 => Ok(Tag::Null),
273 0x06 => Ok(Tag::ObjectIdentifier),
274 0x09 => Ok(Tag::Real),
275 0x0A => Ok(Tag::Enumerated),
276 0x0C => Ok(Tag::Utf8String),
277 0x12 => Ok(Tag::NumericString),
278 0x13 => Ok(Tag::PrintableString),
279 0x14 => Ok(Tag::TeletexString),
280 0x15 => Ok(Tag::VideotexString),
281 0x16 => Ok(Tag::Ia5String),
282 0x17 => Ok(Tag::UtcTime),
283 0x18 => Ok(Tag::GeneralizedTime),
284 0x1A => Ok(Tag::VisibleString),
285 0x1E => Ok(Tag::BmpString),
286 0x30 => Ok(Tag::Sequence), 0x31 => Ok(Tag::Set), 0x40..=0x7E => Ok(Tag::Application {
289 constructed,
290 number,
291 }),
292 0x80..=0xBE => Ok(Tag::ContextSpecific {
293 constructed,
294 number,
295 }),
296 0xC0..=0xFE => Ok(Tag::Private {
297 constructed,
298 number,
299 }),
300 _ => Err(ErrorKind::TagUnknown { byte }.into()),
301 }
302 }
303}
304
305impl From<Tag> for u8 {
306 fn from(tag: Tag) -> u8 {
307 tag.octet()
308 }
309}
310
311impl From<&Tag> for u8 {
312 fn from(tag: &Tag) -> u8 {
313 u8::from(*tag)
314 }
315}
316
317impl<'a> Decode<'a> for Tag {
318 fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> {
319 reader.read_byte().and_then(Self::try_from)
320 }
321}
322
323impl Encode for Tag {
324 fn encoded_len(&self) -> Result<Length> {
325 Ok(Length::ONE)
326 }
327
328 fn encode(&self, writer: &mut impl Writer) -> Result<()> {
329 writer.write_byte(self.into())
330 }
331}
332
333impl DerOrd for Tag {
334 fn der_cmp(&self, other: &Self) -> Result<Ordering> {
335 Ok(self.octet().cmp(&other.octet()))
336 }
337}
338
339impl fmt::Display for Tag {
340 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
341 const FIELD_TYPE: [&str; 2] = ["primitive", "constructed"];
342
343 match *self {
344 Tag::Boolean => f.write_str("BOOLEAN"),
345 Tag::Integer => f.write_str("INTEGER"),
346 Tag::BitString => f.write_str("BIT STRING"),
347 Tag::OctetString => f.write_str("OCTET STRING"),
348 Tag::Null => f.write_str("NULL"),
349 Tag::ObjectIdentifier => f.write_str("OBJECT IDENTIFIER"),
350 Tag::Real => f.write_str("REAL"),
351 Tag::Enumerated => f.write_str("ENUMERATED"),
352 Tag::Utf8String => f.write_str("UTF8String"),
353 Tag::Set => f.write_str("SET"),
354 Tag::NumericString => f.write_str("NumericString"),
355 Tag::PrintableString => f.write_str("PrintableString"),
356 Tag::TeletexString => f.write_str("TeletexString"),
357 Tag::VideotexString => f.write_str("VideotexString"),
358 Tag::Ia5String => f.write_str("IA5String"),
359 Tag::UtcTime => f.write_str("UTCTime"),
360 Tag::GeneralizedTime => f.write_str("GeneralizedTime"),
361 Tag::VisibleString => f.write_str("VisibleString"),
362 Tag::BmpString => f.write_str("BMPString"),
363 Tag::Sequence => f.write_str("SEQUENCE"),
364 Tag::Application {
365 constructed,
366 number,
367 } => write!(
368 f,
369 "APPLICATION [{}] ({})",
370 number,
371 FIELD_TYPE[usize::from(constructed)]
372 ),
373 Tag::ContextSpecific {
374 constructed,
375 number,
376 } => write!(
377 f,
378 "CONTEXT-SPECIFIC [{}] ({})",
379 number,
380 FIELD_TYPE[usize::from(constructed)]
381 ),
382 Tag::Private {
383 constructed,
384 number,
385 } => write!(
386 f,
387 "PRIVATE [{}] ({})",
388 number,
389 FIELD_TYPE[usize::from(constructed)]
390 ),
391 }
392 }
393}
394
395impl fmt::Debug for Tag {
396 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
397 write!(f, "Tag(0x{:02x}: {})", u8::from(*self), self)
398 }
399}
400
401#[cfg(test)]
402mod tests {
403 use super::TagNumber;
404 use super::{Class, Tag};
405
406 #[test]
407 fn tag_class() {
408 assert_eq!(Tag::Boolean.class(), Class::Universal);
409 assert_eq!(Tag::Integer.class(), Class::Universal);
410 assert_eq!(Tag::BitString.class(), Class::Universal);
411 assert_eq!(Tag::OctetString.class(), Class::Universal);
412 assert_eq!(Tag::Null.class(), Class::Universal);
413 assert_eq!(Tag::ObjectIdentifier.class(), Class::Universal);
414 assert_eq!(Tag::Real.class(), Class::Universal);
415 assert_eq!(Tag::Enumerated.class(), Class::Universal);
416 assert_eq!(Tag::Utf8String.class(), Class::Universal);
417 assert_eq!(Tag::Set.class(), Class::Universal);
418 assert_eq!(Tag::NumericString.class(), Class::Universal);
419 assert_eq!(Tag::PrintableString.class(), Class::Universal);
420 assert_eq!(Tag::TeletexString.class(), Class::Universal);
421 assert_eq!(Tag::VideotexString.class(), Class::Universal);
422 assert_eq!(Tag::Ia5String.class(), Class::Universal);
423 assert_eq!(Tag::UtcTime.class(), Class::Universal);
424 assert_eq!(Tag::GeneralizedTime.class(), Class::Universal);
425 assert_eq!(Tag::Sequence.class(), Class::Universal);
426
427 for num in 0..=30 {
428 for &constructed in &[false, true] {
429 let number = TagNumber::new(num);
430
431 assert_eq!(
432 Tag::Application {
433 constructed,
434 number
435 }
436 .class(),
437 Class::Application
438 );
439
440 assert_eq!(
441 Tag::ContextSpecific {
442 constructed,
443 number
444 }
445 .class(),
446 Class::ContextSpecific
447 );
448
449 assert_eq!(
450 Tag::Private {
451 constructed,
452 number
453 }
454 .class(),
455 Class::Private
456 );
457 }
458 }
459 }
460}