der_parser/ber/
serialize.rs

1#![cfg(feature = "std")]
2use crate::ber::*;
3use crate::oid::Oid;
4use asn1_rs::ASN1DateTime;
5use cookie_factory::bytes::be_u8;
6use cookie_factory::combinator::slice;
7use cookie_factory::gen_simple;
8use cookie_factory::multi::many_ref;
9use cookie_factory::sequence::tuple;
10use cookie_factory::{GenError, SerializeFn};
11use std::io::Write;
12
13fn encode_length<'a, W: Write + 'a, Len: Into<Length>>(len: Len) -> impl SerializeFn<W> + 'a {
14    let l = len.into();
15    move |out| {
16        match l {
17            Length::Definite(sz) => {
18                if sz <= 0x7f {
19                    // definite, short form
20                    be_u8(sz as u8)(out)
21                } else {
22                    // definite, long form
23                    let v: Vec<u8> = sz
24                        .to_be_bytes()
25                        .iter()
26                        .cloned()
27                        .skip_while(|&b| b == 0)
28                        .collect();
29                    let b0 = 0b1000_0000 | (v.len() as u8);
30                    tuple((be_u8(b0), slice(v)))(out)
31                }
32            }
33            Length::Indefinite => be_u8(0b1000_0000)(out),
34        }
35    }
36}
37
38/// Encode header as object
39///
40/// The `len` field must be correct
41#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
42pub fn ber_encode_header<'a, 'b: 'a, W: Write + 'a>(hdr: &'b Header) -> impl SerializeFn<W> + 'a {
43    move |out| {
44        // identifier octets (X.690 8.1.2)
45        let class_u8 = (hdr.class() as u8) << 6;
46        let pc_u8 = (if hdr.constructed() { 1 } else { 0 }) << 5;
47        if hdr.tag().0 >= 30 {
48            unimplemented!();
49        }
50        let byte_0 = class_u8 | pc_u8 | (hdr.tag().0 as u8);
51        // length octets (X.690 8.1.3)
52        tuple((be_u8(byte_0), encode_length(hdr.length())))(out)
53    }
54}
55
56fn ber_encode_oid<'a, W: Write + 'a>(oid: &'a Oid) -> impl SerializeFn<W> + 'a {
57    move |out| {
58        // check oid.relative attribute ? this should not be necessary
59        slice(oid.as_bytes())(out)
60    }
61}
62
63fn ber_encode_datetime<'a, W: Write + 'a>(time: &'a ASN1DateTime) -> impl SerializeFn<W> + 'a {
64    move |out| {
65        let s = format!("{}", time);
66        slice(s)(out)
67    }
68}
69
70fn ber_encode_sequence<'a, W: Write + Default + AsRef<[u8]> + 'a>(
71    v: &'a [BerObject],
72) -> impl SerializeFn<W> + 'a {
73    many_ref(v, ber_encode_object)
74}
75
76/// Encode the provided object in an EXPLICIT tagged value, using the provided tag ans class
77///
78/// Note: `obj` should be the object to be encapsulated, not the `ContextSpecific` variant.
79#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
80pub fn ber_encode_tagged_explicit<'a, W: Write + Default + AsRef<[u8]> + 'a>(
81    tag: Tag,
82    class: Class,
83    obj: &'a BerObject,
84) -> impl SerializeFn<W> + 'a {
85    move |out| {
86        // encode inner object
87        let v = gen_simple(ber_encode_object(obj), W::default())?;
88        let len = v.as_ref().len();
89        // encode the application header, using the tag
90        let hdr = Header::new(class, true /* X.690 8.14.2 */, tag, len.into());
91        let v_hdr = gen_simple(ber_encode_header(&hdr), W::default())?;
92        tuple((slice(v_hdr), slice(v)))(out)
93    }
94}
95
96/// Encode the provided object in an IMPLICIT tagged value, using the provided tag and class
97///
98/// Note: `obj` should be the object to be encapsulated, not the `ContextSpecific` variant.
99#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
100pub fn ber_encode_tagged_implicit<'a, W: Write + Default + AsRef<[u8]> + 'a>(
101    tag: Tag,
102    class: Class,
103    obj: &'a BerObject,
104) -> impl SerializeFn<W> + 'a {
105    move |out| {
106        // encode inner object content
107        let v = gen_simple(ber_encode_object_content(&obj.content), W::default())?;
108        // but replace the tag (keep constructed attribute)
109        let len = v.as_ref().len();
110        let hdr = Header::new(class, obj.header.constructed(), tag, len.into());
111        let v_hdr = gen_simple(ber_encode_header(&hdr), W::default())?;
112        tuple((slice(v_hdr), slice(v)))(out)
113    }
114}
115
116fn ber_encode_object_content<'a, W: Write + Default + AsRef<[u8]> + 'a>(
117    c: &'a BerObjectContent,
118) -> impl SerializeFn<W> + 'a {
119    move |out| match c {
120        BerObjectContent::EndOfContent => be_u8(0)(out),
121        BerObjectContent::Boolean(b) => {
122            let b0 = if *b { 0xff } else { 0x00 };
123            be_u8(b0)(out)
124        }
125        BerObjectContent::Integer(s) => slice(s)(out),
126        BerObjectContent::BitString(ignored_bits, s) => {
127            tuple((be_u8(*ignored_bits), slice(s)))(out)
128        }
129        BerObjectContent::OctetString(s) => slice(s)(out),
130        BerObjectContent::Null => Ok(out),
131        BerObjectContent::Enum(i) => {
132            let v: Vec<u8> = i
133                .to_be_bytes()
134                .iter()
135                .cloned()
136                .skip_while(|&b| b == 0)
137                .collect();
138            slice(v)(out)
139        }
140        BerObjectContent::OID(oid) | BerObjectContent::RelativeOID(oid) => ber_encode_oid(oid)(out),
141        BerObjectContent::UTCTime(time) | BerObjectContent::GeneralizedTime(time) => {
142            ber_encode_datetime(time)(out)
143        }
144        BerObjectContent::NumericString(s)
145        | BerObjectContent::GeneralString(s)
146        | BerObjectContent::ObjectDescriptor(s)
147        | BerObjectContent::GraphicString(s)
148        | BerObjectContent::VisibleString(s)
149        | BerObjectContent::PrintableString(s)
150        | BerObjectContent::IA5String(s)
151        | BerObjectContent::T61String(s)
152        | BerObjectContent::VideotexString(s)
153        | BerObjectContent::UTF8String(s) => slice(s)(out),
154        BerObjectContent::BmpString(s) => slice(s)(out),
155        BerObjectContent::UniversalString(s) => slice(s)(out),
156        BerObjectContent::Sequence(v) | BerObjectContent::Set(v) => ber_encode_sequence(v)(out),
157        // best we can do is tagged-explicit, but we don't know
158        BerObjectContent::Optional(inner) => {
159            // directly encode inner object
160            match inner {
161                Some(obj) => ber_encode_object_content(&obj.content)(out),
162                None => slice(&[])(out), // XXX encode NOP ?
163            }
164        }
165        BerObjectContent::Tagged(_class, _tag, inner) => {
166            // directly encode inner object
167            // XXX wrong, we should wrap it!
168            ber_encode_object(inner)(out)
169        }
170        BerObjectContent::Unknown(any) => slice(any.data)(out),
171    }
172}
173
174/// Encode header and object content as BER, without any validation
175///
176/// Note that the encoding will not check *any* `field of the header (including length)
177/// This can be used to craft invalid objects.
178///
179/// *This function is only available if the `serialize` feature is enabled.*
180#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
181pub fn ber_encode_object_raw<'a, 'b: 'a, 'c: 'a, W: Write + Default + AsRef<[u8]> + 'a>(
182    hdr: &'b Header,
183    content: &'c BerObjectContent,
184) -> impl SerializeFn<W> + 'a {
185    tuple((ber_encode_header(hdr), ber_encode_object_content(content)))
186}
187
188/// Encode object as BER
189///
190/// Note that the encoding will not check that the values of the `BerObject` fields are correct.
191/// The length is automatically calculated, and the field is ignored.
192///
193/// `Tagged` objects will be encoded as EXPLICIT.
194///
195/// *This function is only available if the `serialize` feature is enabled.*
196#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
197pub fn ber_encode_object<'a, 'b: 'a, W: Write + Default + AsRef<[u8]> + 'a>(
198    obj: &'b BerObject,
199) -> impl SerializeFn<W> + 'a {
200    move |out| {
201        // XXX should we make an exception for tagged values here ?
202        let v = gen_simple(ber_encode_object_content(&obj.content), W::default())?;
203        let len = v.as_ref().len();
204        let hdr = obj.header.clone().with_length(len.into());
205        let v_hdr = gen_simple(ber_encode_header(&hdr), W::default())?;
206        tuple((slice(v_hdr), slice(v)))(out)
207    }
208}
209
210impl BerObject<'_> {
211    /// Attempt to encode object as BER
212    ///
213    /// Note that the encoding will not check that the values of the `BerObject` fields are correct.
214    /// The length is automatically calculated, and the field is ignored.
215    ///
216    /// `Tagged` objects will be encoded as EXPLICIT.
217    ///
218    /// *This function is only available if the `serialize` feature is enabled.*
219    #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
220    pub fn to_vec(&self) -> Result<Vec<u8>, GenError> {
221        gen_simple(ber_encode_object(self), Vec::new())
222    }
223}
224
225#[cfg(test)]
226mod test {
227    use super::*;
228    use crate::error::BerResult;
229    use cookie_factory::gen_simple;
230    use hex_literal::hex;
231
232    macro_rules! encode_and_parse {
233        ($obj:ident, $encode:ident, $parse:ident) => {{
234            let v = gen_simple($encode(&$obj), Vec::new()).expect("could not encode");
235            let (_, obj2) = $parse(&v).expect("could not re-parse");
236            assert_eq!($obj, obj2);
237            v
238        }};
239    }
240
241    #[test]
242    fn test_encode_length() {
243        let l = 38;
244        let v = gen_simple(encode_length(l), Vec::new()).expect("could not serialize");
245        assert_eq!(&v[..], &[38]);
246        let l = 201;
247        let v = gen_simple(encode_length(l), Vec::new()).expect("could not serialize");
248        assert_eq!(&v[..], &[129, 201]);
249        let l = 0x1234_5678;
250        let v = gen_simple(encode_length(l), Vec::new()).expect("could not serialize");
251        assert_eq!(&v[..], &[132, 0x12, 0x34, 0x56, 0x78]);
252    }
253
254    #[test]
255    fn test_encode_header() {
256        // simple header (integer)
257        let bytes = hex!("02 03 01 00 01");
258        let (_, hdr) = ber_read_element_header(&bytes).expect("could not parse");
259        let v = encode_and_parse!(hdr, ber_encode_header, ber_read_element_header);
260        assert_eq!(&v[..], &bytes[..2]);
261    }
262
263    #[test]
264    fn test_encode_bool() {
265        let b_true = BerObject::from_obj(BerObjectContent::Boolean(true));
266        let b_false = BerObject::from_obj(BerObjectContent::Boolean(false));
267        encode_and_parse!(b_true, ber_encode_object, parse_ber_bool);
268        encode_and_parse!(b_false, ber_encode_object, parse_ber_bool);
269    }
270
271    #[test]
272    fn test_encode_integer() {
273        let i = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01"));
274        encode_and_parse!(i, ber_encode_object, parse_ber_integer);
275    }
276
277    #[test]
278    fn test_encode_bitstring() {
279        let bytes = hex!("03 04 06 6e 5d e0");
280        let b = BerObject::from_obj(BerObjectContent::BitString(
281            6,
282            BitStringObject { data: &bytes[3..] },
283        ));
284        let v = encode_and_parse!(b, ber_encode_object, parse_ber_bitstring);
285        assert_eq!(&v[..], bytes)
286    }
287
288    #[test]
289    fn test_encode_octetstring() {
290        let i = BerObject::from_obj(BerObjectContent::OctetString(b"AAAAA"));
291        let v = encode_and_parse!(i, ber_encode_object, parse_ber_octetstring);
292        assert_eq!(&v[..], hex!("04 05 41 41 41 41 41"))
293    }
294
295    #[test]
296    fn test_encode_enum() {
297        let i = BerObject::from_obj(BerObjectContent::Enum(2));
298        let v = encode_and_parse!(i, ber_encode_object, parse_ber_enum);
299        assert_eq!(&v[..], hex!("0a 01 02"))
300    }
301
302    #[test]
303    fn test_encode_null() {
304        let i = BerObject::from_obj(BerObjectContent::Null);
305        encode_and_parse!(i, ber_encode_object, parse_ber_null);
306    }
307
308    #[test]
309    fn test_encode_oid() {
310        let bytes = hex!("06 09 2A 86 48 86 F7 0D 01 01 05");
311        let obj = BerObject::from_obj(BerObjectContent::OID(
312            Oid::from(&[1, 2, 840, 113_549, 1, 1, 5]).unwrap(),
313        ));
314        let v = encode_and_parse!(obj, ber_encode_object, parse_ber_oid);
315        assert_eq!(&v[..], bytes);
316    }
317
318    #[test]
319    fn test_encode_relative_oid() {
320        let bytes = hex!("0d 04 c2 7b 03 02");
321        let obj = BerObject::from_obj(BerObjectContent::RelativeOID(
322            Oid::from_relative(&[8571, 3, 2]).unwrap(),
323        ));
324        let v = encode_and_parse!(obj, ber_encode_object, parse_ber_relative_oid);
325        assert_eq!(&v[..], bytes);
326    }
327
328    #[test]
329    fn test_encode_sequence() {
330        let bytes = hex!("30 0a 02 03 01 00 01 02 03 01 00 00");
331        let obj = BerObject::from_seq(vec![
332            BerObject::from_int_slice(b"\x01\x00\x01"),
333            BerObject::from_int_slice(b"\x01\x00\x00"),
334        ]);
335        let v = encode_and_parse!(obj, ber_encode_object, parse_ber_sequence);
336        assert_eq!(&v[..], bytes);
337    }
338
339    #[test]
340    fn test_encode_set() {
341        let bytes = hex!("31 0a 02 03 01 00 01 02 03 01 00 00");
342        let obj = BerObject::from_set(vec![
343            BerObject::from_int_slice(b"\x01\x00\x01"),
344            BerObject::from_int_slice(b"\x01\x00\x00"),
345        ]);
346        let v = encode_and_parse!(obj, ber_encode_object, parse_ber_set);
347        assert_eq!(&v[..], bytes);
348    }
349
350    #[test]
351    fn test_encode_tagged_explicit() {
352        fn local_parse(i: &[u8]) -> BerResult {
353            parse_ber_explicit_optional(i, Tag(0), parse_ber_integer)
354        }
355        let bytes = hex!("a0 03 02 01 02");
356        let obj = BerObject::from_int_slice(b"\x02");
357        let v = gen_simple(
358            ber_encode_tagged_explicit(Tag(0), Class::ContextSpecific, &obj),
359            Vec::new(),
360        )
361        .expect("could not encode");
362        let (_, obj2) = local_parse(&v).expect("could not re-parse");
363        let obj2 = obj2
364            .as_optional()
365            .expect("tagged object not found")
366            .expect("optional object empty");
367        let (_class, tag, inner) = obj2.as_tagged().expect("not a tagged object");
368        assert_eq!(tag, Tag(0));
369        assert_eq!(&obj, inner);
370        assert_eq!(&v[..], bytes);
371    }
372
373    #[test]
374    fn test_encode_tagged_implicit() {
375        fn der_read_integer_content<'a>(
376            i: &'a [u8],
377            hdr: &Header,
378            depth: usize,
379        ) -> BerResult<'a, BerObjectContent<'a>> {
380            ber_read_element_content_as(i, Tag::Integer, hdr.length(), false, depth)
381        }
382        fn local_parse(i: &[u8]) -> BerResult<BerObject> {
383            parse_ber_implicit(i, Tag(3), der_read_integer_content)
384        }
385        let obj = BerObject::from_int_slice(b"\x02");
386        let v = gen_simple(
387            ber_encode_tagged_implicit(Tag(3), Class::ContextSpecific, &obj),
388            Vec::new(),
389        )
390        .expect("could not encode");
391        let (_, obj2) = local_parse(&v).expect("could not re-parse");
392        assert_eq!(obj2.header.tag(), Tag(3));
393        assert_eq!(&obj.content, &obj2.content);
394        let bytes = hex!("83 01 02");
395        assert_eq!(&v[..], bytes);
396    }
397    #[test]
398    fn test_encode_tagged_application() {
399        fn local_parse(i: &[u8]) -> BerResult {
400            parse_ber_explicit_optional(i, Tag(2), parse_ber_integer)
401        }
402        let obj = BerObject::from_int_slice(b"\x02");
403        let v = gen_simple(
404            ber_encode_tagged_explicit(Tag(2), Class::Application, &obj),
405            Vec::new(),
406        )
407        .expect("could not encode");
408        let (_, obj2) = local_parse(&v).expect("could not re-parse");
409        let obj2 = obj2
410            .as_optional()
411            .expect("tagged object not found")
412            .expect("optional object empty");
413        let (_class, tag, inner) = obj2.as_tagged().expect("not a tagged object");
414        assert_eq!(tag, Tag(2));
415        assert_eq!(&obj, inner);
416        let bytes = hex!("62 03 02 01 02");
417        assert_eq!(&v[..], bytes);
418    }
419}