bcder/
length.rs

1//! The Length Octets.
2//!
3//! This is a private module. Its public items are re-exported by the parent.
4
5use std::io;
6use crate::decode::{DecodeError, Source};
7use crate::mode::Mode;
8
9
10//------------ Length -------------------------------------------------------
11
12/// The length octets of an encoded value.
13///
14/// A length value can either be definite, meaning it provides the actual
15/// number of content octets in the value, or indefinite, in which case the
16/// content is delimited by a special end-of-value marker.
17///
18/// # BER Encoding
19///
20/// The length can be encoded in one of two basic ways. Which one is used is
21/// determined by the most significant bit of the first octet. If it is not
22/// set, the length octets is one octet long and the remaining bits of this
23/// first octet provide the definite length. Thus, if the first octet is
24/// less than 128, it provides the definite length already.
25///
26/// If the most significant bit is set, the remaining bits of the first
27/// octet specify the number of octets that follow to encode the actual
28/// length. If they specify that there are zero more octets, i.e., the
29/// value of the first octet is 128, the length is indefinite. Otherwise,
30/// those following octets give the big-endian encoding of the definite
31/// length of the content octets.
32///
33/// Under both CER and DER rules, a definite length must be encoded in the
34/// minimum number of octets.
35///
36/// # Limitation
37///
38/// The current implementation is limited to 4 length bytes on 32 bit systems
39/// and 5 length bytes on 64 bit sytems.
40#[derive(Clone, Copy, Debug, Eq, PartialEq)]
41pub enum Length {
42    /// A length value in definite form.
43    ///
44    /// Provides the actual length of the content in octets.
45    Definite(usize),
46
47    /// A length value in indefinite form.
48    ///
49    /// In this form, the end of a value is determined by a special tag.
50    Indefinite
51}
52
53impl Length {
54    /// Takes a length value from the beginning of a source.
55    pub fn take_from<S: Source>(
56        source: &mut S,
57        mode: Mode
58    ) -> Result<Self, DecodeError<S::Error>> {
59        match source.take_u8()? {
60            // Bit 7 clear: other bits are the length
61            n if (n & 0x80) == 0 => Ok(Length::Definite(n as usize)),
62
63            // Bit 7 set: other bits are the number of octets that 
64            // encode the length. Unless they are all 0, in which case this
65            // is the indefinite form.
66            0x80 => Ok(Length::Indefinite),
67            0x81 => {
68                let len = source.take_u8()? as usize;
69                if mode.is_ber() || len > 127 {
70                    Ok(Length::Definite(len))
71                }
72                else {
73                    Err(source.content_err("invalid length"))
74                }
75            }
76            0x82 => {
77                let len =
78                    ((source.take_u8()? as usize) << 8) |
79                    (source.take_u8()? as usize);
80                if mode.is_ber() || len > 255 {
81                    Ok(Length::Definite(len))
82                }
83                else {
84                    Err(source.content_err("invalid length"))
85                }
86            }
87            0x83 => {
88                let len =
89                    ((source.take_u8()? as usize) << 16) |
90                    ((source.take_u8()? as usize) << 8) |
91                    (source.take_u8()? as usize);
92                if mode.is_ber() || len > 0xFFFF {
93                    Ok(Length::Definite(len))
94                }
95                else {
96                    Err(source.content_err("invalid length"))
97                }
98            }
99            0x84 => {
100                let len =
101                    ((source.take_u8()? as usize) << 24) |
102                    ((source.take_u8()? as usize) << 16) |
103                    ((source.take_u8()? as usize) << 8) |
104                    (source.take_u8()? as usize);
105                if mode.is_ber() || len > 0x00FF_FFFF {
106                    Ok(Length::Definite(len))
107                }
108                else {
109                    Err(source.content_err("invalid length"))
110                }
111            }
112            _ => {
113                // We only implement up to two length bytes for now.
114                Err(source.content_err(
115                    "lengths over 4 bytes not implemented"
116                ))
117            }
118        }
119    }
120
121    /// Returns whether the length is definite and zero.
122    pub fn is_zero(&self) -> bool {
123        matches!(*self, Length::Definite(0))
124    }
125
126    /// Returns the length of the encoded representation of the value.
127    #[cfg(not(target_pointer_width = "64"))]
128    pub fn encoded_len(&self) -> usize {
129        match *self {
130            Length::Indefinite => 1,
131            Length::Definite(len) => {
132                if len < 0x80 { 1 }
133                else if len < 0x1_00 { 2 }
134                else if len < 0x1_0000 { 3 }
135                else if len < 0x100_0000 { 4 }
136                else {
137                    panic!("excessive length")
138                }
139            }
140        }
141    }
142
143    /// Returns the length of the encoded representation of the value.
144    #[cfg(target_pointer_width = "64")]
145    pub fn encoded_len(&self) -> usize {
146        match *self {
147            Length::Indefinite => 1,
148            Length::Definite(len) => {
149                if len < 0x80 { 1 }
150                else if len < 0x1_00 { 2 }
151                else if len < 0x1_0000 { 3 }
152                else if len < 0x100_0000 { 4 }
153                else if len < 0x1_0000_0000 { 5 }
154                else {
155                    panic!("excessive length")
156                }
157            }
158        }
159    }
160
161    /// Writes the encoded value to a target.
162    #[cfg(target_pointer_width = "64")]
163    pub fn write_encoded<W: io::Write>(
164        &self,
165        target: &mut W
166    ) -> Result<(), io::Error> {
167        match *self {
168            Length::Indefinite => {
169                let buf = [0x80];
170                target.write_all(&buf)
171            }
172            Length::Definite(len) => {
173                if len < 0x80 {
174                    let buf = [len as u8];
175                    target.write_all(&buf)
176                }
177                else if len < 0x1_00 {
178                    let buf = [0x81, len as u8];
179                    target.write_all(&buf)
180                }
181                else if len < 0x1_0000 {
182                    let buf = [
183                        0x82, (len >> 8) as u8, len as u8
184                    ];
185                    target.write_all(&buf)
186
187                }
188                else if len < 0x100_0000 {
189                    let buf = [
190                        0x83, (len >> 16) as u8, (len >> 8) as u8, len as u8
191                    ];
192                    target.write_all(&buf)
193                }
194                else if len < 0x1_0000_0000 {
195                    let buf = [
196                        0x84,
197                        (len >> 24) as u8, (len >> 16) as u8,
198                        (len >> 8) as u8, len as u8
199                    ];
200                    target.write_all(&buf)
201                }
202                else {
203                    panic!("excessive length")
204                }
205            }
206        }
207    }
208
209    /// Writes the encoded value to a target.
210    #[cfg(not(target_pointer_width = "64"))]
211    pub fn write_encoded<W: io::Write>(
212        &self,
213        target: &mut W
214    ) -> Result<(), io::Error> {
215        match *self {
216            Length::Indefinite => {
217                let buf = [0x80];
218                target.write_all(&buf)
219            }
220            Length::Definite(len) => {
221                if len < 0x80 {
222                    let buf = [len as u8];
223                    target.write_all(&buf)
224                }
225                else if len < 0x1_00 {
226                    let buf = [0x81, len as u8];
227                    target.write_all(&buf)
228                }
229                else if len < 0x1_0000 {
230                    let buf = [
231                        0x82, (len >> 8) as u8, len as u8
232                    ];
233                    target.write_all(&buf)
234
235                }
236                else if len < 0x100_0000 {
237                    let buf = [
238                        0x83, (len >> 16) as u8, (len >> 8) as u8, len as u8
239                    ];
240                    target.write_all(&buf)
241                }
242                else {
243                    panic!("excessive length")
244                }
245            }
246        }
247    }
248}