]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
rust/x509: map decoding errors to decoder events 4721/head
authorPierre Chifflier <chifflier@wzdftpd.net>
Sun, 22 Mar 2020 15:19:57 +0000 (16:19 +0100)
committerPierre Chifflier <chifflier@wzdftpd.net>
Mon, 23 Mar 2020 15:54:20 +0000 (16:54 +0100)
rust/src/x509/mod.rs
src/app-layer-ssl.c
src/app-layer-ssl.h

index f003b2a2928d333b7c7d1f57126a0ba83507f4e9..353edb1d44113f1fa20cd0518df9dc9f147246f6 100644 (file)
 // written by Pierre Chifflier  <chifflier@wzdftpd.net>
 
 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<X509Error>) -> 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,
+        },
+    }
+}
index bd210f49fe3d17c00c56baf11bd2b673d4c70336..8787783d76220ef5d811d350a71e7e3bddeccb27 100644 (file)
@@ -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, &not_before, &not_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;
index 597e85cd02af55bb113de208f167c6e471be2958..8b287e34718fd63be57c23c2675852a5211c6eff 100644 (file)
@@ -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,
 };