Skip to main content

der/
header.rs

1//! ASN.1 DER headers.
2
3#[cfg(feature = "ber")]
4use crate::EncodingRules;
5use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Length, Reader, Result, Tag, Writer};
6
7use core::cmp::Ordering;
8
9/// ASN.1 DER headers: tag + length component of TLV-encoded values
10///
11///
12/// ## Examples
13/// ```
14/// use der::{Decode, Header, Length, Reader, SliceReader, Tag};
15///
16/// let mut reader = SliceReader::new(&[0x04, 0x02, 0x31, 0x32]).unwrap();
17/// let header = Header::decode(&mut reader).expect("valid header");
18///
19/// assert_eq!(header, Header::new(Tag::OctetString, Length::new(2)));
20///
21/// assert_eq!(reader.read_slice(2u8.into()).unwrap(), b"12");
22/// ```
23///
24/// ```
25/// use der::{Encode, Header, Length, Tag};
26/// let header = Header::new(Tag::Sequence, Length::new(256));
27///
28/// // Header of 256-byte SEQUENCE is 4-byte long
29/// assert_eq!(header.encoded_len(), Ok(Length::new(4)));
30/// ```
31#[derive(Copy, Clone, Debug, Eq, PartialEq)]
32pub struct Header {
33    /// Tag representing the type of the encoded value
34    tag: Tag,
35
36    /// Length of the encoded value
37    length: Length,
38
39    /// True if value is constructed, rather than primitive
40    constructed: bool,
41}
42
43impl Header {
44    /// Create a new [`Header`] from a [`Tag`] and a [`Length`].
45    #[must_use]
46    pub fn new(tag: Tag, length: Length) -> Self {
47        #[cfg(feature = "ber")]
48        let constructed = tag.is_constructed() || length.is_indefinite();
49        #[cfg(not(feature = "ber"))]
50        let constructed = tag.is_constructed();
51        Self {
52            tag,
53            length,
54            constructed,
55        }
56    }
57
58    /// [`Tag`] of this header.
59    #[must_use]
60    pub fn tag(&self) -> Tag {
61        self.tag
62    }
63
64    /// [`Length`] of this header.
65    #[must_use]
66    pub fn length(&self) -> Length {
67        self.length
68    }
69
70    /// True if the [`Tag`] of this header has its constructed bit set.
71    #[must_use]
72    pub fn is_constructed(&self) -> bool {
73        self.constructed
74    }
75
76    /// Copy of header with adjusted length.
77    #[must_use]
78    pub fn with_length(&self, length: Length) -> Self {
79        Self {
80            tag: self.tag,
81            length,
82            constructed: self.constructed,
83        }
84    }
85
86    /// Peek forward in the reader, attempting to decode a [`Header`] at the current position.
87    ///
88    /// Does not modify the reader's state.
89    ///
90    /// # Errors
91    /// Returns [`Error`] in the event a header decoding error occurred.
92    pub fn peek<'a>(reader: &impl Reader<'a>) -> Result<Self> {
93        Header::decode(&mut reader.clone())
94    }
95}
96
97impl<'a> Decode<'a> for Header {
98    type Error = Error;
99
100    fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Header> {
101        let (tag, is_constructed) = Tag::decode_with_constructed_bit(reader)?;
102
103        let length = Length::decode(reader).map_err(|e| {
104            if e.kind() == ErrorKind::Overlength {
105                reader.error(tag.length_error())
106            } else {
107                e
108            }
109        })?;
110
111        #[cfg(feature = "ber")]
112        if length.is_indefinite() && !is_constructed {
113            debug_assert_eq!(reader.encoding_rules(), EncodingRules::Ber);
114            return Err(reader.error(ErrorKind::IndefiniteLength));
115        }
116
117        #[cfg(not(feature = "ber"))]
118        debug_assert_eq!(is_constructed, tag.is_constructed());
119
120        Ok(Self {
121            tag,
122            length,
123            constructed: is_constructed,
124        })
125    }
126}
127
128impl Encode for Header {
129    fn encoded_len(&self) -> Result<Length> {
130        self.tag.encoded_len()? + self.length.encoded_len()?
131    }
132
133    fn encode(&self, writer: &mut impl Writer) -> Result<()> {
134        self.tag.encode(writer)?;
135        self.length.encode(writer)
136    }
137}
138
139impl DerOrd for Header {
140    fn der_cmp(&self, other: &Self) -> Result<Ordering> {
141        match self.tag.der_cmp(&other.tag)? {
142            Ordering::Equal => self.length.der_cmp(&other.length),
143            ordering => Ok(ordering),
144        }
145    }
146}
147
148#[cfg(test)]
149mod tests {
150    use super::Header;
151    use crate::{Encode, Length, Reader, SliceReader, Tag, TagNumber};
152    use hex_literal::hex;
153
154    #[test]
155    fn peek() {
156        // INTEGER: 42
157        const EXAMPLE_MSG: &[u8] = &hex!("02012A00");
158
159        let reader = SliceReader::new(EXAMPLE_MSG).expect("slice to be valid length");
160        assert_eq!(reader.position(), Length::ZERO);
161
162        let header = Header::peek(&reader).expect("peeked tag");
163        assert_eq!(header.tag(), Tag::Integer);
164        assert_eq!(header.length(), Length::ONE);
165        assert_eq!(reader.position(), Length::ZERO); // Position unchanged
166    }
167
168    #[test]
169    fn peek_max_header() {
170        const MAX_HEADER: [u8; 11] = hex!("BF8FFFFFFF7F 84FFFFFFFF");
171        let reader = SliceReader::new(&MAX_HEADER).expect("slice to be valid length");
172
173        let header = Header::peek(&reader).expect("peeked tag");
174        assert_eq!(
175            header.tag,
176            Tag::ContextSpecific {
177                constructed: true,
178                number: TagNumber(0xFFFFFFFF)
179            }
180        );
181        assert_eq!(
182            header.length(),
183            Length::new_usize(0xFFFFFFFF).expect("u32 to fit")
184        );
185        assert_eq!(header.encoded_len(), Ok(Length::new(11)));
186        assert_eq!(reader.position(), Length::ZERO); // Position unchanged
187    }
188    #[test]
189    fn negative_peek_overlength_header() {
190        const MAX_HEADER: [u8; 12] = hex!("BF8FFFFFFFFF7F 84FFFFFFFF");
191        let reader = SliceReader::new(&MAX_HEADER).expect("slice to be valid length");
192        // Should not decode
193        Header::peek(&reader).expect_err("overlength error");
194    }
195}