/// Decodes Asn1 objects from an input + length while applying the offset
/// defined in the asn1 keyword options
fn asn1_decode(
- input: *const u8,
- input_len: u32,
+ buffer: &'static [u8],
+ buffer_offset: u32,
ad: &DetectAsn1Data,
) -> Result<Asn1, Asn1DecodeError> {
// Get offset
let offset = if let Some(absolute_offset) = ad.absolute_offset {
- absolute_offset as isize
+ absolute_offset
} else if let Some(relative_offset) = ad.relative_offset {
- relative_offset as isize
+ // relative offset in regards to the last content match
+
+ // buffer_offset (u32) + relative_offset (i32) => offset (u16)
+ u16::try_from({
+ if relative_offset > 0 {
+ buffer_offset
+ .checked_add(u32::try_from(relative_offset)?)
+ .ok_or(Asn1DecodeError::InvalidKeywordParameter)?
+ } else {
+ buffer_offset
+ .checked_sub(u32::try_from(-relative_offset)?)
+ .ok_or(Asn1DecodeError::InvalidKeywordParameter)?
+ }
+ })
+ .or(Err(Asn1DecodeError::InvalidKeywordParameter))?
} else {
0
};
- // Make sure we won't read past the end of the buffer
- if offset >= input_len as isize {
+ // Make sure we won't read past the end or front of the buffer
+ if offset as usize >= buffer.len() {
return Err(Asn1DecodeError::InvalidKeywordParameter);
}
- // Apply offset to input pointer
- let input = unsafe { input.offset(offset) };
-
- // Adjust the length
- let input_len = (input_len as isize)
- .checked_sub(offset)
- .ok_or(Asn1DecodeError::InvalidKeywordParameter)?;
- let input_len =
- usize::try_from(input_len).map_err(|_| Asn1DecodeError::InvalidKeywordParameter)?;
-
- // Get the slice from memory
- let slice = build_slice!(input, input_len);
+ // Get slice from buffer at offset
+ let slice = &buffer[offset as usize..];
Asn1::from_slice(slice, ad)
}
#[no_mangle]
pub unsafe extern "C" fn rs_asn1_decode(
input: *const u8,
- input_len: u32,
+ input_len: u16,
+ buffer_offset: u32,
ad_ptr: *const DetectAsn1Data,
) -> *mut Asn1 {
if input.is_null() || input_len == 0 || ad_ptr.is_null() {
return std::ptr::null_mut();
}
+ let slice = build_slice!(input, input_len as usize);
+
let ad = &*ad_ptr;
- let res = asn1_decode(input, input_len, ad);
+ let res = asn1_decode(slice, buffer_offset, ad);
match res {
Ok(asn1) => Box::into_raw(Box::new(asn1)),
0
}
+impl From<std::num::TryFromIntError> for Asn1DecodeError {
+ fn from(_e: std::num::TryFromIntError) -> Asn1DecodeError {
+ Asn1DecodeError::InvalidKeywordParameter
+ }
+}
+
impl From<nom::Err<der_parser::error::BerError>> for Asn1DecodeError {
fn from(e: nom::Err<der_parser::error::BerError>) -> Asn1DecodeError {
match e {
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::character::complete::{digit1, multispace0, multispace1};
-use nom::combinator::{map_res, opt};
+use nom::combinator::{map_res, opt, verify};
use nom::sequence::{separated_pair, tuple};
use nom::IResult;
use std::ffi::CStr;
pub bitstring_overflow: bool,
pub double_overflow: bool,
pub oversize_length: Option<u32>,
- pub absolute_offset: Option<u32>,
+ pub absolute_offset: Option<u16>,
pub relative_offset: Option<i32>,
pub max_frames: u16,
}
fn parse_u32_number(input: &str) -> IResult<&str, u32> {
map_res(digit1, |digits: &str| digits.parse::<u32>())(input)
}
+
+fn parse_u16_number(input: &str) -> IResult<&str, u16> {
+ map_res(digit1, |digits: &str| digits.parse::<u16>())(input)
+}
+
fn parse_i32_number(input: &str) -> IResult<&str, i32> {
let (rest, negate) = opt(tag("-"))(input)?;
let (rest, d) = map_res(digit1, |s: &str| s.parse::<i32>())(rest)?;
separated_pair(tag("oversize_length"), multispace1, parse_u32_number)(i)
}
- fn absolute_offset(i: &str) -> IResult<&str, (&str, u32)> {
- separated_pair(tag("absolute_offset"), multispace1, parse_u32_number)(i)
+ fn absolute_offset(i: &str) -> IResult<&str, (&str, u16)> {
+ separated_pair(tag("absolute_offset"), multispace1, parse_u16_number)(i)
}
fn relative_offset(i: &str) -> IResult<&str, (&str, i32)> {
- separated_pair(tag("relative_offset"), multispace1, parse_i32_number)(i)
+ separated_pair(
+ tag("relative_offset"),
+ multispace1,
+ verify(parse_i32_number, |v| {
+ *v >= -i32::from(std::u16::MAX) && *v <= i32::from(std::u16::MAX)
+ }),
+ )(i)
}
let mut data = DetectAsn1Data::default();
#[test_case("oversize_length 1024",
DetectAsn1Data { oversize_length: Some(1024), ..Default::default()};
"check that we parse oversize_length correctly")]
+ #[test_case("oversize_length 0",
+ DetectAsn1Data { oversize_length: Some(0), ..Default::default()};
+ "check lower bound on oversize_length")]
+ #[test_case("oversize_length -1",
+ DetectAsn1Data::default() => panics "Error((\"oversize_length -1\", Verify))";
+ "check under lower bound on oversize_length")]
+ #[test_case("oversize_length 4294967295",
+ DetectAsn1Data { oversize_length: Some(4294967295), ..Default::default()};
+ "check upper bound on oversize_length")]
+ #[test_case("oversize_length 4294967296",
+ DetectAsn1Data::default() => panics "Error((\"oversize_length 4294967296\", Verify))";
+ "check over upper bound on oversize_length")]
#[test_case("oversize_length",
DetectAsn1Data::default() => panics "Error((\"oversize_length\", Verify))";
"check that we fail if the needed arg oversize_length is not given")]
#[test_case("absolute_offset 1024",
DetectAsn1Data { absolute_offset: Some(1024), ..Default::default()};
"check that we parse absolute_offset correctly")]
+ #[test_case("absolute_offset 0",
+ DetectAsn1Data { absolute_offset: Some(0), ..Default::default()};
+ "check lower bound on absolute_offset")]
+ #[test_case("absolute_offset -1",
+ DetectAsn1Data::default() => panics "Error((\"absolute_offset -1\", Verify))";
+ "check under lower bound on absolute_offset")]
+ #[test_case("absolute_offset 65535",
+ DetectAsn1Data { absolute_offset: Some(65535), ..Default::default()};
+ "check upper bound on absolute_offset")]
+ #[test_case("absolute_offset 65536",
+ DetectAsn1Data::default() => panics "Error((\"absolute_offset 65536\", Verify))";
+ "check over upper bound on absolute_offset")]
#[test_case("absolute_offset",
DetectAsn1Data::default() => panics "Error((\"absolute_offset\", Verify))";
"check that we fail if the needed arg absolute_offset is not given")]
#[test_case("relative_offset 1024",
DetectAsn1Data { relative_offset: Some(1024), ..Default::default()};
"check that we parse relative_offset correctly")]
+ #[test_case("relative_offset -65535",
+ DetectAsn1Data { relative_offset: Some(-65535), ..Default::default()};
+ "check lower bound on relative_offset")]
+ #[test_case("relative_offset -65536",
+ DetectAsn1Data::default() => panics "Error((\"relative_offset -65536\", Verify))";
+ "check under lower bound on relative_offset")]
+ #[test_case("relative_offset 65535",
+ DetectAsn1Data { relative_offset: Some(65535), ..Default::default()};
+ "check upper bound on relative_offset")]
+ #[test_case("relative_offset 65536",
+ DetectAsn1Data::default() => panics "Error((\"relative_offset 65536\", Verify))";
+ "check over upper bound on relative_offset")]
#[test_case("relative_offset",
DetectAsn1Data::default() => panics "Error((\"relative_offset\", Verify))";
"check that we fail if the needed arg relative_offset is not given")]
const DetectAsn1Data *ad = (const DetectAsn1Data *)ctx;
- Asn1 *asn1 = rs_asn1_decode(p->payload, p->payload_len, ad);
+ Asn1 *asn1 = rs_asn1_decode(p->payload, p->payload_len, det_ctx->buffer_offset, ad);
ret = rs_asn1_checks(asn1, ad);
"content:\"Pablo\"; asn1:absolute_offset 0, "
"oversize_length 130; sid:1;)";
sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; "
- "content:\"AA\"; asn1:relative_offset 2, "
+ "content:\"AA\"; asn1:relative_offset 0, "
"oversize_length 130; sid:2;)";
sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; "
"content:\"lalala\"; asn1: oversize_length 2000; sid:3;)";
"content:\"Pablo\"; asn1:absolute_offset 0, "
"oversize_length 140; sid:1;)";
sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; "
- "content:\"AA\"; asn1:relative_offset 2, "
+ "content:\"AA\"; asn1:relative_offset 0, "
"oversize_length 140; sid:2;)";
sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; "
"content:\"lalala\"; asn1: oversize_length 2000; sid:3;)";
"content:\"Pablo\"; asn1:absolute_offset 0, "
"oversize_length 140; sid:1;)";
sigs[1]= "alert ip any any -> any any (msg:\"Testing id 2\"; "
- "content:\"John\"; asn1:relative_offset -7, "
+ "content:\"John\"; asn1:relative_offset -11, "
"oversize_length 140; sid:2;)";
sigs[2]= "alert ip any any -> any any (msg:\"Testing id 3\"; "
"content:\"lalala\"; asn1: oversize_length 2000; sid:3;)";