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