diff --git a/src/ber.rs b/src/ber.rs index 7f0d1c0..e8eae46 100644 --- a/src/ber.rs +++ b/src/ber.rs @@ -1,461 +1,7 @@ -use crate::bitstring::BitString; -use alloc::vec::Vec; -use core::convert::TryFrom; -use core::fmt; -#[cfg(test)] -use quickcheck::{quickcheck, Arbitrary, Gen}; +pub(crate) mod tag; +pub(crate) mod length; +pub(crate) mod value; -#[repr(u8)] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum BasicTagType { - Boolean = 1, - Integer = 2, - BitString = 3, - OctetString = 4, - Null = 5, - ObjectIdentifier = 6, - ObjectDescriptor = 7, - External = 8, - Real = 9, - Enumerated = 10, - EmbeddedBDV = 11, - UTF8String = 12, - RelativeOID = 13, - Sequence = 16, - Set = 17, - NumericString = 18, - PrintableString = 19, - TeletexString = 20, - VideotexString = 21, - IA5String = 22, - UTCTime = 23, - GeneralizedTime = 24, - GraphicString = 25, - VisibleString = 26, - GeneralString = 27, - UniversalString = 28, - CharacterString = 29, - BMPString = 30, -} - -#[cfg(test)] -impl Arbitrary for BasicTagType { - fn arbitrary(g: &mut G) -> BasicTagType { - let options = vec![ - BasicTagType::Boolean, - BasicTagType::Integer, - BasicTagType::BitString, - BasicTagType::OctetString, - BasicTagType::Null, - BasicTagType::ObjectIdentifier, - BasicTagType::ObjectDescriptor, - BasicTagType::External, - BasicTagType::Real, - BasicTagType::Enumerated, - BasicTagType::EmbeddedBDV, - BasicTagType::UTF8String, - BasicTagType::RelativeOID, - BasicTagType::Sequence, - BasicTagType::Set, - BasicTagType::NumericString, - BasicTagType::PrintableString, - BasicTagType::TeletexString, - BasicTagType::VideotexString, - BasicTagType::IA5String, - BasicTagType::UTCTime, - BasicTagType::GeneralizedTime, - BasicTagType::GraphicString, - BasicTagType::VisibleString, - BasicTagType::GeneralString, - BasicTagType::UniversalString, - BasicTagType::CharacterString, - BasicTagType::BMPString, - ]; - let index = usize::arbitrary(g) % options.len(); - options[index] - } -} - -#[derive(Debug, PartialEq)] -pub enum TagTypeParseError { - UsedReservedSlot, - UsedSignalSlot, - ValueTooLarge, -} - -impl fmt::Display for TagTypeParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - TagTypeParseError::UsedReservedSlot => write!( - f, - "Tag type value was one marked reserved in our specification." - ), - TagTypeParseError::UsedSignalSlot => write!( - f, - "Tag type value was the one that signals a multi-byte tag." - ), - TagTypeParseError::ValueTooLarge => { - write!(f, "Tag type value was much too large for us.") - } - } - } -} - -impl TryFrom for BasicTagType { - type Error = TagTypeParseError; - - fn try_from(x: u8) -> Result { - match x { - 0 => Err(TagTypeParseError::UsedReservedSlot), - 1 => Ok(BasicTagType::Boolean), - 2 => Ok(BasicTagType::Integer), - 3 => Ok(BasicTagType::BitString), - 4 => Ok(BasicTagType::OctetString), - 5 => Ok(BasicTagType::Null), - 6 => Ok(BasicTagType::ObjectIdentifier), - 7 => Ok(BasicTagType::ObjectDescriptor), - 8 => Ok(BasicTagType::External), - 9 => Ok(BasicTagType::Real), - 10 => Ok(BasicTagType::Enumerated), - 11 => Ok(BasicTagType::EmbeddedBDV), - 12 => Ok(BasicTagType::UTF8String), - 13 => Ok(BasicTagType::RelativeOID), - 14 => Err(TagTypeParseError::UsedReservedSlot), - 15 => Err(TagTypeParseError::UsedReservedSlot), - 16 => Ok(BasicTagType::Sequence), - 17 => Ok(BasicTagType::Set), - 18 => Ok(BasicTagType::NumericString), - 19 => Ok(BasicTagType::PrintableString), - 20 => Ok(BasicTagType::TeletexString), - 21 => Ok(BasicTagType::VideotexString), - 22 => Ok(BasicTagType::IA5String), - 23 => Ok(BasicTagType::UTCTime), - 24 => Ok(BasicTagType::GeneralizedTime), - 25 => Ok(BasicTagType::GraphicString), - 26 => Ok(BasicTagType::VisibleString), - 27 => Ok(BasicTagType::GeneralString), - 28 => Ok(BasicTagType::UniversalString), - 29 => Ok(BasicTagType::CharacterString), - 30 => Ok(BasicTagType::BMPString), - 31 => Err(TagTypeParseError::UsedSignalSlot), - _ => Err(TagTypeParseError::ValueTooLarge), - } - } -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum TagClass { - Universal = 0b00, - Application = 0b01, - ContextSpecific = 0b10, - Private = 0b11, -} - -#[cfg(test)] -impl Arbitrary for TagClass { - fn arbitrary(g: &mut G) -> TagClass { - let options = vec![ - TagClass::Universal, - TagClass::Application, - TagClass::ContextSpecific, - TagClass::Private, - ]; - let index = usize::arbitrary(g) % options.len(); - options[index] - } -} - -#[derive(Debug, PartialEq)] -pub enum TagClassParseError { - TagClassTooLarge, -} - -impl fmt::Display for TagClassParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - TagClassParseError::TagClassTooLarge => write!(f, "Tag class value is too big"), - } - } -} - -impl TryFrom for TagClass { - type Error = TagClassParseError; - - fn try_from(x: u8) -> Result { - match x { - 0 => Ok(TagClass::Universal), - 1 => Ok(TagClass::Application), - 2 => Ok(TagClass::ContextSpecific), - 3 => Ok(TagClass::Private), - _ => Err(TagClassParseError::TagClassTooLarge), - } - } -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum TagForm { - Primitive = 0, - Constructed = 1, -} - -#[cfg(test)] -impl Arbitrary for TagForm { - fn arbitrary(g: &mut G) -> TagForm { - let options = vec![TagForm::Primitive, TagForm::Constructed]; - let index = usize::arbitrary(g) % options.len(); - options[index] - } -} - -#[derive(Debug, PartialEq)] -pub enum TagFormParseError { - TagFormTooLarge, -} - -impl fmt::Display for TagFormParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - TagFormParseError::TagFormTooLarge => write!(f, "Tag form value is more than one bit"), - } - } -} - -impl TryFrom for TagForm { - type Error = TagFormParseError; - - fn try_from(x: u8) -> Result { - match x { - 0 => Ok(TagForm::Primitive), - 1 => Ok(TagForm::Constructed), - _ => Err(TagFormParseError::TagFormTooLarge), - } - } -} - -#[derive(Clone, Debug, PartialEq)] -pub enum Tag { - Simple(TagClass, TagForm, BasicTagType), - Extended(TagClass, TagForm, Vec), -} - -#[cfg(test)] -impl Arbitrary for Tag { - fn arbitrary(g: &mut G) -> Tag { - if g.next_u32() & 1 == 0 { - Tag::Simple( - TagClass::arbitrary(g), - TagForm::arbitrary(g), - BasicTagType::arbitrary(g), - ) - } else { - let mut basic_vec = Vec::::arbitrary(g); - basic_vec.push(u8::arbitrary(g)); // just to ensure there's at least one - Tag::Extended(TagClass::arbitrary(g), TagForm::arbitrary(g), basic_vec) - } - } -} - -#[derive(Debug, PartialEq)] -pub enum TagReaderError { - NotEnoughData, - InappropriateExtendedLength, - TagClassProblem(TagClassParseError), - TagFormProblem(TagFormParseError), - TagTypeProblem(TagTypeParseError), -} - -impl From for TagReaderError { - fn from(x: TagClassParseError) -> TagReaderError { - TagReaderError::TagClassProblem(x) - } -} - -impl From for TagReaderError { - fn from(x: TagFormParseError) -> TagReaderError { - TagReaderError::TagFormProblem(x) - } -} - -impl From for TagReaderError { - fn from(x: TagTypeParseError) -> TagReaderError { - TagReaderError::TagTypeProblem(x) - } -} - -#[derive(Debug, PartialEq)] -pub enum TagSerializationError { - NoExtendedTag, - ExtendedTagTooSmall, - InternalError, -} - -impl Tag { - pub fn read>(it: &mut I) -> Result { - match it.next() { - None => Err(TagReaderError::NotEnoughData), - Some(b) => { - let class = TagClass::try_from(b >> 6)?; - let form = TagForm::try_from((b >> 5) & 1)?; - let tag = b & 0b11111; - - if tag == 31 { - let mut bitstr = BitString::new(); - - // OK, here's an example of what we have to do here. - // Imagine that this tag was four bytes [67,33,30,42]: - // - // 01000011_00100001_00011110_00101010 - // - // To encode them, we're going to pad the front, and then - // group them into sevens: - // - // 0000100_0011001_0000100_0111100_0101010 - // 4 25 4 60 42 - // - // We'll then set the high bits on the first 4, giving us - // an input to this function of: - // 132 153 132 188 42 - // - // On the flip side, to parse, we need to first turn these - // back into 8 bit quantities: - // 00001000_01100100_00100011_11000101_010 - let mut ended_clean = false; - - while let Some(b) = it.next() { - bitstr.push_bits(7, b); - if b & 0b1000_0000 == 0 { - ended_clean = true; - break; - } - } - - if !ended_clean { - return Err(TagReaderError::NotEnoughData); - } - // - // which is off by three. - let padding = bitstr.len() % 8; - // - // So if we pull three bits off the front we get back to: - // 01000011_00100001_00011110_00101010 - // - let mut bititer = bitstr.bits().skip(padding); - let mut res = Vec::new(); - let mut work_byte = 0; - let mut count = 0; - - while let Some(x) = bititer.next() { - work_byte = (work_byte << 1) | (x & 1); - count += 1; - if count == 8 { - res.push(work_byte); - count = 0; - work_byte = 0; - } - } - - if count != 0 { - return Err(TagReaderError::InappropriateExtendedLength); - } - - return Ok(Tag::Extended(class, form, res)); - } - - Ok(Tag::Simple(class, form, BasicTagType::try_from(tag)?)) - } - } - } - - pub fn write(&self, buffer: &mut Vec) -> Result<(), TagSerializationError> { - match self { - Tag::Simple(class, form, basic) => { - let class_val = (*class as u8) << 6; - let form_val = (*form as u8) << 5; - let basic_val = *basic as u8; - - buffer.push(class_val | form_val | basic_val); - Ok(()) - } - Tag::Extended(class, form, value) => { - let class_val = (*class as u8) << 6; - let form_val = (*form as u8) << 5; - let basic_val = 0b00011111; - - if value.len() == 0 { - return Err(TagSerializationError::NoExtendedTag); - } - - buffer.push(class_val | form_val | basic_val); - let original_length = value.len() * 8; - let mut work_byte = 0; - let mut bits_added = if original_length % 7 == 0 { - 0 - } else { - 7 - (original_length % 7) - }; - let mut bitstream = BitString::from(value.iter().map(|x| *x)).bits().peekable(); - - while bitstream.peek().is_some() { - while bits_added < 7 { - match bitstream.next() { - None => return Err(TagSerializationError::InternalError), - Some(b) => { - bits_added += 1; - work_byte = (work_byte << 1) | b; - } - } - } - - buffer.push(0b1000_0000 | work_byte); - bits_added = 0; - work_byte = 0; - } - - let last_idx = buffer.len() - 1; - buffer[last_idx] &= 0b0111_1111; - - Ok(()) - } - } - } -} - -macro_rules! item_u8_item { - ($name: ident, $type: ident) => { - #[cfg(test)] - quickcheck! { - fn $name(t: $type) -> bool { - let t8 = t as u8; - match $type::try_from(t8) { - Err(_) => false, - Ok(t2) => t == t2, - } - } - } - }; -} - -item_u8_item!(tag_u8_tag, BasicTagType); -item_u8_item!(form_u8_form, TagForm); -item_u8_item!(class_u8_class, TagClass); - -#[cfg(test)] -quickcheck! { - fn tag_bytes_tag(t: Tag) -> bool { - let mut bytes = Vec::new(); - let () = t.write(&mut bytes).unwrap(); - let mut byteiter = bytes.iter().map(|x| *x); - match Tag::read(&mut byteiter) { - Err(e) => { - // println!("Error result: {:?}", e); - false - } - Ok(t2) => { - // println!("Result: {:?}", t2); - t == t2 - } - } - } -} +pub use crate::ber::tag::*; +pub use crate::ber::length::*; +pub use crate::ber::value::*; diff --git a/src/ber/length.rs b/src/ber/length.rs new file mode 100644 index 0000000..664d360 --- /dev/null +++ b/src/ber/length.rs @@ -0,0 +1,200 @@ +use alloc::vec::Vec; +use core::convert::TryFrom; +use crate::ber::tag::Tag; +use crate::ber::value::ValueReaderError; +#[cfg(test)] +use crate::ber::tag::{TagClass, TagForm, BasicTagType}; +use crate::number::Number; +use crate::util::BufferReader; +#[cfg(test)] +use quickcheck::{quickcheck, Arbitrary, Gen}; + +#[derive(Clone, Debug, PartialEq)] +pub enum Length { + Short(usize), + Long(Number), + Indefinite, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum ConversionError { + ValueTooLarge, + Unconvertable, +} + +impl From for ValueReaderError { + fn from(x: ConversionError) -> ValueReaderError { + match x { + ConversionError::ValueTooLarge => ValueReaderError::LengthTooBig, + ConversionError::Unconvertable => ValueReaderError::LengthIncompatible, + } + } +} + +impl<'a> TryFrom<&'a Length> for usize { + type Error = ConversionError; + + fn try_from(x: &Length) -> Result { + match x { + Length::Short(x) => Ok(*x), + Length::Long(ref v) => usize::try_from(v), + Length::Indefinite => Err(ConversionError::Unconvertable), + } + } +} + +impl From for Length { + fn from(x: usize) -> Self { + Length::Short(x) + } +} + +#[cfg(test)] +impl Arbitrary for Length { + fn arbitrary(g: &mut G) -> Length { + match g.next_u32() % 3 { + 0 => Length::Short(usize::arbitrary(g) % 128), + 1 => Length::Long(Number::arbitrary(g)), + 2 => Length::Indefinite, + _ => panic!("Mathematics broke."), + } + } +} + +#[derive(Debug, PartialEq)] +pub enum LengthReaderError { + NotEnoughData, + IllegalConstructedFound, + IllegalLong, +} + +#[derive(Debug, PartialEq)] +pub enum LengthWriterError { + SizeTooLarge, +} + +impl Length { + /// Read the next length value from the provided iterator, in the context of the provided tag. + /// (In some cases, the tag will allow or disallow certain forms of length field, hence the + /// need for the context.) + pub fn read>(tag: &Tag, it: &mut I) -> Result { + let constructed_form_allowed = !tag.has_primitive_form(); + + match it.next() { + None => + Err(LengthReaderError::NotEnoughData), + Some(l) if l < 128 => + Ok(Length::Short(l as usize)), + Some(l) if l == 0b1000_0000 && constructed_form_allowed => + Ok(Length::Indefinite), + Some(l) if l == 0b1111_1111 => + Err(LengthReaderError::IllegalLong), + Some(l) => { + let bytelen = (l & 0b0111_1111) as usize; + match bytelen.read_buffer(it) { + None => Err(LengthReaderError::NotEnoughData), + Some(bytes) => { + let num = Number::from_bytes(&bytes); + Ok(Length::Long(num)) + } + } + } + } + } + + /// Write the start of a length value to the data stream. Unfortunately, for lengths, you may + /// also need to write something after the value, as well; for that, use `write_postfix` to + /// ensure you frame the length appropriately. + pub fn write(&self, buffer: &mut Vec) -> Result<(), LengthWriterError> { + match self { + Length::Short(s) if *s > 127 => + Err(LengthWriterError::SizeTooLarge), + Length::Short(s) => { + buffer.push(*s as u8); + Ok(()) + } + Length::Long(n) => { + let bytes = n.serialize(); + + if bytes.len() > 127 { + return Err(LengthWriterError::SizeTooLarge); + } + + buffer.push((bytes.len() as u8) | 0b1000_0000); + for x in bytes.iter() { + buffer.push(*x); + } + Ok(()) + } + Length::Indefinite => { + buffer.push(0b1000_0000); + Ok(()) + } + } + } + + /// Write, if required, the postfix bytes to the object. This is only relevant for a very + /// narrow set of types, but I suggest calling it no matter what; it will never do harm to call + /// it. + pub fn write_postfix(&self, buffer: &mut Vec) { + match self { + Length::Indefinite => { + buffer.push(0b0000_0000); + buffer.push(0b0000_0000); + } + _ => {} + } + } +} + +impl BufferReader for Length { + fn read_buffer>(&self, it: &mut I) -> Option> { + match self { + Length::Indefinite => { + let mut res = Vec::new(); + let mut successive_zeros = 0; + + while successive_zeros < 2 { + let next = it.next()?; + + if next == 0 { + successive_zeros += 1; + } else { + successive_zeros = 0; + } + + res.push(next); + } + + res.truncate(res.len() - 2); + Some(res) + } + Length::Long(x) => match usize::try_from(x) { + Err(_) => None, + Ok(x) => x.read_buffer(it), + } + Length::Short(x) => x.read_buffer(it), + } + } +} + +#[cfg(test)] +quickcheck! { + fn length_bytes_length(l: Length) -> bool { + let form = if l == Length::Indefinite { TagForm::Constructed } else { TagForm::Primitive }; + let tag = Tag::Simple(TagClass::Universal, form, BasicTagType::Boolean); + let mut output = Vec::new(); + l.write(&mut output).unwrap(); + let mut outiter = output.iter().map(|x| *x); + match Length::read(&tag, &mut outiter) { + Err(e) => { + println!("Error found: {:?}", e); + false + } + Ok(l2) => { + println!("Result: {:?}", l2); + l == l2 + } + } + } +} diff --git a/src/ber/tag.rs b/src/ber/tag.rs new file mode 100644 index 0000000..0ff3907 --- /dev/null +++ b/src/ber/tag.rs @@ -0,0 +1,456 @@ +use alloc::vec::Vec; +use core::convert::TryFrom; +use core::fmt; +use crate::bitstring::BitString; +use crate::lift_error; +#[cfg(test)] +use quickcheck::{quickcheck, Arbitrary, Gen}; + +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum BasicTagType { + Boolean = 1, + Integer = 2, + BitString = 3, + OctetString = 4, + Null = 5, + ObjectIdentifier = 6, + ObjectDescriptor = 7, + External = 8, + Real = 9, + Enumerated = 10, + EmbeddedBDV = 11, + UTF8String = 12, + RelativeOID = 13, + Sequence = 16, + Set = 17, + NumericString = 18, + PrintableString = 19, + TeletexString = 20, + VideotexString = 21, + IA5String = 22, + UTCTime = 23, + GeneralizedTime = 24, + GraphicString = 25, + VisibleString = 26, + GeneralString = 27, + UniversalString = 28, + CharacterString = 29, + BMPString = 30, +} + +#[cfg(test)] +impl Arbitrary for BasicTagType { + fn arbitrary(g: &mut G) -> BasicTagType { + let options = vec![ + BasicTagType::Boolean, + BasicTagType::Integer, + BasicTagType::BitString, + BasicTagType::OctetString, + BasicTagType::Null, + BasicTagType::ObjectIdentifier, + BasicTagType::ObjectDescriptor, + BasicTagType::External, + BasicTagType::Real, + BasicTagType::Enumerated, + BasicTagType::EmbeddedBDV, + BasicTagType::UTF8String, + BasicTagType::RelativeOID, + BasicTagType::Sequence, + BasicTagType::Set, + BasicTagType::NumericString, + BasicTagType::PrintableString, + BasicTagType::TeletexString, + BasicTagType::VideotexString, + BasicTagType::IA5String, + BasicTagType::UTCTime, + BasicTagType::GeneralizedTime, + BasicTagType::GraphicString, + BasicTagType::VisibleString, + BasicTagType::GeneralString, + BasicTagType::UniversalString, + BasicTagType::CharacterString, + BasicTagType::BMPString, + ]; + let index = usize::arbitrary(g) % options.len(); + options[index] + } +} + +#[derive(Debug, PartialEq)] +pub enum TagTypeParseError { + UsedReservedSlot, + UsedSignalSlot, + ValueTooLarge, +} + +impl fmt::Display for TagTypeParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TagTypeParseError::UsedReservedSlot => write!( + f, + "Tag type value was one marked reserved in our specification." + ), + TagTypeParseError::UsedSignalSlot => write!( + f, + "Tag type value was the one that signals a multi-byte tag." + ), + TagTypeParseError::ValueTooLarge => { + write!(f, "Tag type value was much too large for us.") + } + } + } +} + +impl TryFrom for BasicTagType { + type Error = TagTypeParseError; + + fn try_from(x: u8) -> Result { + match x { + 0 => Err(TagTypeParseError::UsedReservedSlot), + 1 => Ok(BasicTagType::Boolean), + 2 => Ok(BasicTagType::Integer), + 3 => Ok(BasicTagType::BitString), + 4 => Ok(BasicTagType::OctetString), + 5 => Ok(BasicTagType::Null), + 6 => Ok(BasicTagType::ObjectIdentifier), + 7 => Ok(BasicTagType::ObjectDescriptor), + 8 => Ok(BasicTagType::External), + 9 => Ok(BasicTagType::Real), + 10 => Ok(BasicTagType::Enumerated), + 11 => Ok(BasicTagType::EmbeddedBDV), + 12 => Ok(BasicTagType::UTF8String), + 13 => Ok(BasicTagType::RelativeOID), + 14 => Err(TagTypeParseError::UsedReservedSlot), + 15 => Err(TagTypeParseError::UsedReservedSlot), + 16 => Ok(BasicTagType::Sequence), + 17 => Ok(BasicTagType::Set), + 18 => Ok(BasicTagType::NumericString), + 19 => Ok(BasicTagType::PrintableString), + 20 => Ok(BasicTagType::TeletexString), + 21 => Ok(BasicTagType::VideotexString), + 22 => Ok(BasicTagType::IA5String), + 23 => Ok(BasicTagType::UTCTime), + 24 => Ok(BasicTagType::GeneralizedTime), + 25 => Ok(BasicTagType::GraphicString), + 26 => Ok(BasicTagType::VisibleString), + 27 => Ok(BasicTagType::GeneralString), + 28 => Ok(BasicTagType::UniversalString), + 29 => Ok(BasicTagType::CharacterString), + 30 => Ok(BasicTagType::BMPString), + 31 => Err(TagTypeParseError::UsedSignalSlot), + _ => Err(TagTypeParseError::ValueTooLarge), + } + } +} + +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum TagClass { + Universal = 0b00, + Application = 0b01, + ContextSpecific = 0b10, + Private = 0b11, +} + +#[cfg(test)] +impl Arbitrary for TagClass { + fn arbitrary(g: &mut G) -> TagClass { + let options = vec![ + TagClass::Universal, + TagClass::Application, + TagClass::ContextSpecific, + TagClass::Private, + ]; + let index = usize::arbitrary(g) % options.len(); + options[index] + } +} + +#[derive(Debug, PartialEq)] +pub enum TagClassParseError { + TagClassTooLarge, +} + +impl fmt::Display for TagClassParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TagClassParseError::TagClassTooLarge => write!(f, "Tag class value is too big"), + } + } +} + +impl TryFrom for TagClass { + type Error = TagClassParseError; + + fn try_from(x: u8) -> Result { + match x { + 0 => Ok(TagClass::Universal), + 1 => Ok(TagClass::Application), + 2 => Ok(TagClass::ContextSpecific), + 3 => Ok(TagClass::Private), + _ => Err(TagClassParseError::TagClassTooLarge), + } + } +} + +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum TagForm { + Primitive = 0, + Constructed = 1, +} + +#[cfg(test)] +impl Arbitrary for TagForm { + fn arbitrary(g: &mut G) -> TagForm { + let options = vec![TagForm::Primitive, TagForm::Constructed]; + let index = usize::arbitrary(g) % options.len(); + options[index] + } +} + +#[derive(Debug, PartialEq)] +pub enum TagFormParseError { + TagFormTooLarge, +} + +impl fmt::Display for TagFormParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TagFormParseError::TagFormTooLarge => write!(f, "Tag form value is more than one bit"), + } + } +} + +impl TryFrom for TagForm { + type Error = TagFormParseError; + + fn try_from(x: u8) -> Result { + match x { + 0 => Ok(TagForm::Primitive), + 1 => Ok(TagForm::Constructed), + _ => Err(TagFormParseError::TagFormTooLarge), + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum Tag { + Simple(TagClass, TagForm, BasicTagType), + Extended(TagClass, TagForm, Vec), +} + +#[cfg(test)] +impl Arbitrary for Tag { + fn arbitrary(g: &mut G) -> Tag { + if g.next_u32() & 1 == 0 { + Tag::Simple( + TagClass::arbitrary(g), + TagForm::arbitrary(g), + BasicTagType::arbitrary(g), + ) + } else { + let mut basic_vec = Vec::::arbitrary(g); + basic_vec.push(u8::arbitrary(g)); // just to ensure there's at least one + Tag::Extended(TagClass::arbitrary(g), TagForm::arbitrary(g), basic_vec) + } + } +} + +#[derive(Debug, PartialEq)] +pub enum TagReaderError { + NotEnoughData, + InappropriateExtendedLength, + TagClassProblem(TagClassParseError), + TagFormProblem(TagFormParseError), + TagTypeProblem(TagTypeParseError), +} + +lift_error!(TagClassParseError, TagClassProblem, TagReaderError); +lift_error!(TagFormParseError, TagFormProblem, TagReaderError); +lift_error!(TagTypeParseError, TagTypeProblem, TagReaderError); + +#[derive(Debug, PartialEq)] +pub enum TagSerializationError { + NoExtendedTag, + ExtendedTagTooSmall, + InternalError, +} + +impl Tag { + pub fn has_primitive_form(&self) -> bool { + match self { + Tag::Simple(_, TagForm::Primitive, _) => true, + Tag::Extended(_, TagForm::Primitive, _) => true, + _ => false, + } + } + + pub fn read>(it: &mut I) -> Result { + match it.next() { + None => Err(TagReaderError::NotEnoughData), + Some(b) => { + let class = TagClass::try_from(b >> 6)?; + let form = TagForm::try_from((b >> 5) & 1)?; + let tag = b & 0b11111; + + if tag == 31 { + let mut bitstr = BitString::new(); + + // OK, here's an example of what we have to do here. + // Imagine that this tag was four bytes [67,33,30,42]: + // + // 01000011_00100001_00011110_00101010 + // + // To encode them, we're going to pad the front, and then + // group them into sevens: + // + // 0000100_0011001_0000100_0111100_0101010 + // 4 25 4 60 42 + // + // We'll then set the high bits on the first 4, giving us + // an input to this function of: + // 132 153 132 188 42 + // + // On the flip side, to parse, we need to first turn these + // back into 8 bit quantities: + // 00001000_01100100_00100011_11000101_010 + let mut ended_clean = false; + + while let Some(b) = it.next() { + bitstr.push_bits(7, b); + if b & 0b1000_0000 == 0 { + ended_clean = true; + break; + } + } + + if !ended_clean { + return Err(TagReaderError::NotEnoughData); + } + // + // which is off by three. + let padding = bitstr.len() % 8; + // + // So if we pull three bits off the front we get back to: + // 01000011_00100001_00011110_00101010 + // + let mut bititer = bitstr.bits().skip(padding); + let mut res = Vec::new(); + let mut work_byte = 0; + let mut count = 0; + + while let Some(x) = bititer.next() { + work_byte = (work_byte << 1) | (x & 1); + count += 1; + if count == 8 { + res.push(work_byte); + count = 0; + work_byte = 0; + } + } + + if count != 0 { + return Err(TagReaderError::InappropriateExtendedLength); + } + + return Ok(Tag::Extended(class, form, res)); + } + + Ok(Tag::Simple(class, form, BasicTagType::try_from(tag)?)) + } + } + } + + pub fn write(&self, buffer: &mut Vec) -> Result<(), TagSerializationError> { + match self { + Tag::Simple(class, form, basic) => { + let class_val = (*class as u8) << 6; + let form_val = (*form as u8) << 5; + let basic_val = *basic as u8; + + buffer.push(class_val | form_val | basic_val); + Ok(()) + } + Tag::Extended(class, form, value) => { + let class_val = (*class as u8) << 6; + let form_val = (*form as u8) << 5; + let basic_val = 0b00011111; + + if value.len() == 0 { + return Err(TagSerializationError::NoExtendedTag); + } + + buffer.push(class_val | form_val | basic_val); + let original_length = value.len() * 8; + let mut work_byte = 0; + let mut bits_added = if original_length % 7 == 0 { + 0 + } else { + 7 - (original_length % 7) + }; + let mut bitstream = BitString::from(value.iter().map(|x| *x)).bits().peekable(); + + while bitstream.peek().is_some() { + while bits_added < 7 { + match bitstream.next() { + None => return Err(TagSerializationError::InternalError), + Some(b) => { + bits_added += 1; + work_byte = (work_byte << 1) | b; + } + } + } + + buffer.push(0b1000_0000 | work_byte); + bits_added = 0; + work_byte = 0; + } + + let last_idx = buffer.len() - 1; + buffer[last_idx] &= 0b0111_1111; + + Ok(()) + } + } + } +} + +macro_rules! item_u8_item { + ($name: ident, $type: ident) => { + #[cfg(test)] + quickcheck! { + fn $name(t: $type) -> bool { + let t8 = t as u8; + match $type::try_from(t8) { + Err(_) => false, + Ok(t2) => t == t2, + } + } + } + }; +} + +item_u8_item!(tag_u8_tag, BasicTagType); +item_u8_item!(form_u8_form, TagForm); +item_u8_item!(class_u8_class, TagClass); + +#[cfg(test)] +quickcheck! { + fn tag_bytes_tag(t: Tag) -> bool { + let mut bytes = Vec::new(); + let () = t.write(&mut bytes).unwrap(); + let mut byteiter = bytes.iter().map(|x| *x); + match Tag::read(&mut byteiter) { + Err(e) => { + // println!("Error result: {:?}", e); + false + } + Ok(t2) => { + // println!("Result: {:?}", t2); + t == t2 + } + } + } +} diff --git a/src/ber/value.rs b/src/ber/value.rs new file mode 100644 index 0000000..89abbf5 --- /dev/null +++ b/src/ber/value.rs @@ -0,0 +1,94 @@ +use crate::ber::length::{Length, LengthReaderError, LengthWriterError}; +use crate::ber::tag::{Tag, TagClass, TagForm, TagReaderError, TagSerializationError, BasicTagType}; +use crate::lift_error; +use crate::number::Number; +use crate::util::BufferReader; + +pub enum Value { + Boolean(TagClass, TagForm, bool), + Integer(TagClass, TagForm, Number), + Null(TagClass, TagForm), +} + +pub enum ValueReaderError { + LengthIncompatible, + LengthTooBig, + NotEnoughData, + TagReaderProblem(TagReaderError), + LengthReaderError(LengthReaderError), +} + +lift_error!(TagReaderError, TagReaderProblem, ValueReaderError); +lift_error!(LengthReaderError, ValueReaderError); + +pub enum ValueWriterError { + Length(LengthWriterError), + Tag(TagSerializationError), +} + +lift_error!(LengthWriterError, Length, ValueWriterError); +lift_error!(TagSerializationError, Tag, ValueWriterError); + +impl Value { + /// Read a value from the provided iterator. + pub fn read>(it: &mut I) -> Result { + let tag = Tag::read(it)?; + let length = Length::read(&tag, it)?; + let bytes: Vec = match length.read_buffer(it) { + None => return Err(ValueReaderError::NotEnoughData), + Some(x) => x, + }; + + match tag { + Tag::Simple(c, f, BasicTagType::Boolean) => { + match it.next() { + None => Err(ValueReaderError::NotEnoughData), + Some(0) => Ok(Value::Boolean(c, f, false)), + Some(_) => Ok(Value::Boolean(c, f, true)), + } + } + + Tag::Simple(c, f, BasicTagType::Null) => + Ok(Value::Null(c, f)), + + Tag::Simple(c, f, BasicTagType::Integer) => { + let res = Number::from_bytes(&bytes); + Ok(Value::Integer(c, f, res)) + } + + _ => + unimplemented!("Cannot parse tag {:?}", tag) + } + } + + /// Serialize the value to the given buffer. Note that this writes the full definiton of the + /// value: it's type, it's length, and the value itself. + pub fn write(&self, buffer: &mut Vec) -> Result<(), ValueWriterError> { + match self { + Value::Boolean(cl, form, v) => { + Length::from(1).write(buffer)?; + Tag::Simple(*cl, *form, BasicTagType::Boolean).write(buffer)?; + if *v { + buffer.push(0b10101010); + } else { + buffer.push(0b00000000); + } + Ok(()) + } + + Value::Integer(c, f, n) => { + let mut bytes = n.serialize(); + Length::from(bytes.len()).write(buffer)?; + Tag::Simple(*c, *f, BasicTagType::Integer).write(buffer)?; + buffer.append(&mut bytes); + Ok(()) + } + + Value::Null(c, f) => { + Length::from(0).write(buffer)?; + Tag::Simple(*c, *f, BasicTagType::Null).write(buffer)?; + Ok(()) + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 2bdb2db..355971e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,8 @@ extern crate alloc; mod ber; mod bitstring; +mod number; +mod util; use chrono::{DateTime, TimeZone, Utc}; pub use num_bigint::{BigInt, BigUint}; diff --git a/src/number.rs b/src/number.rs new file mode 100644 index 0000000..6f72b39 --- /dev/null +++ b/src/number.rs @@ -0,0 +1,186 @@ +use core::convert::TryFrom; +use crate::ber::length::ConversionError; +#[cfg(test)] +use quickcheck::{quickcheck, Arbitrary, Gen}; + +#[derive(Clone, Debug, PartialEq)] +pub struct Number { + value: Vec, + bits: usize, +} + +#[cfg(test)] +impl Arbitrary for Number { + fn arbitrary(g: &mut G) -> Number { + let bytes = u8::arbitrary(g) as usize; + let digits = (bytes + 7) / 8; + let bits = bytes * 8; + + let mut value = Vec::with_capacity(digits); + for _ in 0..digits { + value.push(g.next_u64()); + } + + if digits > 0 { + let spare_bits = (digits * 64) - bits; + let mask = 0xFFFFFFFFFFFFFFFFu64 >> spare_bits; + value[digits - 1] &= mask; + } + + Number { + value, + bits, + } + } +} + +impl Number { + pub fn new() -> Number { + Number { + value: Vec::new(), + bits: 0 + } + } + + pub fn serialize(&self) -> Vec { + let serialized_bytes = (self.bits + 7) / 8; + let mut res = Vec::with_capacity(serialized_bytes); + + for idx in 0..serialized_bytes { + let byte_off = serialized_bytes - idx - 1; + let val64_off = byte_off / 8; + let internal_bit_off = (byte_off % 8) * 8; + let val = (self.value[val64_off] >> internal_bit_off) & 0xff; + + res.push(val as u8); + } + + res + } + + pub fn from_bytes(bytes: &[u8]) -> Number { + let bits = bytes.len() * 8; + let digit_len = (bytes.len() + 7) / 8; + let mut value = Vec::with_capacity(digit_len); + let mut bytes_added = 0; + let mut next = 0u64; + + for x in bytes.iter().rev() { + next += (*x as u64) << (bytes_added * 8); + bytes_added += 1; + if bytes_added == 8 { + value.push(next); + next = 0; + bytes_added = 0; + } + } + + if bytes_added != 0 { + value.push(next); + } + + Number { value, bits } + } +} + +#[cfg(test)] +#[test] +fn basic_serialization() { + assert_eq!(Number::new().serialize(), vec![]); + // + let one = Number { + value: vec![1], + bits: 8, + }; + let onevec = vec![1]; + assert_eq!(one.serialize(), onevec); + assert_eq!(Number::from_bytes(&onevec), one); + // + let one_oh_oh_one = Number { + value: vec![0x1001], + bits: 16, + }; + let one_oh_oh_one_vec = vec![0x10,0x01]; + assert_eq!(one_oh_oh_one.serialize(), one_oh_oh_one_vec); + assert_eq!(Number::from_bytes(&one_oh_oh_one_vec), one_oh_oh_one); + // + let one_to_nine = Number { + value: vec![0x0807060504030201, 0x09], + bits: 72, + }; + let one_to_nine_vec = vec![0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01]; + assert_eq!(one_to_nine.serialize(), one_to_nine_vec); + assert_eq!(Number::from_bytes(&one_to_nine_vec), one_to_nine); +} + +#[cfg(test)] +#[derive(Clone, Debug)] +struct SmallByteArray { + a: Vec +} + +#[cfg(test)] +impl Arbitrary for SmallByteArray { + fn arbitrary(g: &mut G) -> SmallByteArray { + let len = u8::arbitrary(g); + let mut a = Vec::with_capacity(len as usize); + for _ in 0..len { + a.push(u8::arbitrary(g)); + } + SmallByteArray{ a } + } +} + +#[cfg(test)] +quickcheck! { + fn bytes_num_bytes(x: SmallByteArray) -> bool { + let num = Number::from_bytes(&x.a); + let y = num.serialize(); + println!("x.a: {:?}", x.a); + println!("y: {:?}", y); + &x.a == &y + } + + fn num_bytes_num(x: Number) -> bool { + let bytes = x.serialize(); + let y = Number::from_bytes(&bytes); + println!("x: {:?}", x); + println!("b: {:?}", bytes); + println!("y: {:?}", y); + x == y + } +} + +impl From for Number { + fn from(x: u8) -> Number { + Number { + value: vec![x as u64], + bits: 8, + } + } +} + +impl<'a> TryFrom<&'a Number> for usize { + type Error = ConversionError; + + fn try_from(x: &Number) -> Result { + if x.value.iter().skip(1).all(|v| *v == 0) { + if x.value.len() == 0 { + return Ok(0); + } + + let mut value = x.value[0]; + + if x.bits < 64 { + value &= 0xFFFFFFFFFFFFFFFFu64 >> (64 - x.bits); + } + + match usize::try_from(value) { + Err(_) => Err(ConversionError::ValueTooLarge), + Ok(v) => Ok(v) + } + } else { + Err(ConversionError::ValueTooLarge) + } + } +} diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..84a7352 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,33 @@ +use alloc::vec::Vec; + +pub trait BufferReader { + fn read_buffer>(&self, it: &mut I) -> Option>; +} + +impl BufferReader for usize { + fn read_buffer>(&self, it: &mut I) -> Option> { + let me = *self; + let mut res = Vec::with_capacity(me); + + while res.len() < me { + let n = it.next()?; + res.push(n); + } + + Some(res) + } +} + +#[macro_export] +macro_rules! lift_error { + ($fromt: ident, $tot: ident) => { + lift_error!($fromt, $fromt, $tot); + }; + ($fromt: ident, $const: ident, $tot: ident) => { + impl From<$fromt> for $tot { + fn from(x: $fromt) -> $tot { + $tot::$const(x) + } + } + } +}