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};
pub const MAX_RECURSION: usize = 50;
pub const MAX_OBJECT_SIZE: usize = 4_294_967_295;
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));
}
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 Ok((i3, false));
}
i = i3;
}
}
}
}
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 hdr.length() == Length::Indefinite {
let len = content.len();
assert!(len >= 2);
Ok((i, &content[..len - 2]))
} else {
Ok((i, content))
}
}
#[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)
}
#[inline]
pub fn ber_read_element_header(i: &[u8]) -> BerResult<Header> {
Header::from_ber(i)
}
#[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)
}
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)
}
}
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)
}
}
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)))
}
#[inline]
pub fn parse_ber_endofcontent(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::EndOfContent)
}
#[inline]
pub fn parse_ber_bool(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::Boolean)
}
#[inline]
pub fn parse_ber_integer(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::Integer)
}
#[inline]
pub fn parse_ber_bitstring(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::BitString)
}
#[inline]
pub fn parse_ber_octetstring(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::OctetString)
}
#[inline]
pub fn parse_ber_null(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::Null)
}
#[inline]
pub fn parse_ber_oid(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::Oid)
}
#[inline]
pub fn parse_ber_enum(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::Enumerated)
}
#[inline]
pub fn parse_ber_utf8string(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::Utf8String)
}
#[inline]
pub fn parse_ber_relative_oid(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::RelativeOid)
}
#[inline]
pub fn parse_ber_sequence(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::Sequence)
}
#[inline]
pub fn parse_ber_set(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::Set)
}
#[inline]
pub fn parse_ber_numericstring(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::NumericString)
}
#[inline]
pub fn parse_ber_visiblestring(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::VisibleString)
}
#[inline]
pub fn parse_ber_printablestring(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::PrintableString)
}
#[inline]
pub fn parse_ber_t61string(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::T61String)
}
#[inline]
pub fn parse_ber_videotexstring(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::VideotexString)
}
#[inline]
pub fn parse_ber_ia5string(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::Ia5String)
}
#[inline]
pub fn parse_ber_utctime(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::UtcTime)
}
#[inline]
pub fn parse_ber_generalizedtime(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::GeneralizedTime)
}
#[inline]
pub fn parse_ber_objectdescriptor(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::ObjectDescriptor)
}
#[inline]
pub fn parse_ber_graphicstring(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::GraphicString)
}
#[inline]
pub fn parse_ber_generalstring(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::GeneralString)
}
#[inline]
pub fn parse_ber_bmpstring(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::BmpString)
}
#[inline]
pub fn parse_ber_universalstring(i: &[u8]) -> BerResult {
parse_ber_with_tag(i, Tag::UniversalString)
}
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)
}
#[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)
}
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)))),
}
}
}
#[inline]
pub fn parse_ber_i32(i: &[u8]) -> BerResult<i32> {
<i32>::from_ber(i)
}
#[inline]
pub fn parse_ber_i64(i: &[u8]) -> BerResult<i64> {
<i64>::from_ber(i)
}
#[inline]
pub fn parse_ber_u32(i: &[u8]) -> BerResult<u32> {
<u32>::from_ber(i)
}
#[inline]
pub fn parse_ber_u64(i: &[u8]) -> BerResult<u64> {
<u64>::from_ber(i)
}
#[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)
}
#[inline]
pub fn parse_ber_recursive(i: &[u8], max_depth: usize) -> BerResult {
parse_ber_any_r(i, max_depth)
}
#[inline]
pub fn parse_ber(i: &[u8]) -> BerResult {
parse_ber_recursive(i, MAX_RECURSION)
}
#[test]
fn test_bitstring_to_u64() {
let data = &hex_literal::hex!("0d 71 82");
let r = bitstring_to_u64(8, &BitStringObject { data });
assert_eq!(r, Ok(0x0d71));
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());
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 });
assert_eq!(r, Ok(0x0d71 >> 2));
}