diff options
Diffstat (limited to 'rust/vendor/asn1-rs/src/ber/parser.rs')
-rw-r--r-- | rust/vendor/asn1-rs/src/ber/parser.rs | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/rust/vendor/asn1-rs/src/ber/parser.rs b/rust/vendor/asn1-rs/src/ber/parser.rs new file mode 100644 index 0000000..fdfdb88 --- /dev/null +++ b/rust/vendor/asn1-rs/src/ber/parser.rs @@ -0,0 +1,169 @@ +use crate::error::*; +use crate::header::*; +use crate::{BerParser, DerParser, FromBer, Length, Tag}; +use nom::bytes::streaming::take; +use nom::{Err, Needed, Offset}; +use rusticata_macros::custom_check; + +/// Default maximum recursion limit +pub const MAX_RECURSION: usize = 50; + +/// Default maximum object size (2^32) +// pub const MAX_OBJECT_SIZE: usize = 4_294_967_295; + +pub trait GetObjectContent { + /// Return the raw content (bytes) of the next ASN.1 encoded object + /// + /// Note: if using BER and length is indefinite, terminating End-Of-Content is NOT included + fn get_object_content<'a>( + i: &'a [u8], + hdr: &'_ Header, + max_depth: usize, + ) -> ParseResult<'a, &'a [u8]>; +} + +impl GetObjectContent for BerParser { + fn get_object_content<'a>( + i: &'a [u8], + hdr: &'_ Header, + max_depth: usize, + ) -> ParseResult<'a, &'a [u8]> { + let start_i = i; + let (i, _) = ber_skip_object_content(i, hdr, max_depth)?; + let len = start_i.offset(i); + let (content, i) = start_i.split_at(len); + // if len is indefinite, there are 2 extra bytes for EOC + if hdr.length == Length::Indefinite { + let len = content.len(); + assert!(len >= 2); + Ok((i, &content[..len - 2])) + } else { + Ok((i, content)) + } + } +} + +impl GetObjectContent for DerParser { + /// Skip object content, accepting only DER + /// + /// This this function is for DER only, it cannot go into recursion (no indefinite length) + fn get_object_content<'a>( + i: &'a [u8], + hdr: &'_ Header, + _max_depth: usize, + ) -> ParseResult<'a, &'a [u8]> { + match hdr.length { + Length::Definite(l) => take(l)(i), + Length::Indefinite => Err(Err::Error(Error::DerConstraintFailed( + DerConstraint::IndefiniteLength, + ))), + } + } +} + +/// Skip object content, and return true if object was End-Of-Content +fn ber_skip_object_content<'a>( + i: &'a [u8], + hdr: &Header, + max_depth: usize, +) -> ParseResult<'a, bool> { + if max_depth == 0 { + return Err(Err::Error(Error::BerMaxDepth)); + } + match hdr.length { + Length::Definite(l) => { + if l == 0 && hdr.tag == Tag::EndOfContent { + return Ok((i, true)); + } + let (i, _) = take(l)(i)?; + Ok((i, false)) + } + Length::Indefinite => { + hdr.assert_constructed()?; + // read objects until EndOfContent (00 00) + // this is recursive + let mut i = i; + loop { + let (i2, header2) = Header::from_ber(i)?; + let (i3, eoc) = ber_skip_object_content(i2, &header2, max_depth - 1)?; + if eoc { + // return false, since top object was not EndOfContent + return Ok((i3, false)); + } + i = i3; + } + } + } +} + +/// Try to parse input bytes as u64 +#[inline] +pub(crate) fn bytes_to_u64(s: &[u8]) -> core::result::Result<u64, Error> { + let mut u: u64 = 0; + for &c in s { + if u & 0xff00_0000_0000_0000 != 0 { + return Err(Error::IntegerTooLarge); + } + u <<= 8; + u |= u64::from(c); + } + Ok(u) +} + +pub(crate) fn parse_identifier(i: &[u8]) -> ParseResult<(u8, u8, u32, &[u8])> { + if i.is_empty() { + Err(Err::Incomplete(Needed::new(1))) + } else { + let a = i[0] >> 6; + let b = u8::from(i[0] & 0b0010_0000 != 0); + let mut c = u32::from(i[0] & 0b0001_1111); + + let mut tag_byte_count = 1; + + if c == 0x1f { + c = 0; + loop { + // Make sure we don't read past the end of our data. + custom_check!(i, tag_byte_count >= i.len(), Error::InvalidTag)?; + + // With tag defined as u32 the most we can fit in is four tag bytes. + // (X.690 doesn't actually specify maximum tag width.) + custom_check!(i, tag_byte_count > 5, Error::InvalidTag)?; + + c = (c << 7) | (u32::from(i[tag_byte_count]) & 0x7f); + let done = i[tag_byte_count] & 0x80 == 0; + tag_byte_count += 1; + if done { + break; + } + } + } + + let (raw_tag, rem) = i.split_at(tag_byte_count); + + Ok((rem, (a, b, c, raw_tag))) + } +} + +/// Return the MSB and the rest of the first byte, or an error +pub(crate) fn parse_ber_length_byte(i: &[u8]) -> ParseResult<(u8, u8)> { + if i.is_empty() { + Err(Err::Incomplete(Needed::new(1))) + } else { + let a = i[0] >> 7; + let b = i[0] & 0b0111_1111; + Ok((&i[1..], (a, b))) + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! der_constraint_fail_if( + ($slice:expr, $cond:expr, $constraint:expr) => ( + { + if $cond { + return Err(::nom::Err::Error(Error::DerConstraintFailed($constraint))); + } + } + ); +); |