1mod class;
4mod mode;
5mod number;
6
7pub use self::{class::Class, mode::TagMode, number::TagNumber};
8
9use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Length, Reader, Result, Writer};
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 Real,
72
73 Enumerated,
75
76 Utf8String,
78
79 Sequence,
81
82 Set,
84
85 NumericString,
87
88 PrintableString,
90
91 TeletexString,
93
94 VideotexString,
96
97 Ia5String,
99
100 UtcTime,
102
103 GeneralizedTime,
105
106 VisibleString,
108
109 BmpString,
111
112 Application {
114 constructed: bool,
116
117 number: TagNumber,
119 },
120
121 ContextSpecific {
123 constructed: bool,
125
126 number: TagNumber,
128 },
129
130 Private {
132 constructed: bool,
134
135 number: TagNumber,
137 },
138}
139
140impl Tag {
141 pub fn assert_eq(self, expected: Tag) -> Result<Tag> {
145 if self == expected {
146 Ok(self)
147 } else {
148 Err(self.unexpected_error(Some(expected)))
149 }
150 }
151
152 pub fn class(self) -> Class {
154 match self {
155 Tag::Application { .. } => Class::Application,
156 Tag::ContextSpecific { .. } => Class::ContextSpecific,
157 Tag::Private { .. } => Class::Private,
158 _ => Class::Universal,
159 }
160 }
161
162 pub fn number(self) -> TagNumber {
164 TagNumber(self.octet() & TagNumber::MASK)
165 }
166
167 pub fn is_constructed(self) -> bool {
169 self.octet() & CONSTRUCTED_FLAG != 0
170 }
171
172 pub fn is_application(self) -> bool {
174 self.class() == Class::Application
175 }
176
177 pub fn is_context_specific(self) -> bool {
179 self.class() == Class::ContextSpecific
180 }
181
182 pub fn is_private(self) -> bool {
184 self.class() == Class::Private
185 }
186
187 pub fn is_universal(self) -> bool {
189 self.class() == Class::Universal
190 }
191
192 pub fn octet(self) -> u8 {
194 match self {
195 Tag::Boolean => 0x01,
196 Tag::Integer => 0x02,
197 Tag::BitString => 0x03,
198 Tag::OctetString => 0x04,
199 Tag::Null => 0x05,
200 Tag::ObjectIdentifier => 0x06,
201 Tag::Real => 0x09,
202 Tag::Enumerated => 0x0A,
203 Tag::Utf8String => 0x0C,
204 Tag::Sequence => 0x10 | CONSTRUCTED_FLAG,
205 Tag::Set => 0x11 | CONSTRUCTED_FLAG,
206 Tag::NumericString => 0x12,
207 Tag::PrintableString => 0x13,
208 Tag::TeletexString => 0x14,
209 Tag::VideotexString => 0x15,
210 Tag::Ia5String => 0x16,
211 Tag::UtcTime => 0x17,
212 Tag::GeneralizedTime => 0x18,
213 Tag::VisibleString => 0x1A,
214 Tag::BmpString => 0x1D,
215 Tag::Application {
216 constructed,
217 number,
218 }
219 | Tag::ContextSpecific {
220 constructed,
221 number,
222 }
223 | Tag::Private {
224 constructed,
225 number,
226 } => self.class().octet(constructed, number),
227 }
228 }
229
230 pub fn length_error(self) -> Error {
232 ErrorKind::Length { tag: self }.into()
233 }
234
235 pub fn non_canonical_error(self) -> Error {
238 ErrorKind::Noncanonical { tag: self }.into()
239 }
240
241 pub fn unexpected_error(self, expected: Option<Self>) -> Error {
244 ErrorKind::TagUnexpected {
245 expected,
246 actual: self,
247 }
248 .into()
249 }
250
251 pub fn value_error(self) -> Error {
254 ErrorKind::Value { tag: self }.into()
255 }
256}
257
258impl TryFrom<u8> for Tag {
259 type Error = Error;
260
261 fn try_from(byte: u8) -> Result<Tag> {
262 let constructed = byte & CONSTRUCTED_FLAG != 0;
263 let number = TagNumber::try_from(byte & TagNumber::MASK)?;
264
265 match byte {
266 0x01 => Ok(Tag::Boolean),
267 0x02 => Ok(Tag::Integer),
268 0x03 => Ok(Tag::BitString),
269 0x04 => Ok(Tag::OctetString),
270 0x05 => Ok(Tag::Null),
271 0x06 => Ok(Tag::ObjectIdentifier),
272 0x09 => Ok(Tag::Real),
273 0x0A => Ok(Tag::Enumerated),
274 0x0C => Ok(Tag::Utf8String),
275 0x12 => Ok(Tag::NumericString),
276 0x13 => Ok(Tag::PrintableString),
277 0x14 => Ok(Tag::TeletexString),
278 0x15 => Ok(Tag::VideotexString),
279 0x16 => Ok(Tag::Ia5String),
280 0x17 => Ok(Tag::UtcTime),
281 0x18 => Ok(Tag::GeneralizedTime),
282 0x1A => Ok(Tag::VisibleString),
283 0x1d => Ok(Tag::BmpString),
284 0x30 => Ok(Tag::Sequence), 0x31 => Ok(Tag::Set), 0x40..=0x7E => Ok(Tag::Application {
287 constructed,
288 number,
289 }),
290 0x80..=0xBE => Ok(Tag::ContextSpecific {
291 constructed,
292 number,
293 }),
294 0xC0..=0xFE => Ok(Tag::Private {
295 constructed,
296 number,
297 }),
298 _ => Err(ErrorKind::TagUnknown { byte }.into()),
299 }
300 }
301}
302
303impl From<Tag> for u8 {
304 fn from(tag: Tag) -> u8 {
305 tag.octet()
306 }
307}
308
309impl From<&Tag> for u8 {
310 fn from(tag: &Tag) -> u8 {
311 u8::from(*tag)
312 }
313}
314
315impl<'a> Decode<'a> for Tag {
316 fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> {
317 reader.read_byte().and_then(Self::try_from)
318 }
319}
320
321impl Encode for Tag {
322 fn encoded_len(&self) -> Result<Length> {
323 Ok(Length::ONE)
324 }
325
326 fn encode(&self, writer: &mut dyn Writer) -> Result<()> {
327 writer.write_byte(self.into())
328 }
329}
330
331impl DerOrd for Tag {
332 fn der_cmp(&self, other: &Self) -> Result<Ordering> {
333 Ok(self.octet().cmp(&other.octet()))
334 }
335}
336
337impl fmt::Display for Tag {
338 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
339 const FIELD_TYPE: [&str; 2] = ["primitive", "constructed"];
340
341 match *self {
342 Tag::Boolean => f.write_str("BOOLEAN"),
343 Tag::Integer => f.write_str("INTEGER"),
344 Tag::BitString => f.write_str("BIT STRING"),
345 Tag::OctetString => f.write_str("OCTET STRING"),
346 Tag::Null => f.write_str("NULL"),
347 Tag::ObjectIdentifier => f.write_str("OBJECT IDENTIFIER"),
348 Tag::Real => f.write_str("REAL"),
349 Tag::Enumerated => f.write_str("ENUMERATED"),
350 Tag::Utf8String => f.write_str("UTF8String"),
351 Tag::Set => f.write_str("SET"),
352 Tag::NumericString => f.write_str("NumericString"),
353 Tag::PrintableString => f.write_str("PrintableString"),
354 Tag::TeletexString => f.write_str("TeletexString"),
355 Tag::VideotexString => f.write_str("VideotexString"),
356 Tag::Ia5String => f.write_str("IA5String"),
357 Tag::UtcTime => f.write_str("UTCTime"),
358 Tag::GeneralizedTime => f.write_str("GeneralizedTime"),
359 Tag::VisibleString => f.write_str("VisibleString"),
360 Tag::BmpString => f.write_str("BMPString"),
361 Tag::Sequence => f.write_str("SEQUENCE"),
362 Tag::Application {
363 constructed,
364 number,
365 } => write!(
366 f,
367 "APPLICATION [{}] ({})",
368 number,
369 FIELD_TYPE[usize::from(constructed)]
370 ),
371 Tag::ContextSpecific {
372 constructed,
373 number,
374 } => write!(
375 f,
376 "CONTEXT-SPECIFIC [{}] ({})",
377 number,
378 FIELD_TYPE[usize::from(constructed)]
379 ),
380 Tag::Private {
381 constructed,
382 number,
383 } => write!(
384 f,
385 "PRIVATE [{}] ({})",
386 number,
387 FIELD_TYPE[usize::from(constructed)]
388 ),
389 }
390 }
391}
392
393impl fmt::Debug for Tag {
394 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
395 write!(f, "Tag(0x{:02x}: {})", u8::from(*self), self)
396 }
397}
398
399#[cfg(test)]
400mod tests {
401 use super::TagNumber;
402 use super::{Class, Tag};
403
404 #[test]
405 fn tag_class() {
406 assert_eq!(Tag::Boolean.class(), Class::Universal);
407 assert_eq!(Tag::Integer.class(), Class::Universal);
408 assert_eq!(Tag::BitString.class(), Class::Universal);
409 assert_eq!(Tag::OctetString.class(), Class::Universal);
410 assert_eq!(Tag::Null.class(), Class::Universal);
411 assert_eq!(Tag::ObjectIdentifier.class(), Class::Universal);
412 assert_eq!(Tag::Real.class(), Class::Universal);
413 assert_eq!(Tag::Enumerated.class(), Class::Universal);
414 assert_eq!(Tag::Utf8String.class(), Class::Universal);
415 assert_eq!(Tag::Set.class(), Class::Universal);
416 assert_eq!(Tag::NumericString.class(), Class::Universal);
417 assert_eq!(Tag::PrintableString.class(), Class::Universal);
418 assert_eq!(Tag::TeletexString.class(), Class::Universal);
419 assert_eq!(Tag::VideotexString.class(), Class::Universal);
420 assert_eq!(Tag::Ia5String.class(), Class::Universal);
421 assert_eq!(Tag::UtcTime.class(), Class::Universal);
422 assert_eq!(Tag::GeneralizedTime.class(), Class::Universal);
423 assert_eq!(Tag::Sequence.class(), Class::Universal);
424
425 for num in 0..=30 {
426 for &constructed in &[false, true] {
427 let number = TagNumber::new(num);
428
429 assert_eq!(
430 Tag::Application {
431 constructed,
432 number
433 }
434 .class(),
435 Class::Application
436 );
437
438 assert_eq!(
439 Tag::ContextSpecific {
440 constructed,
441 number
442 }
443 .class(),
444 Class::ContextSpecific
445 );
446
447 assert_eq!(
448 Tag::Private {
449 constructed,
450 number
451 }
452 .class(),
453 Class::Private
454 );
455 }
456 }
457 }
458}