Skip to content

Commit

Permalink
Impl read_enumerated and write_enumerated for DerReader/-Writer
Browse files Browse the repository at this point in the history
  • Loading branch information
kellerkindt committed Jan 21, 2024
1 parent c74917f commit 6901043
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 43 deletions.
10 changes: 6 additions & 4 deletions src/protocol/basic/distinguished/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,17 @@ impl<T: Write> BasicWrite for T {

#[inline]
fn write_integer_i64(&mut self, value: i64) -> Result<(), Error> {
let offset = value.leading_zeros() / u8::BITS;
self.write_all(&value.to_be_bytes()[offset as usize..])?;
let bytes = value.to_be_bytes();
let offset = (value.leading_zeros() / u8::BITS).min(bytes.len() as u32 - 1);
self.write_all(&bytes[offset as usize..])?;
Ok(())
}

#[inline]
fn write_integer_u64(&mut self, value: u64) -> Result<(), Error> {
let offset = value.leading_zeros() / u8::BITS;
self.write_all(&value.to_be_bytes()[offset as usize..])?;
let bytes = value.to_be_bytes();
let offset = (value.leading_zeros() / u8::BITS).min(bytes.len() as u32 - 1);
self.write_all(&bytes[offset as usize..])?;
Ok(())
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/protocol/basic/err.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ impl Error {
Self::from(ErrorKind::UnexpectedTypeLength { expected, got })
}

#[cold]
#[inline(never)]
pub fn unexpected_choice_index(expected: Range<u64>, got: u64) -> Self {
Self::from(ErrorKind::UnexpectedChoiceIndex { expected, got })
}

#[cold]
#[inline(never)]
pub fn unsupported_byte_len(max: u8, got: u8) -> Self {
Expand Down Expand Up @@ -86,6 +92,7 @@ impl From<ErrorKind> for Inner {
pub enum ErrorKind {
UnexpectedTypeTag { expected: Tag, got: Tag },
UnexpectedTypeLength { expected: Range<u64>, got: u64 },
UnexpectedChoiceIndex { expected: Range<u64>, got: u64 },
UnsupportedByteLen { max: u8, got: u8 },
IoError(std::io::Error),
}
Expand All @@ -99,6 +106,9 @@ impl Display for ErrorKind {
ErrorKind::UnexpectedTypeLength { expected, got } => {
write!(f, "Expected length in range {expected:?} but got {got:?}")
}
ErrorKind::UnexpectedChoiceIndex { expected, got } => {
write!(f, "Expected choice index in {expected:?} but got {got:?}")
}
ErrorKind::UnsupportedByteLen { max, got } => {
write!(
f,
Expand Down
47 changes: 38 additions & 9 deletions src/rw/der.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::descriptor::numbers::Number;
use crate::descriptor::sequence::Constraint;
use crate::descriptor::{Null, ReadableType, Reader, WritableType, Writer};
use crate::descriptor::{numbers, Null, ReadableType, Reader, WritableType, Writer};
use crate::protocol::basic::Error;
use crate::protocol::basic::{BasicRead, BasicWrite};
use asn1rs_model::asn::Tag;
use std::marker::PhantomData;

pub struct BasicWriter<W: BasicWrite> {
write: W,
Expand Down Expand Up @@ -54,11 +55,25 @@ impl<W: BasicWrite> Writer for BasicWriter<W> {
todo!()
}

#[inline]
fn write_enumerated<C: crate::descriptor::enumerated::Constraint>(
&mut self,
_enumerated: &C,
enumerated: &C,
) -> Result<(), Self::Error> {
todo!()
struct IntegerConstraint<IC: crate::descriptor::enumerated::Constraint>(PhantomData<IC>);
impl<IC: crate::descriptor::enumerated::Constraint> crate::descriptor::common::Constraint
for IntegerConstraint<IC>
{
const TAG: Tag = <IC as crate::descriptor::common::Constraint>::TAG;
}
impl<IC: crate::descriptor::enumerated::Constraint> numbers::Constraint<u64>
for IntegerConstraint<IC>
{
}
numbers::Integer::<u64, IntegerConstraint<C>>::write_value(
self,
&enumerated.to_choice_index(),
)
}

fn write_choice<C: crate::descriptor::choice::Constraint>(
Expand Down Expand Up @@ -90,7 +105,7 @@ impl<W: BasicWrite> Writer for BasicWriter<W> {
let value = value.to_i64();
let offset = value.leading_zeros() / u8::BITS;
let len = value.to_be_bytes().len() as u64 - offset as u64;
self.write.write_length(len)?;
self.write.write_length(len.max(1))?;
self.write.write_integer_i64(value)?;
Ok(())
}
Expand Down Expand Up @@ -210,10 +225,24 @@ impl<R: BasicRead> Reader for BasicReader<R> {
todo!()
}

#[inline]
fn read_enumerated<C: crate::descriptor::enumerated::Constraint>(
&mut self,
) -> Result<C, Self::Error> {
todo!()
struct IntegerConstraint<IC: crate::descriptor::enumerated::Constraint>(PhantomData<IC>);
impl<IC: crate::descriptor::enumerated::Constraint> crate::descriptor::common::Constraint
for IntegerConstraint<IC>
{
const TAG: Tag = <IC as crate::descriptor::common::Constraint>::TAG;
}
impl<IC: crate::descriptor::enumerated::Constraint> numbers::Constraint<u64>
for IntegerConstraint<IC>
{
}
numbers::Integer::<u64, IntegerConstraint<C>>::read_value(self).and_then(|v| {
C::from_choice_index(v)
.ok_or_else(|| Error::unexpected_choice_index(0..C::VARIANT_COUNT, v))
})
}

fn read_choice<C: crate::descriptor::choice::Constraint>(&mut self) -> Result<C, Self::Error> {
Expand All @@ -234,8 +263,8 @@ impl<R: BasicRead> Reader for BasicReader<R> {
&mut self,
) -> Result<T, Self::Error> {
let identifier = self.read.read_identifier()?;
if identifier.value() != Tag::DEFAULT_INTEGER.value() {
return Err(Error::unexpected_tag(Tag::DEFAULT_INTEGER, identifier));
if identifier.value() != C::TAG.value() {
return Err(Error::unexpected_tag(C::TAG, identifier));
}
let len = self.read.read_length()?;
self.read.read_integer_i64(len as u32).map(T::from_i64)
Expand Down Expand Up @@ -287,8 +316,8 @@ impl<R: BasicRead> Reader for BasicReader<R> {
&mut self,
) -> Result<bool, Self::Error> {
let identifier = self.read.read_identifier()?;
if identifier.value() != Tag::DEFAULT_BOOLEAN.value() {
return Err(Error::unexpected_tag(Tag::DEFAULT_BOOLEAN, identifier));
if identifier.value() != C::TAG.value() {
return Err(Error::unexpected_tag(C::TAG, identifier));
}
let expecting = 1_u64..2_u64;
let length = self.read.read_length()?;
Expand Down
52 changes: 22 additions & 30 deletions tests/basic_enumerated.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
use asn1rs::rw::UperReader as NewUperReader;
use asn1rs::rw::UperWriter as NewUperWriter;

mod test_utils;
use test_utils::*;

Expand Down Expand Up @@ -35,24 +32,12 @@ asn_to_rust!(
END"
);

fn serialize_uper(to_uper: impl Writable) -> (usize, Vec<u8>) {
let mut writer = NewUperWriter::default();
writer.write(&to_uper).unwrap();
let bits = writer.bit_len();
(bits, writer.into_bytes_vec())
}

fn deserialize_uper<T: Readable>(bytes: &[u8], bit_len: usize) -> T {
let mut reader = NewUperReader::from((bytes, bit_len));
reader.read::<T>().unwrap()
}

#[test]
fn test_predefined_numbers() {
assert_eq!((2, vec![0x00_u8]), serialize_uper(PredefinedNumbers::Abc));
assert_eq!((2, vec![0x40_u8]), serialize_uper(PredefinedNumbers::Def));
assert_eq!((8, vec![0x80_u8]), serialize_uper(PredefinedNumbers::Ghi));
assert_eq!((8, vec![0x81_u8]), serialize_uper(PredefinedNumbers::Jkl));
fn test_uper_predefined_numbers() {
assert_eq!((2, vec![0x00_u8]), serialize_uper(&PredefinedNumbers::Abc));
assert_eq!((2, vec![0x40_u8]), serialize_uper(&PredefinedNumbers::Def));
assert_eq!((8, vec![0x80_u8]), serialize_uper(&PredefinedNumbers::Ghi));
assert_eq!((8, vec![0x81_u8]), serialize_uper(&PredefinedNumbers::Jkl));

assert_eq!(PredefinedNumbers::Abc, deserialize_uper(&[0x00_u8], 2,));
assert_eq!(PredefinedNumbers::Def, deserialize_uper(&[0x40_u8], 2,));
Expand All @@ -61,7 +46,7 @@ fn test_predefined_numbers() {
}

#[test]
fn test_basic_variants_parsed() {
fn test_uper_basic_variants_parsed() {
let _abc = Basic::Abc;
let _def = Basic::Def;
let _ghi = Basic::Ghi;
Expand All @@ -73,8 +58,8 @@ fn test_basic_variants_parsed() {
}

#[test]
pub fn test_basic_uper() {
let mut writer = NewUperWriter::default();
pub fn test_uper_basic() {
let mut writer = UperWriter::default();
writer.write(&Basic::Abc).unwrap();
writer.write(&Basic::Def).unwrap();
writer.write(&Basic::Ghi).unwrap();
Expand All @@ -90,11 +75,18 @@ pub fn test_basic_uper() {
}

#[test]
fn test_some_enum_with_skipped_numbers() {
test_utils::serialize_and_deserialize_uper(3, &[0x00], &SomeEnum::Abc);
test_utils::serialize_and_deserialize_uper(3, &[0x20], &SomeEnum::Def);
test_utils::serialize_and_deserialize_uper(3, &[0x40], &SomeEnum::Ghi);
test_utils::serialize_and_deserialize_uper(3, &[0x60], &SomeEnum::Jkl);
test_utils::serialize_and_deserialize_uper(3, &[0x80], &SomeEnum::Mno);
test_utils::serialize_and_deserialize_uper(3, &[0xA0], &SomeEnum::Qrs);
fn test_uper_some_enum_with_skipped_numbers() {
serialize_and_deserialize_uper(3, &[0x00], &SomeEnum::Abc);
serialize_and_deserialize_uper(3, &[0x20], &SomeEnum::Def);
serialize_and_deserialize_uper(3, &[0x40], &SomeEnum::Ghi);
serialize_and_deserialize_uper(3, &[0x60], &SomeEnum::Jkl);
serialize_and_deserialize_uper(3, &[0x80], &SomeEnum::Mno);
serialize_and_deserialize_uper(3, &[0xA0], &SomeEnum::Qrs);
}

#[test]
fn test_der_basic() {
serialize_and_deserialize_der(&[0x0A, 0x01, 0x00], &Basic::Abc);
serialize_and_deserialize_der(&[0x0A, 0x01, 0x01], &Basic::Def);
serialize_and_deserialize_der(&[0x0A, 0x01, 0x02], &Basic::Ghi);
}
36 changes: 36 additions & 0 deletions tests/test_utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![allow(unused)]

use asn1rs::prelude::basic::DER;
pub use asn1rs::prelude::*;

pub fn serialize_uper(to_uper: &impl Writable) -> (usize, Vec<u8>) {
Expand Down Expand Up @@ -39,6 +40,41 @@ pub fn serialize_and_deserialize_uper<T: Readable + Writable + std::fmt::Debug +
);
}

pub fn serialize_der(to_der: &impl Writable) -> Vec<u8> {
let mut writer = DER::writer(Vec::new());
writer.write(to_der).unwrap();
writer.into_inner()
}

pub fn deserialize_der<T: Readable>(data: &[u8]) -> T {
let mut reader = DER::reader(data);
let result = reader.read::<T>().unwrap();
assert_eq!(
0,
reader.into_inner().len(),
"After reading, there are still bytes remaining!"
);
result
}

pub fn serialize_and_deserialize_der<T: Readable + Writable + std::fmt::Debug + PartialEq>(
data: &[u8],
value: &T,
) {
let serialized = serialize_der(value);
assert_eq!(
data,
&serialized[..],
"Serialized binary data does not match, bad-hex: {:02x?}",
&serialized[..]
);
assert_eq!(
value,
&deserialize_der::<T>(data),
"Deserialized data struct does not match"
);
}

#[cfg(feature = "protobuf")]
pub fn serialize_protobuf(to_protobuf: &impl Writable) -> Vec<u8> {
let mut writer = ProtobufWriter::default();
Expand Down

0 comments on commit 6901043

Please sign in to comment.