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