diff --git a/rust/src/x509/mod.rs b/rust/src/x509/mod.rs index f003b2a292..353edb1d44 100644 --- a/rust/src/x509/mod.rs +++ b/rust/src/x509/mod.rs @@ -18,9 +18,27 @@ // written by Pierre Chifflier use crate::common::rust_string_to_c; +use nom; use std; use std::os::raw::c_char; -use x509_parser::{parse_x509_der, X509Certificate}; +use x509_parser::{error::X509Error, parse_x509_der, X509Certificate}; + +#[repr(u32)] +pub enum X509DecodeError { + Success = 0, + /// Generic decoding error + InvalidCert, + /// Some length does not match, or certificate is incomplete + InvalidLength, + InvalidVersion, + InvalidSerial, + InvalidAlgorithmIdentifier, + InvalidX509Name, + InvalidDate, + InvalidExtensions, + /// DER structure is invalid + InvalidDER, +} pub struct X509(X509Certificate<'static>); @@ -30,12 +48,20 @@ pub struct X509(X509Certificate<'static>); /// /// input must be a valid buffer of at least input_len bytes #[no_mangle] -pub unsafe extern "C" fn rs_x509_decode(input: *const u8, input_len: u32) -> *mut X509 { +pub unsafe extern "C" fn rs_x509_decode( + input: *const u8, + input_len: u32, + err_code: *mut u32, +) -> *mut X509 { let slice = std::slice::from_raw_parts(input, input_len as usize); let res = parse_x509_der(slice); match res { Ok((_rem, cert)) => Box::into_raw(Box::new(X509(cert))), - Err(_) => std::ptr::null_mut(), + Err(e) => { + let error = x509_parse_error_to_errcode(&e); + *err_code = error as u32; + std::ptr::null_mut() + } } } @@ -66,10 +92,7 @@ pub extern "C" fn rs_x509_get_serial(ptr: *const X509) -> *mut c_char { } let x509 = cast_pointer! {ptr, X509}; let raw_serial = x509.0.tbs_certificate.raw_serial(); - let v : Vec<_> = raw_serial - .iter() - .map(|x| format!("{:02X}", x)) - .collect(); + let v: Vec<_> = raw_serial.iter().map(|x| format!("{:02X}", x)).collect(); let serial = v.join(":"); rust_string_to_c(serial) } @@ -108,3 +131,19 @@ pub unsafe extern "C" fn rs_x509_free(ptr: *mut X509) { } drop(Box::from_raw(ptr)); } + +fn x509_parse_error_to_errcode(e: &nom::Err) -> X509DecodeError { + match e { + nom::Err::Incomplete(_) => X509DecodeError::InvalidLength, + nom::Err::Error(e) | nom::Err::Failure(e) => match e { + X509Error::InvalidVersion => X509DecodeError::InvalidVersion, + X509Error::InvalidSerial => X509DecodeError::InvalidSerial, + X509Error::InvalidAlgorithmIdentifier => X509DecodeError::InvalidAlgorithmIdentifier, + X509Error::InvalidX509Name => X509DecodeError::InvalidX509Name, + X509Error::InvalidDate => X509DecodeError::InvalidDate, + X509Error::InvalidExtensions => X509DecodeError::InvalidExtensions, + X509Error::Der(_) => X509DecodeError::InvalidDER, + _ => X509DecodeError::InvalidCert, + }, + } +} diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index bd210f49fe..8787783d76 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -71,16 +71,42 @@ SCEnumCharMap tls_decoder_event_table[ ] = { { "TOO_MANY_RECORDS_IN_PACKET", TLS_DECODER_EVENT_TOO_MANY_RECORDS_IN_PACKET }, /* certificate decoding messages */ { "INVALID_CERTIFICATE", TLS_DECODER_EVENT_INVALID_CERTIFICATE }, - { "CERTIFICATE_MISSING_ELEMENT", TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT }, - { "CERTIFICATE_UNKNOWN_ELEMENT", TLS_DECODER_EVENT_CERTIFICATE_UNKNOWN_ELEMENT }, { "CERTIFICATE_INVALID_LENGTH", TLS_DECODER_EVENT_CERTIFICATE_INVALID_LENGTH }, - { "CERTIFICATE_INVALID_STRING", TLS_DECODER_EVENT_CERTIFICATE_INVALID_STRING }, + { "CERTIFICATE_INVALID_VERSION", TLS_DECODER_EVENT_CERTIFICATE_INVALID_VERSION }, + { "CERTIFICATE_INVALID_SERIAL", TLS_DECODER_EVENT_CERTIFICATE_INVALID_SERIAL }, + { "CERTIFICATE_INVALID_ALGORITHMIDENTIFIER", TLS_DECODER_EVENT_CERTIFICATE_INVALID_ALGORITHMIDENTIFIER }, + { "CERTIFICATE_INVALID_X509NAME", TLS_DECODER_EVENT_CERTIFICATE_INVALID_X509NAME }, + { "CERTIFICATE_INVALID_DATE", TLS_DECODER_EVENT_CERTIFICATE_INVALID_DATE }, + { "CERTIFICATE_INVALID_EXTENSIONS", TLS_DECODER_EVENT_CERTIFICATE_INVALID_EXTENSIONS }, + { "CERTIFICATE_INVALID_DER", TLS_DECODER_EVENT_CERTIFICATE_INVALID_DER }, + { "CERTIFICATE_INVALID_SUBJECT", TLS_DECODER_EVENT_CERTIFICATE_INVALID_SUBJECT }, + { "CERTIFICATE_INVALID_ISSUER", TLS_DECODER_EVENT_CERTIFICATE_INVALID_ISSUER }, + { "CERTIFICATE_INVALID_VALIDITY", TLS_DECODER_EVENT_CERTIFICATE_INVALID_VALIDITY }, { "ERROR_MESSAGE_ENCOUNTERED", TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED }, /* used as a generic error event */ { "INVALID_SSL_RECORD", TLS_DECODER_EVENT_INVALID_SSL_RECORD }, { NULL, -1 }, }; +enum { + /* X.509 error codes, returned by decoder + * THESE CONSTANTS MUST MATCH rust/src/x509/mod.rs ! */ + ERR_INVALID_CERTIFICATE=1, + ERR_INVALID_LENGTH, + ERR_INVALID_VERSION, + ERR_INVALID_SERIAL, + ERR_INVALID_ALGORITHMIDENTIFIER, + ERR_INVALID_X509NAME, + ERR_INVALID_DATE, + ERR_INVALID_EXTENSIONS, + ERR_INVALID_DER, + + /* error getting data */ + ERR_EXTRACT_SUBJECT, + ERR_EXTRACT_ISSUER, + ERR_EXTRACT_VALIDITY, +}; + /* JA3 fingerprints are disabled by default */ #define SSL_CONFIG_DEFAULT_JA3 0 @@ -353,6 +379,49 @@ void SSLVersionToString(uint16_t version, char *buffer) } } +static void TlsDecodeHSCertificateErrSetEvent(SSLState *ssl_state, uint32_t err) +{ + switch(err) { + case ERR_EXTRACT_VALIDITY: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_VALIDITY); + break; + case ERR_EXTRACT_ISSUER: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_ISSUER); + break; + case ERR_EXTRACT_SUBJECT: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_SUBJECT); + break; + case ERR_INVALID_DER: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_DER); + break; + case ERR_INVALID_EXTENSIONS: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_EXTENSIONS); + break; + case ERR_INVALID_DATE: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_DATE); + break; + case ERR_INVALID_X509NAME: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_X509NAME); + break; + case ERR_INVALID_ALGORITHMIDENTIFIER: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_ALGORITHMIDENTIFIER); + break; + case ERR_INVALID_SERIAL: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_SERIAL); + break; + case ERR_INVALID_VERSION: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_VERSION); + break; + case ERR_INVALID_LENGTH: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_CERTIFICATE_INVALID_LENGTH); + break; + case ERR_INVALID_CERTIFICATE: + default: + SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_CERTIFICATE); + break; + } +} + static inline int TlsDecodeHSCertificateFingerprint(SSLState *ssl_state, const uint8_t *input, uint32_t cert_len) @@ -397,6 +466,7 @@ static int TlsDecodeHSCertificate(SSLState *ssl_state, const uint32_t input_len) { const uint8_t *input = (uint8_t *)initial_input; + uint32_t err_code = 0; X509 *x509 = NULL; @@ -413,6 +483,8 @@ static int TlsDecodeHSCertificate(SSLState *ssl_state, /* coverity[tainted_data] */ while (processed_len < cert_chain_len) { + err_code = 0; + if (!(HAS_SPACE(3))) goto invalid_cert; @@ -430,30 +502,38 @@ static int TlsDecodeHSCertificate(SSLState *ssl_state, char * str; int64_t not_before, not_after; - x509 = rs_x509_decode(input, cert_len); + x509 = rs_x509_decode(input, cert_len, &err_code); if (x509 == NULL) { - SSLSetEvent(ssl_state, TLS_DECODER_EVENT_INVALID_CERTIFICATE); + TlsDecodeHSCertificateErrSetEvent(ssl_state, err_code); goto next; } str = rs_x509_get_subject(x509); - if (str == NULL) + if (str == NULL) { + err_code = ERR_EXTRACT_SUBJECT; goto error; + } ssl_state->server_connp.cert0_subject = str; str = rs_x509_get_issuer(x509); - if (str == NULL) + if (str == NULL) { + err_code = ERR_EXTRACT_ISSUER; goto error; + } ssl_state->server_connp.cert0_issuerdn = str; str = rs_x509_get_serial(x509); - if (str == NULL) + if (str == NULL) { + err_code = ERR_INVALID_SERIAL; goto error; + } ssl_state->server_connp.cert0_serial = str; rc = rs_x509_get_validity(x509, ¬_before, ¬_after); - if (rc != 0) + if (rc != 0) { + err_code = ERR_EXTRACT_VALIDITY; goto error; + } ssl_state->server_connp.cert0_not_before = (time_t)not_before; ssl_state->server_connp.cert0_not_after = (time_t)not_after; @@ -477,6 +557,8 @@ next: return (input - initial_input); error: + if (err_code != 0) + TlsDecodeHSCertificateErrSetEvent(ssl_state, err_code); if (x509 != NULL) rs_x509_free(x509); return -1; diff --git a/src/app-layer-ssl.h b/src/app-layer-ssl.h index 597e85cd02..8b287e3471 100644 --- a/src/app-layer-ssl.h +++ b/src/app-layer-ssl.h @@ -50,10 +50,17 @@ enum { TLS_DECODER_EVENT_TOO_MANY_RECORDS_IN_PACKET, /* Certificates decoding messages */ TLS_DECODER_EVENT_INVALID_CERTIFICATE, - TLS_DECODER_EVENT_CERTIFICATE_MISSING_ELEMENT, - TLS_DECODER_EVENT_CERTIFICATE_UNKNOWN_ELEMENT, TLS_DECODER_EVENT_CERTIFICATE_INVALID_LENGTH, - TLS_DECODER_EVENT_CERTIFICATE_INVALID_STRING, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_VERSION, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_SERIAL, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_ALGORITHMIDENTIFIER, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_X509NAME, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_DATE, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_EXTENSIONS, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_DER, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_SUBJECT, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_ISSUER, + TLS_DECODER_EVENT_CERTIFICATE_INVALID_VALIDITY, TLS_DECODER_EVENT_ERROR_MSG_ENCOUNTERED, TLS_DECODER_EVENT_INVALID_SSL_RECORD, };