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