1 //! ASN.1 tags. 2 3 mod class; 4 mod mode; 5 mod number; 6 7 pub use self::{class::Class, mode::TagMode, number::TagNumber}; 8 9 use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Length, Reader, Result, Writer}; 10 use core::{cmp::Ordering, fmt}; 11 12 /// Indicator bit for constructed form encoding (i.e. vs primitive form) 13 const CONSTRUCTED_FLAG: u8 = 0b100000; 14 15 /// Types which have a constant ASN.1 [`Tag`]. 16 pub trait FixedTag { 17 /// ASN.1 tag 18 const TAG: Tag; 19 } 20 21 /// Types which have an ASN.1 [`Tag`]. 22 pub trait Tagged { 23 /// Get the ASN.1 tag that this type is encoded with. tag(&self) -> Tag24 fn tag(&self) -> Tag; 25 } 26 27 /// Types which are [`FixedTag`] always have a known [`Tag`] type. 28 impl<T: FixedTag> Tagged for T { tag(&self) -> Tag29 fn tag(&self) -> Tag { 30 T::TAG 31 } 32 } 33 34 /// ASN.1 tags. 35 /// 36 /// Tags are the leading identifier octet of the Tag-Length-Value encoding 37 /// used by ASN.1 DER and identify the type of the subsequent value. 38 /// 39 /// They are described in X.690 Section 8.1.2: Identifier octets, and 40 /// structured as follows: 41 /// 42 /// ```text 43 /// | Class | P/C | Tag Number | 44 /// ``` 45 /// 46 /// - Bits 8/7: [`Class`] 47 /// - Bit 6: primitive (0) or constructed (1) 48 /// - Bits 5-1: tag number 49 #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] 50 #[non_exhaustive] 51 pub enum Tag { 52 /// `BOOLEAN` tag: `1`. 53 Boolean, 54 55 /// `INTEGER` tag: `2`. 56 Integer, 57 58 /// `BIT STRING` tag: `3`. 59 BitString, 60 61 /// `OCTET STRING` tag: `4`. 62 OctetString, 63 64 /// `NULL` tag: `5`. 65 Null, 66 67 /// `OBJECT IDENTIFIER` tag: `6`. 68 ObjectIdentifier, 69 70 /// `REAL` tag: `9`. 71 Real, 72 73 /// `ENUMERATED` tag: `10`. 74 Enumerated, 75 76 /// `UTF8String` tag: `12`. 77 Utf8String, 78 79 /// `SEQUENCE` tag: `16`. 80 Sequence, 81 82 /// `SET` and `SET OF` tag: `17`. 83 Set, 84 85 /// `NumericString` tag: `18`. 86 NumericString, 87 88 /// `PrintableString` tag: `19`. 89 PrintableString, 90 91 /// `TeletexString` tag: `20`. 92 TeletexString, 93 94 /// `VideotexString` tag: `21`. 95 VideotexString, 96 97 /// `IA5String` tag: `22`. 98 Ia5String, 99 100 /// `UTCTime` tag: `23`. 101 UtcTime, 102 103 /// `GeneralizedTime` tag: `24`. 104 GeneralizedTime, 105 106 /// `VisibleString` tag: `26`. 107 VisibleString, 108 109 /// `BMPString` tag: `30`. 110 BmpString, 111 112 /// Application tag. 113 Application { 114 /// Is this tag constructed? (vs primitive). 115 constructed: bool, 116 117 /// Tag number. 118 number: TagNumber, 119 }, 120 121 /// Context-specific tag. 122 ContextSpecific { 123 /// Is this tag constructed? (vs primitive). 124 constructed: bool, 125 126 /// Tag number. 127 number: TagNumber, 128 }, 129 130 /// Private tag number. 131 Private { 132 /// Is this tag constructed? (vs primitive). 133 constructed: bool, 134 135 /// Tag number. 136 number: TagNumber, 137 }, 138 } 139 140 impl Tag { 141 /// Assert that this [`Tag`] matches the provided expected tag. 142 /// 143 /// On mismatch, returns an [`Error`] with [`ErrorKind::TagUnexpected`]. assert_eq(self, expected: Tag) -> Result<Tag>144 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 /// Get the [`Class`] that corresponds to this [`Tag`]. class(self) -> Class153 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 /// Get the [`TagNumber`] (lower 6-bits) for this tag. number(self) -> TagNumber163 pub fn number(self) -> TagNumber { 164 TagNumber(self.octet() & TagNumber::MASK) 165 } 166 167 /// Does this tag represent a constructed (as opposed to primitive) field? is_constructed(self) -> bool168 pub fn is_constructed(self) -> bool { 169 self.octet() & CONSTRUCTED_FLAG != 0 170 } 171 172 /// Is this an application tag? is_application(self) -> bool173 pub fn is_application(self) -> bool { 174 self.class() == Class::Application 175 } 176 177 /// Is this a context-specific tag? is_context_specific(self) -> bool178 pub fn is_context_specific(self) -> bool { 179 self.class() == Class::ContextSpecific 180 } 181 182 /// Is this a private tag? is_private(self) -> bool183 pub fn is_private(self) -> bool { 184 self.class() == Class::Private 185 } 186 187 /// Is this a universal tag? is_universal(self) -> bool188 pub fn is_universal(self) -> bool { 189 self.class() == Class::Universal 190 } 191 192 /// Get the octet encoding for this [`Tag`]. octet(self) -> u8193 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 /// Create an [`Error`] for an invalid [`Length`]. length_error(self) -> Error231 pub fn length_error(self) -> Error { 232 ErrorKind::Length { tag: self }.into() 233 } 234 235 /// Create an [`Error`] for an non-canonical value with the ASN.1 type 236 /// identified by this tag. non_canonical_error(self) -> Error237 pub fn non_canonical_error(self) -> Error { 238 ErrorKind::Noncanonical { tag: self }.into() 239 } 240 241 /// Create an [`Error`] because the current tag was unexpected, with an 242 /// optional expected tag. unexpected_error(self, expected: Option<Self>) -> Error243 pub fn unexpected_error(self, expected: Option<Self>) -> Error { 244 ErrorKind::TagUnexpected { 245 expected, 246 actual: self, 247 } 248 .into() 249 } 250 251 /// Create an [`Error`] for an invalid value with the ASN.1 type identified 252 /// by this tag. value_error(self) -> Error253 pub fn value_error(self) -> Error { 254 ErrorKind::Value { tag: self }.into() 255 } 256 } 257 258 impl TryFrom<u8> for Tag { 259 type Error = Error; 260 try_from(byte: u8) -> Result<Tag>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), // constructed 285 0x31 => Ok(Tag::Set), // constructed 286 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 303 impl From<Tag> for u8 { from(tag: Tag) -> u8304 fn from(tag: Tag) -> u8 { 305 tag.octet() 306 } 307 } 308 309 impl From<&Tag> for u8 { from(tag: &Tag) -> u8310 fn from(tag: &Tag) -> u8 { 311 u8::from(*tag) 312 } 313 } 314 315 impl<'a> Decode<'a> for Tag { decode<R: Reader<'a>>(reader: &mut R) -> Result<Self>316 fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> { 317 reader.read_byte().and_then(Self::try_from) 318 } 319 } 320 321 impl Encode for Tag { encoded_len(&self) -> Result<Length>322 fn encoded_len(&self) -> Result<Length> { 323 Ok(Length::ONE) 324 } 325 encode(&self, writer: &mut dyn Writer) -> Result<()>326 fn encode(&self, writer: &mut dyn Writer) -> Result<()> { 327 writer.write_byte(self.into()) 328 } 329 } 330 331 impl DerOrd for Tag { der_cmp(&self, other: &Self) -> Result<Ordering>332 fn der_cmp(&self, other: &Self) -> Result<Ordering> { 333 Ok(self.octet().cmp(&other.octet())) 334 } 335 } 336 337 impl fmt::Display for Tag { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result338 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 393 impl fmt::Debug for Tag { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result394 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)] 400 mod tests { 401 use super::TagNumber; 402 use super::{Class, Tag}; 403 404 #[test] tag_class()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 } 459