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}