#![cfg(feature = "std")]
use crate::ber::*;
use crate::oid::Oid;
use asn1_rs::{ASN1DateTime, Tag};
use cookie_factory::bytes::be_u8;
use cookie_factory::combinator::slice;
use cookie_factory::gen_simple;
use cookie_factory::multi::many_ref;
use cookie_factory::sequence::tuple;
use cookie_factory::{GenError, SerializeFn};
use std::io::Write;
fn encode_length<'a, W: Write + 'a, Len: Into<Length>>(len: Len) -> impl SerializeFn<W> + 'a {
let l = len.into();
move |out| {
match l {
Length::Definite(sz) => {
if sz <= 128 {
be_u8(sz as u8)(out)
} else {
let v: Vec<u8> = sz
.to_be_bytes()
.iter()
.cloned()
.skip_while(|&b| b == 0)
.collect();
let b0 = 0b1000_0000 | (v.len() as u8);
tuple((be_u8(b0), slice(v)))(out)
}
}
Length::Indefinite => be_u8(0b1000_0000)(out),
}
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
pub fn ber_encode_header<'a, 'b: 'a, W: Write + 'a>(hdr: &'b Header) -> impl SerializeFn<W> + 'a {
move |out| {
let class_u8 = (hdr.class() as u8) << 6;
let pc_u8 = (if hdr.constructed() { 1 } else { 0 }) << 5;
if hdr.tag().0 >= 30 {
unimplemented!();
}
let byte_0 = class_u8 | pc_u8 | (hdr.tag().0 as u8);
tuple((be_u8(byte_0), encode_length(hdr.length())))(out)
}
}
fn ber_encode_oid<'a, W: Write + 'a>(oid: &'a Oid) -> impl SerializeFn<W> + 'a {
move |out| {
slice(oid.as_bytes())(out)
}
}
fn ber_encode_datetime<'a, W: Write + 'a>(time: &'a ASN1DateTime) -> impl SerializeFn<W> + 'a {
move |out| {
let s = format!("{}", time);
slice(s)(out)
}
}
fn ber_encode_sequence<'a, W: Write + Default + AsRef<[u8]> + 'a>(
v: &'a [BerObject],
) -> impl SerializeFn<W> + 'a {
many_ref(v, ber_encode_object)
}
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
pub fn ber_encode_tagged_explicit<'a, W: Write + Default + AsRef<[u8]> + 'a>(
tag: Tag,
class: Class,
obj: &'a BerObject,
) -> impl SerializeFn<W> + 'a {
move |out| {
let v = gen_simple(ber_encode_object(obj), W::default())?;
let len = v.as_ref().len();
let hdr = Header::new(class, true , tag, len.into());
let v_hdr = gen_simple(ber_encode_header(&hdr), W::default())?;
tuple((slice(v_hdr), slice(v)))(out)
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
pub fn ber_encode_tagged_implicit<'a, W: Write + Default + AsRef<[u8]> + 'a>(
tag: Tag,
class: Class,
obj: &'a BerObject,
) -> impl SerializeFn<W> + 'a {
move |out| {
let v = gen_simple(ber_encode_object_content(&obj.content), W::default())?;
let len = v.as_ref().len();
let hdr = Header::new(class, obj.header.constructed(), tag, len.into());
let v_hdr = gen_simple(ber_encode_header(&hdr), W::default())?;
tuple((slice(v_hdr), slice(v)))(out)
}
}
fn ber_encode_object_content<'a, W: Write + Default + AsRef<[u8]> + 'a>(
c: &'a BerObjectContent,
) -> impl SerializeFn<W> + 'a {
move |out| match c {
BerObjectContent::EndOfContent => be_u8(0)(out),
BerObjectContent::Boolean(b) => {
let b0 = if *b { 0xff } else { 0x00 };
be_u8(b0)(out)
}
BerObjectContent::Integer(s) => slice(s)(out),
BerObjectContent::BitString(ignored_bits, s) => {
tuple((be_u8(*ignored_bits), slice(s)))(out)
}
BerObjectContent::OctetString(s) => slice(s)(out),
BerObjectContent::Null => Ok(out),
BerObjectContent::Enum(i) => {
let v: Vec<u8> = i
.to_be_bytes()
.iter()
.cloned()
.skip_while(|&b| b == 0)
.collect();
slice(v)(out)
}
BerObjectContent::OID(oid) | BerObjectContent::RelativeOID(oid) => ber_encode_oid(oid)(out),
BerObjectContent::UTCTime(time) | BerObjectContent::GeneralizedTime(time) => {
ber_encode_datetime(time)(out)
}
BerObjectContent::NumericString(s)
| BerObjectContent::BmpString(s)
| BerObjectContent::GeneralString(s)
| BerObjectContent::ObjectDescriptor(s)
| BerObjectContent::GraphicString(s)
| BerObjectContent::VisibleString(s)
| BerObjectContent::PrintableString(s)
| BerObjectContent::IA5String(s)
| BerObjectContent::T61String(s)
| BerObjectContent::VideotexString(s)
| BerObjectContent::UTF8String(s) => slice(s)(out),
BerObjectContent::UniversalString(s) => slice(s)(out),
BerObjectContent::Sequence(v) | BerObjectContent::Set(v) => ber_encode_sequence(v)(out),
BerObjectContent::Optional(inner) => {
match inner {
Some(obj) => ber_encode_object_content(&obj.content)(out),
None => slice(&[])(out), }
}
BerObjectContent::Tagged(_class, _tag, inner) => {
ber_encode_object(inner)(out)
}
BerObjectContent::Unknown(any) => slice(any.data)(out),
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
pub fn ber_encode_object_raw<'a, 'b: 'a, 'c: 'a, W: Write + Default + AsRef<[u8]> + 'a>(
hdr: &'b Header,
content: &'c BerObjectContent,
) -> impl SerializeFn<W> + 'a {
tuple((ber_encode_header(hdr), ber_encode_object_content(content)))
}
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
pub fn ber_encode_object<'a, 'b: 'a, W: Write + Default + AsRef<[u8]> + 'a>(
obj: &'b BerObject,
) -> impl SerializeFn<W> + 'a {
move |out| {
let v = gen_simple(ber_encode_object_content(&obj.content), W::default())?;
let len = v.as_ref().len();
let hdr = obj.header.clone().with_length(len.into());
let v_hdr = gen_simple(ber_encode_header(&hdr), W::default())?;
tuple((slice(v_hdr), slice(v)))(out)
}
}
impl<'a> BerObject<'a> {
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
pub fn to_vec(&self) -> Result<Vec<u8>, GenError> {
gen_simple(ber_encode_object(self), Vec::new())
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::error::BerResult;
use cookie_factory::gen_simple;
use hex_literal::hex;
macro_rules! encode_and_parse {
($obj:ident, $encode:ident, $parse:ident) => {{
let v = gen_simple($encode(&$obj), Vec::new()).expect("could not encode");
let (_, obj2) = $parse(&v).expect("could not re-parse");
assert_eq!($obj, obj2);
v
}};
}
#[test]
fn test_encode_length() {
let l = 38;
let v = gen_simple(encode_length(l), Vec::new()).expect("could not serialize");
assert_eq!(&v[..], &[38]);
let l = 201;
let v = gen_simple(encode_length(l), Vec::new()).expect("could not serialize");
assert_eq!(&v[..], &[129, 201]);
let l = 0x1234_5678;
let v = gen_simple(encode_length(l), Vec::new()).expect("could not serialize");
assert_eq!(&v[..], &[132, 0x12, 0x34, 0x56, 0x78]);
}
#[test]
fn test_encode_header() {
let bytes = hex!("02 03 01 00 01");
let (_, hdr) = ber_read_element_header(&bytes).expect("could not parse");
let v = encode_and_parse!(hdr, ber_encode_header, ber_read_element_header);
assert_eq!(&v[..], &bytes[..2]);
}
#[test]
fn test_encode_bool() {
let b_true = BerObject::from_obj(BerObjectContent::Boolean(true));
let b_false = BerObject::from_obj(BerObjectContent::Boolean(false));
encode_and_parse!(b_true, ber_encode_object, parse_ber_bool);
encode_and_parse!(b_false, ber_encode_object, parse_ber_bool);
}
#[test]
fn test_encode_integer() {
let i = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01"));
encode_and_parse!(i, ber_encode_object, parse_ber_integer);
}
#[test]
fn test_encode_bitstring() {
let bytes = hex!("03 04 06 6e 5d e0");
let b = BerObject::from_obj(BerObjectContent::BitString(
6,
BitStringObject { data: &bytes[3..] },
));
let v = encode_and_parse!(b, ber_encode_object, parse_ber_bitstring);
assert_eq!(&v[..], bytes)
}
#[test]
fn test_encode_octetstring() {
let i = BerObject::from_obj(BerObjectContent::OctetString(b"AAAAA"));
let v = encode_and_parse!(i, ber_encode_object, parse_ber_octetstring);
assert_eq!(&v[..], hex!("04 05 41 41 41 41 41"))
}
#[test]
fn test_encode_enum() {
let i = BerObject::from_obj(BerObjectContent::Enum(2));
let v = encode_and_parse!(i, ber_encode_object, parse_ber_enum);
assert_eq!(&v[..], hex!("0a 01 02"))
}
#[test]
fn test_encode_null() {
let i = BerObject::from_obj(BerObjectContent::Null);
encode_and_parse!(i, ber_encode_object, parse_ber_null);
}
#[test]
fn test_encode_oid() {
let bytes = hex!("06 09 2A 86 48 86 F7 0D 01 01 05");
let obj = BerObject::from_obj(BerObjectContent::OID(
Oid::from(&[1, 2, 840, 113_549, 1, 1, 5]).unwrap(),
));
let v = encode_and_parse!(obj, ber_encode_object, parse_ber_oid);
assert_eq!(&v[..], bytes);
}
#[test]
fn test_encode_relative_oid() {
let bytes = hex!("0d 04 c2 7b 03 02");
let obj = BerObject::from_obj(BerObjectContent::RelativeOID(
Oid::from_relative(&[8571, 3, 2]).unwrap(),
));
let v = encode_and_parse!(obj, ber_encode_object, parse_ber_relative_oid);
assert_eq!(&v[..], bytes);
}
#[test]
fn test_encode_sequence() {
let bytes = hex!("30 0a 02 03 01 00 01 02 03 01 00 00");
let obj = BerObject::from_seq(vec![
BerObject::from_int_slice(b"\x01\x00\x01"),
BerObject::from_int_slice(b"\x01\x00\x00"),
]);
let v = encode_and_parse!(obj, ber_encode_object, parse_ber_sequence);
assert_eq!(&v[..], bytes);
}
#[test]
fn test_encode_set() {
let bytes = hex!("31 0a 02 03 01 00 01 02 03 01 00 00");
let obj = BerObject::from_set(vec![
BerObject::from_int_slice(b"\x01\x00\x01"),
BerObject::from_int_slice(b"\x01\x00\x00"),
]);
let v = encode_and_parse!(obj, ber_encode_object, parse_ber_set);
assert_eq!(&v[..], bytes);
}
#[test]
fn test_encode_tagged_explicit() {
fn local_parse(i: &[u8]) -> BerResult {
parse_ber_explicit_optional(i, Tag(0), parse_ber_integer)
}
let bytes = hex!("a0 03 02 01 02");
let obj = BerObject::from_int_slice(b"\x02");
let v = gen_simple(
ber_encode_tagged_explicit(Tag(0), Class::ContextSpecific, &obj),
Vec::new(),
)
.expect("could not encode");
let (_, obj2) = local_parse(&v).expect("could not re-parse");
let obj2 = obj2
.as_optional()
.expect("tagged object not found")
.expect("optional object empty");
let (_class, tag, inner) = obj2.as_tagged().expect("not a tagged object");
assert_eq!(tag, Tag(0));
assert_eq!(&obj, inner);
assert_eq!(&v[..], bytes);
}
#[test]
fn test_encode_tagged_implicit() {
fn der_read_integer_content<'a>(
i: &'a [u8],
hdr: &Header,
depth: usize,
) -> BerResult<'a, BerObjectContent<'a>> {
ber_read_element_content_as(i, Tag::Integer, hdr.length(), false, depth)
}
fn local_parse(i: &[u8]) -> BerResult<BerObject> {
parse_ber_implicit(i, Tag(3), der_read_integer_content)
}
let obj = BerObject::from_int_slice(b"\x02");
let v = gen_simple(
ber_encode_tagged_implicit(Tag(3), Class::ContextSpecific, &obj),
Vec::new(),
)
.expect("could not encode");
let (_, obj2) = local_parse(&v).expect("could not re-parse");
assert_eq!(obj2.header.tag(), Tag(3));
assert_eq!(&obj.content, &obj2.content);
let bytes = hex!("83 01 02");
assert_eq!(&v[..], bytes);
}
#[test]
fn test_encode_tagged_application() {
fn local_parse(i: &[u8]) -> BerResult {
parse_ber_explicit_optional(i, Tag(2), parse_ber_integer)
}
let obj = BerObject::from_int_slice(b"\x02");
let v = gen_simple(
ber_encode_tagged_explicit(Tag(2), Class::Application, &obj),
Vec::new(),
)
.expect("could not encode");
let (_, obj2) = local_parse(&v).expect("could not re-parse");
let obj2 = obj2
.as_optional()
.expect("tagged object not found")
.expect("optional object empty");
let (_class, tag, inner) = obj2.as_tagged().expect("not a tagged object");
assert_eq!(tag, Tag(2));
assert_eq!(&obj, inner);
let bytes = hex!("62 03 02 01 02");
assert_eq!(&v[..], bytes);
}
}