diff options
Diffstat (limited to 'rust/vendor/der-parser/src/ber/parser.rs')
-rw-r--r-- | rust/vendor/der-parser/src/ber/parser.rs | 661 |
1 files changed, 661 insertions, 0 deletions
diff --git a/rust/vendor/der-parser/src/ber/parser.rs b/rust/vendor/der-parser/src/ber/parser.rs new file mode 100644 index 0000000..f951402 --- /dev/null +++ b/rust/vendor/der-parser/src/ber/parser.rs @@ -0,0 +1,661 @@ +use crate::ber::wrap_any::parse_ber_any_r; +use crate::ber::*; +use crate::error::*; +use asn1_rs::{FromBer, Tag}; +use nom::bytes::streaming::take; +use nom::{Err, Offset}; + +/// 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; + +/// Skip object content, and return true if object was End-Of-Content +pub(crate) fn ber_skip_object_content<'a>( + i: &'a [u8], + hdr: &Header, + max_depth: usize, +) -> BerResult<'a, bool> { + if max_depth == 0 { + return Err(Err::Error(BerError::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 => { + if hdr.is_primitive() { + return Err(Err::Error(BerError::ConstructExpected)); + } + // read objects until EndOfContent (00 00) + // this is recursive + let mut i = i; + loop { + let (i2, header2) = ber_read_element_header(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; + } + } + } +} + +/// Read object raw content (bytes) +pub(crate) fn ber_get_object_content<'a>( + i: &'a [u8], + hdr: &Header, + max_depth: usize, +) -> BerResult<'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)) + } +} + +/// Try to parse an input bit string as u64. +/// +/// Note: this is for the primitive BER/DER encoding only, the +/// constructed BER encoding for BIT STRING does not seem to be +/// supported at all by the library currently. +#[inline] +pub(crate) fn bitstring_to_u64( + padding_bits: usize, + data: &BitStringObject, +) -> Result<u64, BerError> { + let raw_bytes = data.data; + let bit_size = (raw_bytes.len() * 8) + .checked_sub(padding_bits) + .ok_or(BerError::InvalidLength)?; + if bit_size > 64 { + return Err(BerError::IntegerTooLarge); + } + let padding_bits = padding_bits % 8; + let num_bytes = if bit_size % 8 > 0 { + (bit_size / 8) + 1 + } else { + bit_size / 8 + }; + let mut resulting_integer: u64 = 0; + for &c in &raw_bytes[..num_bytes] { + resulting_integer <<= 8; + resulting_integer |= c as u64; + } + Ok(resulting_integer >> padding_bits) +} + +/// Read an object header +/// +/// ### Example +/// +/// ``` +/// # use der_parser::ber::{ber_read_element_header, Class, Length, Tag}; +/// # +/// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; +/// let (i, hdr) = ber_read_element_header(bytes).expect("could not read header"); +/// +/// assert_eq!(hdr.class(), Class::Universal); +/// assert_eq!(hdr.tag(), Tag::Integer); +/// assert_eq!(hdr.length(), Length::Definite(3)); +/// ``` +#[inline] +pub fn ber_read_element_header(i: &[u8]) -> BerResult<Header> { + Header::from_ber(i) +} + +/// Parse the next bytes as the *content* of a BER object. +/// +/// Content type is *not* checked to match tag, caller is responsible of providing the correct tag +/// +/// This function is mostly used when parsing implicit tagged objects, when reading primitive +/// types. +/// +/// `max_depth` is the maximum allowed recursion for objects. +/// +/// ### Example +/// +/// ``` +/// # use der_parser::ber::{ber_read_element_content_as, ber_read_element_header, Tag}; +/// # +/// # let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; +/// let (i, hdr) = ber_read_element_header(bytes).expect("could not read header"); +/// let (_, content) = ber_read_element_content_as( +/// i, hdr.tag(), hdr.length(), hdr.is_constructed(), 5 +/// ).expect("parsing failed"); +/// # +/// # assert_eq!(hdr.tag(), Tag::Integer); +/// # assert_eq!(content.as_u32(), Ok(0x10001)); +/// ``` +#[inline] +pub fn ber_read_element_content_as( + i: &[u8], + tag: Tag, + length: Length, + constructed: bool, + max_depth: usize, +) -> BerResult<BerObjectContent> { + try_read_berobjectcontent_as(i, tag, length, constructed, max_depth) +} + +/// Parse the next bytes as the content of a BER object (combinator, header reference) +/// +/// Content type is *not* checked to match tag, caller is responsible of providing the correct tag +/// +/// Caller is also responsible to check if parsing function consumed the expected number of +/// bytes (`header.len`). +/// +/// The arguments of the parse function are: `(input, ber_object_header, max_recursion)`. +/// +/// This function differs from [`parse_ber_content2`](fn.parse_ber_content2.html) because it passes +/// the BER object header by reference (required for ex. by `parse_ber_implicit`). +/// +/// Example: manually parsing header and content +/// +/// ``` +/// # use der_parser::ber::*; +/// # +/// # let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; +/// let (i, header) = ber_read_element_header(bytes).expect("parsing failed"); +/// let (rem, content) = parse_ber_content(header.tag())(i, &header, MAX_RECURSION) +/// .expect("parsing failed"); +/// # +/// # assert_eq!(header.tag(), Tag::Integer); +/// ``` +pub fn parse_ber_content<'a>( + tag: Tag, +) -> impl Fn(&'a [u8], &'_ Header, usize) -> BerResult<'a, BerObjectContent<'a>> { + move |i: &[u8], hdr: &Header, max_recursion: usize| { + ber_read_element_content_as(i, tag, hdr.length(), hdr.is_constructed(), max_recursion) + } +} + +/// Parse the next bytes as the content of a BER object (combinator, owned header) +/// +/// Content type is *not* checked to match tag, caller is responsible of providing the correct tag +/// +/// Caller is also responsible to check if parsing function consumed the expected number of +/// bytes (`header.len`). +/// +/// The arguments of the parse function are: `(input, ber_object_header, max_recursion)`. +/// +/// This function differs from [`parse_ber_content`](fn.parse_ber_content.html) because it passes +/// an owned BER object header (required for ex. by `parse_ber_tagged_implicit_g`). +/// +/// Example: manually parsing header and content +/// +/// ``` +/// # use der_parser::ber::*; +/// # +/// # let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; +/// let (i, header) = ber_read_element_header(bytes).expect("parsing failed"); +/// let (rem, content) = parse_ber_content(header.tag())(i, &header, MAX_RECURSION) +/// .expect("parsing failed"); +/// # +/// # assert_eq!(header.tag(), Tag::Integer); +/// ``` +pub fn parse_ber_content2<'a>( + tag: Tag, +) -> impl Fn(&'a [u8], Header<'a>, usize) -> BerResult<'a, BerObjectContent<'a>> { + move |i: &[u8], hdr: Header, max_recursion: usize| { + ber_read_element_content_as(i, tag, hdr.length(), hdr.is_constructed(), max_recursion) + } +} + +/// Parse a BER object, expecting a value with specified tag +/// +/// The object is parsed recursively, with a maximum depth of `MAX_RECURSION`. +/// +/// ### Example +/// +/// ``` +/// use der_parser::ber::Tag; +/// use der_parser::ber::parse_ber_with_tag; +/// +/// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; +/// let (_, obj) = parse_ber_with_tag(bytes, Tag::Integer).expect("parsing failed"); +/// +/// assert_eq!(obj.header.tag(), Tag::Integer); +/// ``` +pub fn parse_ber_with_tag<T: Into<Tag>>(i: &[u8], tag: T) -> BerResult { + let tag = tag.into(); + let (i, hdr) = ber_read_element_header(i)?; + hdr.assert_tag(tag)?; + let (i, content) = ber_read_element_content_as( + i, + hdr.tag(), + hdr.length(), + hdr.is_constructed(), + MAX_RECURSION, + )?; + Ok((i, BerObject::from_header_and_content(hdr, content))) +} + +/// Read end of content marker +#[inline] +pub fn parse_ber_endofcontent(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::EndOfContent) +} + +/// Read a boolean value +/// +/// The encoding of a boolean value shall be primitive. The contents octets shall consist of a +/// single octet. +/// +/// If the boolean value is FALSE, the octet shall be zero. +/// If the boolean value is TRUE, the octet shall be one byte, and have all bits set to one (0xff). +#[inline] +pub fn parse_ber_bool(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::Boolean) +} + +/// Read an integer value +/// +/// The encoding of a boolean value shall be primitive. The contents octets shall consist of one or +/// more octets. +/// +/// To access the content, use the [`as_u64`](struct.BerObject.html#method.as_u64), +/// [`as_u32`](struct.BerObject.html#method.as_u32), +/// [`as_biguint`](struct.BerObject.html#method.as_biguint) or +/// [`as_bigint`](struct.BerObject.html#method.as_bigint) methods. +/// Remember that a BER integer has unlimited size, so these methods return `Result` or `Option` +/// objects. +/// +/// # Examples +/// +/// ```rust +/// # extern crate nom; +/// # use der_parser::ber::parse_ber_integer; +/// # use der_parser::ber::{BerObject,BerObjectContent}; +/// let empty = &b""[..]; +/// let bytes = [0x02, 0x03, 0x01, 0x00, 0x01]; +/// let expected = BerObject::from_obj(BerObjectContent::Integer(b"\x01\x00\x01")); +/// assert_eq!( +/// parse_ber_integer(&bytes), +/// Ok((empty, expected)) +/// ); +/// ``` +#[inline] +pub fn parse_ber_integer(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::Integer) +} + +/// Read an bitstring value +#[inline] +pub fn parse_ber_bitstring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::BitString) +} + +/// Read an octetstring value +#[inline] +pub fn parse_ber_octetstring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::OctetString) +} + +/// Read a null value +#[inline] +pub fn parse_ber_null(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::Null) +} + +/// Read an object identifier value +#[inline] +pub fn parse_ber_oid(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::Oid) +} + +/// Read an enumerated value +#[inline] +pub fn parse_ber_enum(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::Enumerated) +} + +/// Read a UTF-8 string value. The encoding is checked. +#[inline] +pub fn parse_ber_utf8string(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::Utf8String) +} + +/// Read a relative object identifier value +#[inline] +pub fn parse_ber_relative_oid(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::RelativeOid) +} + +/// Parse a sequence of BER elements +/// +/// Read a sequence of BER objects, without any constraint on the types. +/// Sequence is parsed recursively, so if constructed elements are found, they are parsed using the +/// same function. +/// +/// To read a specific sequence of objects (giving the expected types), use the +/// [`parse_ber_sequence_defined`](macro.parse_ber_sequence_defined.html) macro. +#[inline] +pub fn parse_ber_sequence(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::Sequence) +} + +/// Parse a set of BER elements +/// +/// Read a set of BER objects, without any constraint on the types. +/// Set is parsed recursively, so if constructed elements are found, they are parsed using the +/// same function. +/// +/// To read a specific set of objects (giving the expected types), use the +/// [`parse_ber_set_defined`](macro.parse_ber_set_defined.html) macro. +#[inline] +pub fn parse_ber_set(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::Set) +} + +/// Read a numeric string value. The content is verified to +/// contain only digits and spaces. +#[inline] +pub fn parse_ber_numericstring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::NumericString) +} + +/// Read a visible string value. The content is verified to +/// contain only the allowed characters. +#[inline] +pub fn parse_ber_visiblestring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::VisibleString) +} + +/// Read a printable string value. The content is verified to +/// contain only the allowed characters. +#[inline] +pub fn parse_ber_printablestring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::PrintableString) +} + +/// Read a T61 string value +#[inline] +pub fn parse_ber_t61string(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::T61String) +} + +/// Read a Videotex string value +#[inline] +pub fn parse_ber_videotexstring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::VideotexString) +} + +/// Read an IA5 string value. The content is verified to be ASCII. +#[inline] +pub fn parse_ber_ia5string(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::Ia5String) +} + +/// Read an UTC time value +#[inline] +pub fn parse_ber_utctime(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::UtcTime) +} + +/// Read a Generalized time value +#[inline] +pub fn parse_ber_generalizedtime(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::GeneralizedTime) +} + +/// Read an ObjectDescriptor value +#[inline] +pub fn parse_ber_objectdescriptor(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::ObjectDescriptor) +} + +/// Read a GraphicString value +#[inline] +pub fn parse_ber_graphicstring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::GraphicString) +} + +/// Read a GeneralString value +#[inline] +pub fn parse_ber_generalstring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::GeneralString) +} + +/// Read a BmpString value +#[inline] +pub fn parse_ber_bmpstring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::BmpString) +} + +/// Read a UniversalString value +#[inline] +pub fn parse_ber_universalstring(i: &[u8]) -> BerResult { + parse_ber_with_tag(i, Tag::UniversalString) +} + +/// Parse an optional tagged object, applying function to get content +/// +/// This function returns a `BerObject`, trying to read content as generic BER objects. +/// If parsing failed, return an optional object containing `None`. +/// +/// To support other return or error types, use +/// [parse_ber_tagged_explicit_g](fn.parse_ber_tagged_explicit_g.html) +/// +/// This function will never fail: if parsing content failed, the BER value `Optional(None)` is +/// returned. +pub fn parse_ber_explicit_optional<F>(i: &[u8], tag: Tag, f: F) -> BerResult +where + F: Fn(&[u8]) -> BerResult, +{ + parse_ber_optional(parse_ber_tagged_explicit_g(tag, |content, hdr| { + let (rem, obj) = f(content)?; + let content = BerObjectContent::Tagged(hdr.class(), hdr.tag(), Box::new(obj)); + let tagged = BerObject::from_header_and_content(hdr, content); + Ok((rem, tagged)) + }))(i) +} + +/// Parse an implicit tagged object, applying function to read content +/// +/// Note: unlike explicit tagged functions, the callback must be a *content* parsing function, +/// often based on the [`parse_ber_content`](fn.parse_ber_content.html) combinator. +/// +/// The built object will use the original header (and tag), so the content may not match the tag +/// value. +/// +/// For a combinator version, see [parse_ber_tagged_implicit](fn.parse_ber_tagged_implicit.html). +/// +/// For a generic version (different output and error types), see +/// [parse_ber_tagged_implicit_g](fn.parse_ber_tagged_implicit_g.html). +/// +/// # Examples +/// +/// The following parses `[3] IMPLICIT INTEGER` into a `BerObject`: +/// +/// ```rust +/// # use der_parser::ber::*; +/// # use der_parser::error::BerResult; +/// # +/// fn parse_int_implicit(i:&[u8]) -> BerResult<BerObject> { +/// parse_ber_implicit( +/// i, +/// 3, +/// parse_ber_content(Tag::Integer), +/// ) +/// } +/// +/// # let bytes = &[0x83, 0x03, 0x01, 0x00, 0x01]; +/// let res = parse_int_implicit(bytes); +/// # match res { +/// # Ok((rem, content)) => { +/// # assert!(rem.is_empty()); +/// # assert_eq!(content.as_u32(), Ok(0x10001)); +/// # }, +/// # _ => assert!(false) +/// # } +/// ``` +#[inline] +pub fn parse_ber_implicit<'a, T, F>(i: &'a [u8], tag: T, f: F) -> BerResult<'a> +where + F: Fn(&'a [u8], &'_ Header, usize) -> BerResult<'a, BerObjectContent<'a>>, + T: Into<Tag>, +{ + parse_ber_tagged_implicit(tag, f)(i) +} + +/// Combinator for building optional BER values +/// +/// To read optional BER values, it is to use the nom `opt()` combinator. However, this results in +/// a `Option<BerObject>` and prevents using some functions from this crate (the generic functions +/// can still be used). +/// +/// This combinator is used when parsing BER values, while keeping `BerObject` output only. +/// +/// This function will never fail: if parsing content failed, the BER value `Optional(None)` is +/// returned. +/// +/// ### Example +/// +/// ``` +/// # use der_parser::ber::*; +/// # +/// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; +/// let mut parser = parse_ber_optional(parse_ber_integer); +/// let (_, obj) = parser(bytes).expect("parsing failed"); +/// +/// assert_eq!(obj.header.tag(), Tag::Integer); +/// assert!(obj.as_optional().is_ok()); +/// ``` +pub fn parse_ber_optional<'a, F>(mut f: F) -> impl FnMut(&'a [u8]) -> BerResult<'a> +where + F: FnMut(&'a [u8]) -> BerResult<'a>, +{ + move |i: &[u8]| { + let res = f(i); + match res { + Ok((rem, inner)) => { + let opt = BerObject::from_header_and_content( + inner.header.clone(), + BerObjectContent::Optional(Some(Box::new(inner))), + ); + Ok((rem, opt)) + } + Err(_) => Ok((i, BerObject::from_obj(BerObjectContent::Optional(None)))), + } + } +} + +/// Parse BER object and try to decode it as a 32-bits signed integer +/// +/// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target +/// integer type. +#[inline] +pub fn parse_ber_i32(i: &[u8]) -> BerResult<i32> { + <i32>::from_ber(i) +} + +/// Parse BER object and try to decode it as a 64-bits signed integer +/// +/// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target +/// integer type. +#[inline] +pub fn parse_ber_i64(i: &[u8]) -> BerResult<i64> { + <i64>::from_ber(i) +} + +/// Parse BER object and try to decode it as a 32-bits unsigned integer +/// +/// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target +/// integer type. +#[inline] +pub fn parse_ber_u32(i: &[u8]) -> BerResult<u32> { + <u32>::from_ber(i) +} + +/// Parse BER object and try to decode it as a 64-bits unsigned integer +/// +/// Return `IntegerTooLarge` if object is an integer, but can not be represented in the target +/// integer type. +#[inline] +pub fn parse_ber_u64(i: &[u8]) -> BerResult<u64> { + <u64>::from_ber(i) +} + +/// Parse BER object and get content as slice +#[inline] +pub fn parse_ber_slice<T: Into<Tag>>(i: &[u8], tag: T) -> BerResult<&[u8]> { + let tag = tag.into(); + parse_ber_container(move |content, hdr| { + hdr.assert_tag(tag)?; + Ok((&b""[..], content)) + })(i) +} + +/// Parse BER object recursively, specifying the maximum recursion depth +/// +/// Return a tuple containing the remaining (unparsed) bytes and the BER Object, or an error. +/// +/// ### Example +/// +/// ``` +/// use der_parser::ber::{parse_ber_recursive, Tag}; +/// +/// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; +/// let (_, obj) = parse_ber_recursive(bytes, 1).expect("parsing failed"); +/// +/// assert_eq!(obj.header.tag(), Tag::Integer); +/// ``` +#[inline] +pub fn parse_ber_recursive(i: &[u8], max_depth: usize) -> BerResult { + parse_ber_any_r(i, max_depth) +} + +/// Parse BER object recursively +/// +/// Return a tuple containing the remaining (unparsed) bytes and the BER Object, or an error. +/// +/// *Note*: this is the same as calling `parse_ber_recursive` with `MAX_RECURSION`. +/// +/// ### Example +/// +/// ``` +/// use der_parser::ber::{parse_ber, Tag}; +/// +/// let bytes = &[0x02, 0x03, 0x01, 0x00, 0x01]; +/// let (_, obj) = parse_ber(bytes).expect("parsing failed"); +/// +/// assert_eq!(obj.header.tag(), Tag::Integer); +/// ``` +#[inline] +pub fn parse_ber(i: &[u8]) -> BerResult { + parse_ber_recursive(i, MAX_RECURSION) +} + +#[test] +fn test_bitstring_to_u64() { + // ignored bits modulo 8 to 0 + let data = &hex_literal::hex!("0d 71 82"); + let r = bitstring_to_u64(8, &BitStringObject { data }); + assert_eq!(r, Ok(0x0d71)); + + // input too large to fit a 64-bits integer + let data = &hex_literal::hex!("0d 71 82 0e 73 72 76 6e 67 6e 62 6c 6e 2d 65 78 30 31"); + let r = bitstring_to_u64(0, &BitStringObject { data }); + assert!(r.is_err()); + + // test large number but with many ignored bits + let data = &hex_literal::hex!("0d 71 82 0e 73 72 76 6e 67 6e 62 6c 6e 2d 65 78 30 31"); + let r = bitstring_to_u64(130, &BitStringObject { data }); + // 2 = 130 % 8 + assert_eq!(r, Ok(0x0d71 >> 2)); +} |