detect/asn1: Simplify errors and checks

pull/5149/head
Emmanuel Thompson 5 years ago committed by Victor Julien
parent 4fc45b5c60
commit 6e5d64f102

@ -15,9 +15,7 @@
* 02110-1301, USA.
*/
use crate::log::*;
use der_parser::ber::{parse_ber_recursive, BerObject, BerObjectContent, BerTag};
use der_parser::error::BerError;
use std::convert::TryFrom;
mod parse_rules;
@ -32,20 +30,7 @@ pub struct Asn1<'a>(Vec<BerObject<'a>>);
enum Asn1DecodeError {
InvalidKeywordParameter,
MaxFrames,
InvalidStructure,
BerTypeError,
BerValueError,
InvalidTag,
InvalidLength,
InvalidClass,
ConstructExpected,
ConstructUnexpected,
IntegerTooLarge,
BerMaxDepth,
ObjectTooShort,
DerConstraintFailed,
UnknownTag,
Unsupported,
BerError(nom::Err<der_parser::error::BerError>),
}
/// Enumeration of Asn1 checks
@ -54,61 +39,46 @@ enum Asn1Check {
OversizeLength,
BitstringOverflow,
DoubleOverflow,
}
/// Errors possible during Asn1 checks
#[derive(Debug)]
enum Asn1CheckError {
MaxDepth,
}
impl std::fmt::Display for Asn1CheckError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Asn1CheckError::MaxDepth => write!(f, "MaxDepth"),
}
}
}
impl<'a> Asn1<'a> {
/// Checks each BerObject contained in self with the provided detection
/// data, returns the first successful match if one occurs
fn check(&self, ad: &DetectAsn1Data) -> Result<Option<Asn1Check>, Asn1CheckError> {
fn check(&self, ad: &DetectAsn1Data) -> Option<Asn1Check> {
for obj in &self.0 {
let res = Asn1::check_object_recursive(obj, ad, ad.max_frames as usize)?;
let res = Asn1::check_object_recursive(obj, ad, ad.max_frames as usize);
if res.is_some() {
return Ok(res);
return res;
}
}
Ok(None)
None
}
fn check_object_recursive(
obj: &BerObject,
ad: &DetectAsn1Data,
max_depth: usize,
) -> Result<Option<Asn1Check>, Asn1CheckError> {
obj: &BerObject, ad: &DetectAsn1Data, max_depth: usize,
) -> Option<Asn1Check> {
// Check stack depth
if max_depth == 0 {
return Err(Asn1CheckError::MaxDepth);
return Some(Asn1Check::MaxDepth);
}
// Check current object
let res = Asn1::check_object(obj, ad);
if res.is_some() {
return Ok(res);
return res;
}
// Check sub-nodes
for node in obj.ref_iter() {
let res = Asn1::check_object_recursive(node, ad, max_depth - 1)?;
let res = Asn1::check_object_recursive(node, ad, max_depth - 1);
if res.is_some() {
return Ok(res);
return res;
}
}
Ok(None)
None
}
/// Checks a BerObject and subnodes against the Asn1 checks
@ -197,9 +167,7 @@ impl<'a> Asn1<'a> {
/// Decodes Asn1 objects from an input + length while applying the offset
/// defined in the asn1 keyword options
fn asn1_decode<'a>(
buffer: &'a [u8],
buffer_offset: u32,
ad: &DetectAsn1Data,
buffer: &'a [u8], buffer_offset: u32, ad: &DetectAsn1Data,
) -> Result<Asn1<'a>, Asn1DecodeError> {
// Get offset
let offset = if let Some(absolute_offset) = ad.absolute_offset {
@ -244,10 +212,7 @@ fn asn1_decode<'a>(
/// pointer must be freed using `rs_asn1_free`
#[no_mangle]
pub extern "C" fn rs_asn1_decode(
input: *const u8,
input_len: u16,
buffer_offset: u32,
ad_ptr: *const DetectAsn1Data,
input: *const u8, input_len: u16, buffer_offset: u32, ad_ptr: *const DetectAsn1Data,
) -> *mut Asn1<'static> {
if input.is_null() || input_len == 0 || ad_ptr.is_null() {
return std::ptr::null_mut();
@ -290,10 +255,7 @@ pub unsafe extern "C" fn rs_asn1_free(ptr: *mut Asn1) {
///
/// Returns 1 if any of the options match, 0 if not
#[no_mangle]
pub unsafe extern "C" fn rs_asn1_checks(
ptr: *const Asn1,
ad_ptr: *const DetectAsn1Data,
) -> u8 {
pub unsafe extern "C" fn rs_asn1_checks(ptr: *const Asn1, ad_ptr: *const DetectAsn1Data) -> u8 {
if ptr.is_null() || ad_ptr.is_null() {
return 0;
}
@ -302,12 +264,8 @@ pub unsafe extern "C" fn rs_asn1_checks(
let ad = &*ad_ptr;
match asn1.check(ad) {
Ok(Some(_check)) => 1,
Ok(None) => 0,
Err(e) => {
SCLogError!("error during asn1 checks: {}", e.to_string());
0
}
Some(_check) => 1,
None => 0,
}
}
@ -319,25 +277,7 @@ impl From<std::num::TryFromIntError> for Asn1DecodeError {
impl From<nom::Err<der_parser::error::BerError>> for Asn1DecodeError {
fn from(e: nom::Err<der_parser::error::BerError>) -> Asn1DecodeError {
match e {
nom::Err::Incomplete(_) => Asn1DecodeError::InvalidLength,
nom::Err::Error(e) | nom::Err::Failure(e) => match e {
BerError::BerTypeError => Asn1DecodeError::BerTypeError,
BerError::BerValueError => Asn1DecodeError::BerValueError,
BerError::InvalidTag => Asn1DecodeError::InvalidTag,
BerError::InvalidClass => Asn1DecodeError::InvalidClass,
BerError::InvalidLength => Asn1DecodeError::InvalidLength,
BerError::ConstructExpected => Asn1DecodeError::ConstructExpected,
BerError::ConstructUnexpected => Asn1DecodeError::ConstructUnexpected,
BerError::IntegerTooLarge => Asn1DecodeError::IntegerTooLarge,
BerError::BerMaxDepth => Asn1DecodeError::BerMaxDepth,
BerError::ObjectTooShort => Asn1DecodeError::ObjectTooShort,
BerError::DerConstraintFailed => Asn1DecodeError::DerConstraintFailed,
BerError::UnknownTag => Asn1DecodeError::UnknownTag,
BerError::Unsupported => Asn1DecodeError::Unsupported,
_ => Asn1DecodeError::InvalidStructure,
},
}
Asn1DecodeError::BerError(e)
}
}
@ -430,9 +370,7 @@ mod tests {
..Default::default()
}, None; "Test double_overflow rule (non-match)" )]
fn test_checks(
rule: &str,
asn1_buf: &'static [u8],
expected_data: DetectAsn1Data,
rule: &str, asn1_buf: &'static [u8], expected_data: DetectAsn1Data,
expected_check: Option<Asn1Check>,
) {
// Parse rule
@ -443,7 +381,7 @@ mod tests {
let asn1 = Asn1::from_slice(asn1_buf, &ad).unwrap();
// Run checks
let result = asn1.check(&ad).unwrap();
let result = asn1.check(&ad);
assert_eq!(expected_check, result);
}
}

Loading…
Cancel
Save