asn1_rs/
to_ber.rs

1#![cfg(feature = "std")]
2
3use std::io::Write;
4
5use crate::{Class, Header, InnerError, Length, SerializeResult, Tag};
6
7mod constructed;
8mod constructed_indefinite;
9mod encoder;
10mod generic;
11mod primitive;
12
13pub use constructed::*;
14pub use constructed_indefinite::*;
15pub use encoder::*;
16pub use generic::*;
17pub use primitive::*;
18
19/// Common trait for BER encoding functions
20///
21/// The `Encoder` type allows specifying common encoders for objects with similar headers
22/// (for ex. primitive objects) easily.
23pub trait ToBer {
24    type Encoder: BerEncoder;
25
26    /// Returns the length of the encoded content of the object
27    ///
28    /// The length describes the _content_ only, not the header.
29    fn ber_content_len(&self) -> Length;
30
31    /// Returns the total length (including header) of the encoded content of the object
32    fn ber_total_len(&self) -> Length {
33        let (_, _, tag) = self.ber_tag_info();
34        let content_length = self.ber_content_len();
35        ber_total_length(tag, content_length)
36    }
37
38    /// Return the tag information to be encoded in header
39    fn ber_tag_info(&self) -> (Class, bool, Tag);
40
41    /// Encode and write the content of the object to the writer `target`
42    ///
43    /// Returns the number of bytes written
44    fn ber_write_content<W: Write>(&self, target: &mut W) -> SerializeResult<usize>;
45
46    /// Encode and write the header of the object to the writer `target`
47    ///
48    /// Returns the number of bytes written
49    fn ber_write_header<W: Write>(&self, target: &mut W) -> SerializeResult<usize> {
50        let mut encoder = Self::Encoder::new();
51
52        let mut sz = 0;
53        let (class, constructed, tag) = self.ber_tag_info();
54        sz += encoder.write_tag_info(class, constructed, tag, target)?;
55
56        // write length
57        let length = self.ber_content_len();
58        sz += encoder.write_length(length, target)?;
59
60        Ok(sz)
61    }
62
63    /// Encode and write the object (header + content) to the writer `target`
64    ///
65    /// Returns the number of bytes written
66    fn ber_encode<W: Write>(&self, target: &mut W) -> SerializeResult<usize> {
67        let sz = self.ber_write_header(target)? + self.ber_write_content(target)?;
68
69        Ok(sz)
70    }
71
72    /// Encode and write the object (header + content) as TAGGED EXPLICIT and write it to the writer `target`
73    ///
74    /// Usually, `class` is `Class::ContextSpecific`.
75    ///
76    /// Returns the number of bytes written
77    fn ber_encode_tagged_explicit<W: Write>(
78        &self,
79        class: Class,
80        tag_number: u32,
81        target: &mut W,
82    ) -> SerializeResult<usize> {
83        let length = self.ber_total_len();
84        let tagged_header = Header::new(class, true, Tag(tag_number), length);
85        let sz = tagged_header.ber_write_header(target)?
86            + self.ber_write_header(target)?
87            + self.ber_write_content(target)?;
88
89        Ok(sz)
90    }
91
92    /// Encode and write the object (header + content) as TAGGED IMPLICIT and write it to the writer `target`
93    ///
94    /// Usually, `class` is `Class::ContextSpecific`.
95    ///
96    /// Returns the number of bytes written
97    fn ber_encode_tagged_implicit<W: Write>(
98        &self,
99        class: Class,
100        tag_number: u32,
101        target: &mut W,
102    ) -> SerializeResult<usize> {
103        let length = self.ber_content_len();
104        let (_, constructed, _) = self.ber_tag_info();
105        let tagged_header = Header::new(class, constructed, Tag(tag_number), length);
106        let sz = tagged_header.ber_write_header(target)? + self.ber_write_content(target)?;
107
108        Ok(sz)
109    }
110
111    /// Write the DER encoded representation to a newly allocated `Vec<u8>`
112    fn to_ber_vec(&self) -> SerializeResult<Vec<u8>> {
113        let mut v = Vec::new();
114        self.ber_encode(&mut v)?;
115        Ok(v)
116    }
117
118    /// Encode in BER and write the object (header + content) to the writer `target`
119    ///
120    /// Returns the number of bytes written
121    fn write_ber<W: Write>(&self, writer: &mut W) -> SerializeResult<usize> {
122        self.ber_encode(writer)
123    }
124}
125
126//--- blanket impls
127
128impl<E, T: ToBer> ToBer for &'_ T
129where
130    T: ToBer<Encoder = E>,
131    E: BerEncoder,
132{
133    type Encoder = <T as ToBer>::Encoder;
134
135    fn ber_content_len(&self) -> Length {
136        (*self).ber_content_len()
137    }
138
139    fn ber_tag_info(&self) -> (Class, bool, Tag) {
140        (*self).ber_tag_info()
141    }
142
143    fn ber_write_content<W: Write>(&self, target: &mut W) -> SerializeResult<usize> {
144        (*self).ber_write_content(target)
145    }
146}
147
148//--- helper functions
149
150/// Returns the length (in bytes) required for the given tag
151pub fn ber_tag_length(tag: Tag) -> usize {
152    match tag.0 {
153        0..=30 => 1,
154        t => {
155            let mut sz = 1;
156            let mut val = t;
157            loop {
158                if val <= 127 {
159                    return sz + 1;
160                } else {
161                    val >>= 7;
162                    sz += 1;
163                }
164            }
165        }
166    }
167}
168
169/// Returns the length (in bytes) required for the given length
170pub fn ber_length_length(length: Length) -> Result<usize, InnerError> {
171    match length {
172        Length::Indefinite => Ok(1),
173        Length::Definite(l) => match l {
174            0..=0x7f => Ok(1),
175            0x80..=0xff => Ok(2),
176            0x100..=0xffff => Ok(3),
177            0x1_0000..=0xffff_ffff => Ok(4),
178            _ => Err(InnerError::InvalidLength),
179        },
180    }
181}
182
183/// Returns the total length (header+content) required for an object, given the input parameters
184///
185/// If the content length is `Indefinite`, then the result will also be `Indefinite`
186pub fn ber_total_length(tag: Tag, content_length: Length) -> Length {
187    let header_len = ber_header_length(tag, content_length).unwrap_or(0);
188    content_length + header_len
189}
190
191/// Returns the length (in bytes) required for the full header (tag+length)
192///
193/// Returns 0 if length is invalid (overflow)
194pub fn ber_header_length(tag: Tag, length: Length) -> Result<usize, InnerError> {
195    let sz = ber_tag_length(tag);
196    let sz = sz + ber_length_length(length)?;
197    Ok(sz)
198}
199
200/// Return the length (in bytes) required for a set of objects (BER)
201///
202/// Compute the length by iterating through all items, and add lengths for their header+content.
203///
204/// Note: if one of the objects has an undefinite length, then the resulting length
205/// will be indefinite.
206pub fn ber_length_constructed_items<'a, T, IT>(iter: IT) -> Length
207where
208    T: ToBer + 'a,
209    IT: Iterator<Item = &'a T>,
210{
211    iter.map(|t| t.ber_total_len()).sum()
212}