1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
//! The identifer octets of a BER encoded value.
//!
//! This is a private module. Its public items are re-exported by the parent.
use std::{fmt, io};
use super::decode;
//------------ Tag -----------------------------------------------------------
/// The tag of a BER encoded value.
///
/// Each BER encoded value starts with a sequence of one or more octets called
/// the _identifier octets._ They encode both the tag of the value as well as
/// whether the value uses primitive or constructed encoding. The `Tag` type
/// represents the tag only. The distinction between primitive and constructed
/// encoding is captured by the decoder types [`Primitive`] and
/// [`Constructed`] instead.
///
/// The tag in turn consists of two parts: the class and the number – the
/// `Tag` type includes both of them.
///
/// At the moment, you can only compare two tags. All necessary values are
/// defined as associated constants; there is no other way to create new tag
/// values.
///
/// # Limitations
///
/// At this time, we can only decode single-octet identifier octets. That is,
/// we only support tag numbers between 0 and 30.
///
/// [`Primitive`]: decode/struct.Primitive.html
/// [`Constructed`]: decode/struct.Constructed.html
//
// For the moment, the tag is stored as a single `u8` with the constructed
// bit always cleared.
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Tag(u8);
/// # Constants for Often Used Tag Values
///
impl Tag {
/// The mask for checking the class.
const CLASS_MASK: u8 = 0xc0;
/// The tag value representing for the ‘universal’ class.
const UNIVERSAL: u8 = 0x00;
/// The tag value representing the ‘application’ class.
const APPLICATION: u8 = 0x40;
/// The tag value representing the ‘context-specific’ class.
const CONTEXT_SPECIFIC: u8 = 0x80;
/// The tag value representing the `private` class.
const PRIVATE: u8 = 0xc0;
/// The tag marking the end-of-value in an indefinite length value.
///
/// This is UNIVERSAL 0.
pub const END_OF_VALUE: Self = Tag(0);
//--- Universal Tags
//
// See clause 8.4 of X.690.
/// The tag for the BOOLEAN type, UNIVERSAL 1.
pub const BOOLEAN: Self = Tag(1);
/// The tag for the INTEGER type, UNIVERSAL 2.
pub const INTEGER: Self = Tag(2);
/// The tag for the BIT STRING type, UNIVERSAL 3.
pub const BIT_STRING: Self = Tag(3);
/// The tag for the OCTET STRING type, UNIVERSAL 4.
pub const OCTET_STRING: Self = Tag(4);
/// The tag for the NULL type, UNIVERSAL 5.
pub const NULL: Self = Tag(5);
/// The tag for the OBJECT IDENTIFIER type, UNIVERSAL 6.
pub const OID: Self = Tag(6);
/// The tag for the ObjectDescriptor type, UNIVERSAL 7.
pub const OBJECT_DESCRIPTOR: Self = Tag(7);
/// The tag for the EXTERNAL and Instance-of types, UNIVERSAL 8.
pub const EXTERNAL: Self = Tag(8);
/// The tag for the REAL type, UNIVERSAL 9.
pub const REAL: Self = Tag(9);
/// The tag for the ENUMERATED type, UNIVERAL 10.
pub const ENUMERATED: Self = Tag(10);
/// The tag for the EMBEDDED PDV type, UNIVERAL 11.
pub const EMBEDDED_PDV: Self = Tag(11);
/// The tag for the UTF8String type, UNIVERSAL 12
pub const UTF8_STRING: Self = Tag(12);
/// The tag for the RELATIVE-OID type, UNIVERAL 13.
pub const RELATIVE_OID: Self = Tag(13);
/// The tag for the SEQUENCE and SEQUENCE OF types, UNIVERSAL 16.
pub const SEQUENCE: Self = Tag(16);
/// The tag for the SET and SET OF types, UNIVERSAL 17.
pub const SET: Self = Tag(17);
/// The tag for the NumericString type, UNIVERSAL 18.
pub const NUMERIC_STRING: Self = Tag(18);
/// The tag for the PrintableString type, UNIVERSAL 19.
pub const PRINTABLE_STRING: Self = Tag(19);
/// The tag for the TeletexString type, UNIVERSAL 20.
pub const TELETEX_STRING: Self = Tag(20);
/// The tag for the VideotexString type, UNIVERSAL 21.
pub const VIDEOTEX_STRING: Self = Tag(21);
/// The tag for the IA5String type, UNIVERSAL 22.
pub const IA5_STRING: Self = Tag(22);
/// The tag for the UTCTime type, UNIVERSAL 23.
pub const UTC_TIME: Self = Tag(23);
/// The tag for the GeneralizedType type, UNIVERAL 24.
pub const GENERALIZED_TIME: Self = Tag(24);
/// The tag for the GraphicString type, UNIVERSAL 25.
pub const GRAPHIC_STRING: Self = Tag(25);
/// The tag for the VisibleString type, UNIVERSAL 26.
pub const VISIBLE_STRING: Self = Tag(26);
/// The tag for the GeneralString type, UNIVERSAL 27.
pub const GENERAL_STRING: Self = Tag(27);
/// The tag for the UniversalString type, UNIVERSAL 28.
pub const UNIVERSAL_STRING: Self = Tag(28);
/// The tag for the BMPString type, UNIVERSAL 29.
pub const BMP_STRING: Self = Tag(29);
/// The tag context specific tag [0].
pub const CTX_0: Self = Tag(Tag::CONTEXT_SPECIFIC | 0);
/// The tag context specific tag [1].
pub const CTX_1: Self = Tag(Tag::CONTEXT_SPECIFIC | 1);
/// The tag context specific tag [2].
pub const CTX_2: Self = Tag(Tag::CONTEXT_SPECIFIC | 2);
/// The tag context specific tag [3].
pub const CTX_3: Self = Tag(Tag::CONTEXT_SPECIFIC | 3);
/// The tag context specific tag [4].
pub const CTX_4: Self = Tag(Tag::CONTEXT_SPECIFIC | 4);
/// The tag context specific tag [5].
pub const CTX_5: Self = Tag(Tag::CONTEXT_SPECIFIC | 5);
/// The tag context specific tag [6].
pub const CTX_6: Self = Tag(Tag::CONTEXT_SPECIFIC | 6);
}
impl Tag {
/// Creates a new tag in the universal class with the given tag number.
///
/// # Panics
///
/// Currently, this function panics if the tag number is greater than
/// 30.
pub fn universal(number: u8) -> Self {
assert!(number < 31);
Tag(number)
}
/// Creates a new tag in the application class with the given tag number.
///
/// # Panics
///
/// Currently, this function panics if the tag number is greater than
/// 30.
pub fn application(number: u8) -> Self {
assert!(number < 31);
Tag(Tag::APPLICATION | number)
}
/// Creates a new tag in the context specific class.
///
/// # Panics
///
/// Currently, this function panics if the provided tag number is greater
/// than 30.
pub fn context_specific(number: u8) -> Self {
assert!(number < 31);
Tag(Tag::CONTEXT_SPECIFIC| number)
}
/// Creates a new tag in the private class with the given tag number.
///
/// # Panics
///
/// Currently, this function panics if the provided tag number is greater
/// than 30.
pub fn private(number: u8) -> Self {
assert!(number < 31);
Tag(Tag::PRIVATE | number)
}
/// Takes a tag from the beginning of a source.
///
/// Upon success, returns both the tag and whether the value is
/// constructed. If there are no more octets available in the source,
/// an error is returned.
pub fn take_from<S: decode::Source>(
source: &mut S,
) -> Result<(Self, bool), S::Err> {
let byte = source.take_u8()?;
if (byte & 0x1F) == 0x1F {
// If all five lower bits are 1, the tag is encoded in multiple
// bytes. We don’t support that.
xerr!(return Err(decode::Error::Unimplemented.into()))
}
Ok((Tag(byte & 0xdf), byte & 0x20 != 0))
}
/// Takes a tag from the beginning of a resource if it matches this tag.
///
/// If there is no more data available in the source or if the tag is
/// something else, returns `Ok(None)`. If the tag matches `self`, returns
/// whether the value is constructed.
pub fn take_from_if<S: decode::Source>(
self,
source: &mut S,
) -> Result<Option<bool>, S::Err> {
if source.request(1)? == 0 {
return Ok(None)
}
let byte = source.slice()[0];
let (tag, compressed) = (Tag(byte & 0xdf), byte & 0x20 != 0);
if tag == self {
source.advance(1)?;
Ok(Some(compressed))
}
else {
Ok(None)
}
}
/// Returns the number of octets of the encoded form of the tag.
pub fn encoded_len(&self) -> usize {
1
}
/// Encodes the tag into a target.
///
/// If `constructed` is `true`, the encoded tag will signal a value in
/// constructed encoding and primitive encoding otherwise.
pub fn write_encoded<W: io::Write>(
&self,
constructed: bool,
target: &mut W
) -> Result<(), io::Error> {
let mut buf = [self.0];
if constructed {
buf[0] |= 0x20
}
target.write_all(&buf)
}
}
impl fmt::Display for Tag {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Tag::BOOLEAN => write!(f, "BOOLEAN"),
Tag::INTEGER => write!(f, "INTEGER"),
Tag::BIT_STRING => write!(f, "BIT STRING"),
Tag::OCTET_STRING => write!(f, "OCTET STRING"),
Tag::NULL => write!(f, "NULL"),
Tag::OID => write!(f, "OBJECT IDENTIFIER"),
Tag::OBJECT_DESCRIPTOR => write!(f, "ObjectDescriptor"),
Tag::EXTERNAL => write!(f, "EXTERNAL"),
Tag::REAL => write!(f, "REAL"),
Tag::ENUMERATED => write!(f, "ENUMERATED"),
Tag::EMBEDDED_PDV => write!(f, "EMBEDDED PDV"),
Tag::UTF8_STRING => write!(f, "UTF8String"),
Tag::RELATIVE_OID => write!(f, "RELATIVE-OID"),
Tag::SEQUENCE => write!(f, "SEQUENCE"),
Tag::SET => write!(f, "SET"),
Tag::NUMERIC_STRING => write!(f, "NumericString"),
Tag::PRINTABLE_STRING => write!(f, "PrintableString"),
Tag::TELETEX_STRING => write!(f, "TeletexString"),
Tag::VIDEOTEX_STRING => write!(f, "VideotexString"),
Tag::IA5_STRING => write!(f, "IA5String"),
Tag::UTC_TIME => write!(f, "UTCTime"),
Tag::GENERALIZED_TIME => write!(f, "GeneralizedTime"),
Tag::GRAPHIC_STRING => write!(f, "GraphicString"),
Tag::VISIBLE_STRING => write!(f, "VisibleString"),
Tag::GENERAL_STRING => write!(f, "GeneralString"),
Tag::UNIVERSAL_STRING => write!(f, "UniversalString"),
Tag::BMP_STRING => write!(f, "BMPString"),
tag => {
match tag.0 & Tag::CLASS_MASK {
Tag::UNIVERSAL => write!(f, "[UNIVERSAL ")?,
Tag::APPLICATION => write!(f, "[APPLICATION ")?,
Tag::CONTEXT_SPECIFIC => write!(f, "[")?,
Tag::PRIVATE => write!(f, "[PRIVATE ")?,
_ => unreachable!()
}
write!(f, "{}]", tag.0 & !Tag::CLASS_MASK)
}
}
}
}
impl fmt::Debug for Tag {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Tag({})", self)
}
}