1 //! ASN.1 tag numbers 2 3 use super::Tag; 4 use crate::{Error, ErrorKind, Result}; 5 use core::fmt; 6 7 /// ASN.1 tag numbers (i.e. lower 5 bits of a [`Tag`]). 8 /// 9 /// From X.690 Section 8.1.2.2: 10 /// 11 /// > bits 5 to 1 shall encode the number of the tag as a binary integer with 12 /// > bit 5 as the most significant bit. 13 /// 14 /// This library supports tag numbers ranging from zero to 30 (inclusive), 15 /// which can be represented as a single identifier octet. 16 /// 17 /// Section 8.1.2.4 describes how to support multi-byte tag numbers, which are 18 /// encoded by using a leading tag number of 31 (`0b11111`). This library 19 /// deliberately does not support this: tag numbers greater than 30 are 20 /// disallowed. 21 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 22 pub struct TagNumber(pub(super) u8); 23 24 impl TagNumber { 25 /// Tag number `0` 26 pub const N0: Self = Self(0); 27 28 /// Tag number `1` 29 pub const N1: Self = Self(1); 30 31 /// Tag number `2` 32 pub const N2: Self = Self(2); 33 34 /// Tag number `3` 35 pub const N3: Self = Self(3); 36 37 /// Tag number `4` 38 pub const N4: Self = Self(4); 39 40 /// Tag number `5` 41 pub const N5: Self = Self(5); 42 43 /// Tag number `6` 44 pub const N6: Self = Self(6); 45 46 /// Tag number `7` 47 pub const N7: Self = Self(7); 48 49 /// Tag number `8` 50 pub const N8: Self = Self(8); 51 52 /// Tag number `9` 53 pub const N9: Self = Self(9); 54 55 /// Tag number `10` 56 pub const N10: Self = Self(10); 57 58 /// Tag number `11` 59 pub const N11: Self = Self(11); 60 61 /// Tag number `12` 62 pub const N12: Self = Self(12); 63 64 /// Tag number `13` 65 pub const N13: Self = Self(13); 66 67 /// Tag number `14` 68 pub const N14: Self = Self(14); 69 70 /// Tag number `15` 71 pub const N15: Self = Self(15); 72 73 /// Tag number `16` 74 pub const N16: Self = Self(16); 75 76 /// Tag number `17` 77 pub const N17: Self = Self(17); 78 79 /// Tag number `18` 80 pub const N18: Self = Self(18); 81 82 /// Tag number `19` 83 pub const N19: Self = Self(19); 84 85 /// Tag number `20` 86 pub const N20: Self = Self(20); 87 88 /// Tag number `21` 89 pub const N21: Self = Self(21); 90 91 /// Tag number `22` 92 pub const N22: Self = Self(22); 93 94 /// Tag number `23` 95 pub const N23: Self = Self(23); 96 97 /// Tag number `24` 98 pub const N24: Self = Self(24); 99 100 /// Tag number `25` 101 pub const N25: Self = Self(25); 102 103 /// Tag number `26` 104 pub const N26: Self = Self(26); 105 106 /// Tag number `27` 107 pub const N27: Self = Self(27); 108 109 /// Tag number `28` 110 pub const N28: Self = Self(28); 111 112 /// Tag number `29` 113 pub const N29: Self = Self(29); 114 115 /// Tag number `30` 116 pub const N30: Self = Self(30); 117 118 /// Mask value used to obtain the tag number from a tag octet. 119 pub(super) const MASK: u8 = 0b11111; 120 121 /// Maximum tag number supported (inclusive). 122 const MAX: u8 = 30; 123 124 /// Create a new tag number (const-friendly). 125 /// 126 /// Panics if the tag number is greater than `30`. 127 /// For a fallible conversion, use [`TryFrom`] instead. new(byte: u8) -> Self128 pub const fn new(byte: u8) -> Self { 129 #[allow(clippy::panic)] 130 if byte > Self::MAX { 131 panic!("tag number out of range"); 132 } 133 134 Self(byte) 135 } 136 137 /// Create an `APPLICATION` tag with this tag number. application(self, constructed: bool) -> Tag138 pub fn application(self, constructed: bool) -> Tag { 139 Tag::Application { 140 constructed, 141 number: self, 142 } 143 } 144 145 /// Create a `CONTEXT-SPECIFIC` tag with this tag number. context_specific(self, constructed: bool) -> Tag146 pub fn context_specific(self, constructed: bool) -> Tag { 147 Tag::ContextSpecific { 148 constructed, 149 number: self, 150 } 151 } 152 153 /// Create a `PRIVATE` tag with this tag number. private(self, constructed: bool) -> Tag154 pub fn private(self, constructed: bool) -> Tag { 155 Tag::Private { 156 constructed, 157 number: self, 158 } 159 } 160 161 /// Get the inner value. value(self) -> u8162 pub fn value(self) -> u8 { 163 self.0 164 } 165 } 166 167 impl TryFrom<u8> for TagNumber { 168 type Error = Error; 169 try_from(byte: u8) -> Result<Self>170 fn try_from(byte: u8) -> Result<Self> { 171 match byte { 172 0..=Self::MAX => Ok(Self(byte)), 173 _ => Err(ErrorKind::TagNumberInvalid.into()), 174 } 175 } 176 } 177 178 impl From<TagNumber> for u8 { from(tag_number: TagNumber) -> u8179 fn from(tag_number: TagNumber) -> u8 { 180 tag_number.0 181 } 182 } 183 184 impl fmt::Display for TagNumber { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 186 write!(f, "{}", self.0) 187 } 188 } 189 190 // Implement by hand because the derive would create invalid values. 191 // Use the constructor to create a valid value. 192 #[cfg(feature = "arbitrary")] 193 impl<'a> arbitrary::Arbitrary<'a> for TagNumber { arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self>194 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { 195 Ok(Self::new(u.int_in_range(0..=Self::MAX)?)) 196 } 197 size_hint(depth: usize) -> (usize, Option<usize>)198 fn size_hint(depth: usize) -> (usize, Option<usize>) { 199 u8::size_hint(depth) 200 } 201 } 202