diff --git a/crates/asn1-parser/README.md b/crates/asn1-parser/README.md index 87610fd9..facf5cc4 100644 --- a/crates/asn1-parser/README.md +++ b/crates/asn1-parser/README.md @@ -38,6 +38,7 @@ This `asn1` parser is aimed to parse input bytes and return an AST as the result --- - [X] [Integer](https://www.oss.com/asn1/resources/asn1-made-simple/asn1-quick-reference/integer.html) +- [X] [Enumerated](https://www.oss.com/asn1/resources/asn1-made-simple/asn1-quick-reference/enumerated.html) - [X] [Boolean](https://www.oss.com/asn1/resources/asn1-made-simple/asn1-quick-reference/boolean.html) - [X] [Null](https://www.oss.com/asn1/resources/asn1-made-simple/asn1-quick-reference/null.html) - [X] [ObjectIdentifier](https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-object-identifier) @@ -61,4 +62,4 @@ This `asn1` parser is aimed to parse input bytes and return an AST as the result ```rust todo!(); -``` \ No newline at end of file +``` diff --git a/crates/asn1-parser/src/asn1.rs b/crates/asn1-parser/src/asn1.rs index 3e17a492..e74881f3 100644 --- a/crates/asn1-parser/src/asn1.rs +++ b/crates/asn1-parser/src/asn1.rs @@ -4,9 +4,10 @@ use core::ops::Range; use crate::reader::Reader; use crate::writer::Writer; use crate::{ - ApplicationTag, Asn1Encoder, Asn1Result, Asn1ValueDecoder, BitString, BmpString, Bool, Error, ExplicitTag, - GeneralString, GeneralizedTime, IA5String, ImplicitTag, Integer, MetaInfo, Null, NumericString, ObjectIdentifier, - OctetString, PrintableString, Sequence, Set, Tag, Taggable, Tlv, UtcTime, Utf8String, VisibleString, + ApplicationTag, Asn1Encoder, Asn1Result, Asn1ValueDecoder, BitString, BmpString, Bool, Enumerated, Error, + ExplicitTag, GeneralString, GeneralizedTime, IA5String, ImplicitTag, Integer, MetaInfo, Null, NumericString, + ObjectIdentifier, OctetString, PrintableString, Sequence, Set, Tag, Taggable, Tlv, UtcTime, Utf8String, + VisibleString, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -30,6 +31,7 @@ pub enum Asn1Type<'data> { Bool(Bool), Null(Null), Integer(Integer<'data>), + Enumerated(Enumerated<'data>), ObjectIdentifier(ObjectIdentifier), ExplicitTag(ExplicitTag<'data>), @@ -58,6 +60,7 @@ impl Asn1Type<'_> { Asn1Type::Bool(b) => Asn1Type::Bool(b.clone()), Asn1Type::Null(n) => Asn1Type::Null(n.clone()), Asn1Type::Integer(i) => Asn1Type::Integer(i.to_owned()), + Asn1Type::Enumerated(e) => Asn1Type::Enumerated(e.to_owned()), Asn1Type::ObjectIdentifier(o) => Asn1Type::ObjectIdentifier(o.clone()), Asn1Type::ExplicitTag(e) => Asn1Type::ExplicitTag(e.to_owned()), Asn1Type::ImplicitTag(i) => Asn1Type::ImplicitTag(i.to_owned()), @@ -86,6 +89,7 @@ impl Taggable for Asn1Type<'_> { Asn1Type::Bool(b) => b.tag(), Asn1Type::Null(n) => n.tag(), Asn1Type::Integer(i) => i.tag(), + Asn1Type::Enumerated(e) => e.tag(), Asn1Type::ObjectIdentifier(o) => o.tag(), Asn1Type::ExplicitTag(e) => e.tag(), Asn1Type::ImplicitTag(i) => i.tag(), @@ -97,7 +101,10 @@ impl Taggable for Asn1Type<'_> { } impl<'data> Asn1ValueDecoder<'data> for Asn1Type<'data> { + #[instrument(level = "debug", ret)] fn decode(tag: Tag, reader: &mut Reader<'data>) -> Asn1Result { + debug!(?tag); + decode_asn1!( OctetString, Utf8String, @@ -112,6 +119,7 @@ impl<'data> Asn1ValueDecoder<'data> for Asn1Type<'data> { VisibleString, Bool, Integer, + Enumerated, ObjectIdentifier, ExplicitTag, ImplicitTag, @@ -122,7 +130,7 @@ impl<'data> Asn1ValueDecoder<'data> for Asn1Type<'data> { in tag, reader ); - Err(Error::from("Invalid asn1 data")) + Err(Error::from("Invalid or unsupported asn1 tag")) } fn compare_tags(_tag: Tag) -> bool { @@ -146,6 +154,7 @@ impl Asn1Encoder for Asn1Type<'_> { Asn1Type::VisibleString(g) => g.needed_buf_size(), Asn1Type::Bool(boolean) => boolean.needed_buf_size(), Asn1Type::Integer(integer) => integer.needed_buf_size(), + Asn1Type::Enumerated(enumerated) => enumerated.needed_buf_size(), Asn1Type::ObjectIdentifier(object_identifier) => object_identifier.needed_buf_size(), Asn1Type::ExplicitTag(e) => e.needed_buf_size(), Asn1Type::ImplicitTag(i) => i.needed_buf_size(), @@ -171,6 +180,7 @@ impl Asn1Encoder for Asn1Type<'_> { Asn1Type::VisibleString(numeric) => numeric.encode(writer), Asn1Type::Bool(boolean) => boolean.encode(writer), Asn1Type::Integer(integer) => integer.encode(writer), + Asn1Type::Enumerated(enumerated) => enumerated.encode(writer), Asn1Type::ObjectIdentifier(object_identifier) => object_identifier.encode(writer), Asn1Type::ExplicitTag(e) => e.encode(writer), Asn1Type::ImplicitTag(i) => i.encode(writer), @@ -198,6 +208,7 @@ impl MetaInfo for Asn1Type<'_> { Asn1Type::VisibleString(_) => {} Asn1Type::Bool(_) => {} Asn1Type::Integer(_) => {} + Asn1Type::Enumerated(_) => {} Asn1Type::ObjectIdentifier(_) => {} Asn1Type::ExplicitTag(explicit_tag) => explicit_tag.clear_meta(), Asn1Type::ImplicitTag(implicit_tag) => implicit_tag.clear_meta(), diff --git a/crates/asn1-parser/src/primitives/enumerated.rs b/crates/asn1-parser/src/primitives/enumerated.rs new file mode 100644 index 00000000..88218eee --- /dev/null +++ b/crates/asn1-parser/src/primitives/enumerated.rs @@ -0,0 +1,76 @@ +use alloc::borrow::Cow; +use alloc::vec::Vec; + +use num_bigint_dig::BigUint; + +use crate::length::{len_size, write_len}; +use crate::reader::Reader; +use crate::writer::Writer; +use crate::{Asn1Encoder, Asn1Result, Asn1ValueDecoder, Tag, Taggable}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Enumerated<'data>(Cow<'data, [u8]>); + +pub type OwnedEnumerated = Enumerated<'static>; + +impl Enumerated<'_> { + pub const TAG: Tag = Tag(10); + + pub fn raw_data(&self) -> &[u8] { + self.0.as_ref() + } + + pub fn as_big_uint(&self) -> BigUint { + BigUint::from_bytes_be(if self.0.len() > 1 { + if self.0[0] == 0x00 { + &self.0[1..] + } else { + &self.0 + } + } else if self.0.is_empty() { + &[0] + } else { + &self.0 + }) + } + + pub fn to_owned(&self) -> OwnedEnumerated { + Enumerated(Cow::Owned(self.0.as_ref().to_vec())) + } +} + +impl From> for OwnedEnumerated { + fn from(bytes: Vec) -> Self { + Self(Cow::Owned(bytes)) + } +} + +impl Taggable for Enumerated<'_> { + fn tag(&self) -> Tag { + Self::TAG + } +} + +impl<'data> Asn1ValueDecoder<'data> for Enumerated<'data> { + fn decode(_: Tag, reader: &mut Reader<'data>) -> Asn1Result { + Ok(Self(Cow::Borrowed(reader.remaining()))) + } + + fn compare_tags(tag: Tag) -> bool { + Self::TAG == tag + } +} + +impl Asn1Encoder for Enumerated<'_> { + fn needed_buf_size(&self) -> usize { + let data_len = self.0.len(); + + 1 /* tag */ + len_size(data_len) + data_len + } + + fn encode(&self, writer: &mut Writer) -> Asn1Result<()> { + writer.write_byte(Self::TAG.into())?; + write_len(self.0.len(), writer)?; + writer.write_slice(self.0.as_ref()) + } +} diff --git a/crates/asn1-parser/src/primitives/mod.rs b/crates/asn1-parser/src/primitives/mod.rs index 5e219856..a343fa54 100644 --- a/crates/asn1-parser/src/primitives/mod.rs +++ b/crates/asn1-parser/src/primitives/mod.rs @@ -1,9 +1,11 @@ mod boolean; +mod enumerated; mod integer; mod null; mod object_identifier; pub use boolean::Bool; +pub use enumerated::{Enumerated, OwnedEnumerated}; pub use integer::{Integer, OwnedInteger}; pub use null::Null; pub use object_identifier::ObjectIdentifier; diff --git a/crates/asn1-parser/src/tlv.rs b/crates/asn1-parser/src/tlv.rs index 7665cd90..297ccc83 100644 --- a/crates/asn1-parser/src/tlv.rs +++ b/crates/asn1-parser/src/tlv.rs @@ -73,6 +73,8 @@ impl<'data, A: Asn1ValueDecoder<'data> + Debug> Asn1Decoder<'data> for Tlv<'data let (data, data_range) = read_data(reader, len)?; + trace!(?tag, ?len, ?data); + let mut inner_reader = Reader::new(data); inner_reader.set_next_id(reader.next_id()); inner_reader.set_offset(reader.full_offset() - data.len());