From d92321d8b12b84eee9d28a80cc960a68477f32f0 Mon Sep 17 00:00:00 2001 From: Pierre Chifflier Date: Mon, 9 Mar 2020 13:38:13 +0100 Subject: [PATCH] ssl/tls: use the rust decoder to decode X.509 certificates --- rust/src/lib.rs | 1 + rust/src/x509/mod.rs | 105 +++++++++++++++++++++++++++++++++++ src/app-layer-ssl.c | 128 +++++++++---------------------------------- 3 files changed, 131 insertions(+), 103 deletions(-) create mode 100644 rust/src/x509/mod.rs diff --git a/rust/src/lib.rs b/rust/src/lib.rs index dddb9ec143..30624ba7b1 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -69,3 +69,4 @@ pub mod sip; pub mod rfb; pub mod applayertemplate; pub mod rdp; +pub mod x509; diff --git a/rust/src/x509/mod.rs b/rust/src/x509/mod.rs new file mode 100644 index 0000000000..780dc6291f --- /dev/null +++ b/rust/src/x509/mod.rs @@ -0,0 +1,105 @@ +/* Copyright (C) 2019-2020 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +// written by Pierre Chifflier + +use crate::common::rust_string_to_c; +use std; +use std::os::raw::c_char; +use x509_parser::{parse_x509_der, X509Certificate}; + +pub struct X509(X509Certificate<'static>); + +/// Attempt to parse a X.509 from input, and return a pointer to the parsed object if successful. +/// +/// # Safety +/// +/// 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 { + 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(), + } +} + +#[no_mangle] +pub extern "C" fn rs_x509_get_subject(ptr: *const X509) -> *mut c_char { + if ptr.is_null() { + return std::ptr::null_mut(); + } + let x509 = cast_pointer! {ptr, X509}; + let subject = x509.0.tbs_certificate.subject.to_string(); + rust_string_to_c(subject) +} + +#[no_mangle] +pub extern "C" fn rs_x509_get_issuer(ptr: *const X509) -> *mut c_char { + if ptr.is_null() { + return std::ptr::null_mut(); + } + let x509 = cast_pointer! {ptr, X509}; + let issuer = x509.0.tbs_certificate.issuer.to_string(); + rust_string_to_c(issuer) +} + +#[no_mangle] +pub extern "C" fn rs_x509_get_serial(ptr: *const X509) -> *mut c_char { + if ptr.is_null() { + return std::ptr::null_mut(); + } + let x509 = cast_pointer! {ptr, X509}; + let serial = x509.0.tbs_certificate.serial.to_string(); + rust_string_to_c(serial) +} + +/// Extract validity from input X.509 object +/// +/// # Safety +/// +/// ptr must be a valid object obtained using `rs_x509_decode` +#[no_mangle] +pub unsafe extern "C" fn rs_x509_get_validity( + ptr: *const X509, + not_before: *mut i64, + not_after: *mut i64, +) -> i32 { + if ptr.is_null() { + return -1; + } + let x509 = &*ptr; + let n_b = x509.0.tbs_certificate.validity.not_before.to_timespec().sec; + let n_a = x509.0.tbs_certificate.validity.not_after.to_timespec().sec; + *not_before = n_b; + *not_after = n_a; + 0 +} + +/// Free a X.509 object allocated by Rust +/// +/// # Safety +/// +/// ptr must be a valid object obtained using `rs_x509_decode` +#[no_mangle] +pub unsafe extern "C" fn rs_x509_free(ptr: *mut X509) { + if ptr.is_null() { + return; + } + drop(Box::from_raw(ptr)); +} diff --git a/src/app-layer-ssl.c b/src/app-layer-ssl.c index f38346adc2..8b3e43b2ca 100644 --- a/src/app-layer-ssl.c +++ b/src/app-layer-ssl.c @@ -385,91 +385,6 @@ static void TlsDecodeHSCertificateErrSetEvent(SSLState *ssl_state, uint32_t err) } } -static inline int TlsDecodeHSCertificateSubject(SSLState *ssl_state, - Asn1Generic *cert) -{ - if (unlikely(ssl_state->server_connp.cert0_subject != NULL)) - return 0; - - uint32_t err = 0; - char buffer[512]; - - int rc = Asn1DerGetSubjectDN(cert, buffer, sizeof(buffer), &err); - if (rc != 0) { - TlsDecodeHSCertificateErrSetEvent(ssl_state, err); - return 0; - } - - ssl_state->server_connp.cert0_subject = SCStrdup(buffer); - if (ssl_state->server_connp.cert0_subject == NULL) - return -1; - - return 0; -} - -static inline int TlsDecodeHSCertificateIssuer(SSLState *ssl_state, - Asn1Generic *cert) -{ - if (unlikely(ssl_state->server_connp.cert0_issuerdn != NULL)) - return 0; - - uint32_t err = 0; - char buffer[512]; - - int rc = Asn1DerGetIssuerDN(cert, buffer, sizeof(buffer), &err); - if (rc != 0) { - TlsDecodeHSCertificateErrSetEvent(ssl_state, err); - return 0; - } - - ssl_state->server_connp.cert0_issuerdn = SCStrdup(buffer); - if (ssl_state->server_connp.cert0_issuerdn == NULL) - return -1; - - return 0; -} - -static inline int TlsDecodeHSCertificateSerial(SSLState *ssl_state, - Asn1Generic *cert) -{ - if (unlikely(ssl_state->server_connp.cert0_serial != NULL)) - return 0; - - uint32_t err = 0; - char buffer[512]; - - int rc = Asn1DerGetSerial(cert, buffer, sizeof(buffer), &err); - if (rc != 0) { - TlsDecodeHSCertificateErrSetEvent(ssl_state, err); - return 0; - } - - ssl_state->server_connp.cert0_serial = SCStrdup(buffer); - if (ssl_state->server_connp.cert0_serial == NULL) - return -1; - - return 0; -} - -static inline int TlsDecodeHSCertificateValidity(SSLState *ssl_state, - Asn1Generic *cert) -{ - uint32_t err = 0; - time_t not_before; - time_t not_after; - - int rc = Asn1DerGetValidity(cert, ¬_before, ¬_after, &err); - if (rc != 0) { - TlsDecodeHSCertificateErrSetEvent(ssl_state, err); - return 0; - } - - ssl_state->server_connp.cert0_not_before = not_before; - ssl_state->server_connp.cert0_not_after = not_after; - - return 0; -} - static inline int TlsDecodeHSCertificateFingerprint(SSLState *ssl_state, const uint8_t *input, uint32_t cert_len) @@ -515,7 +430,7 @@ static int TlsDecodeHSCertificate(SSLState *ssl_state, { const uint8_t *input = (uint8_t *)initial_input; - Asn1Generic *cert = NULL; + X509 *x509 = NULL; if (!(HAS_SPACE(3))) return 1; @@ -539,40 +454,47 @@ static int TlsDecodeHSCertificate(SSLState *ssl_state, if (!(HAS_SPACE(cert_len))) goto invalid_cert; - uint32_t err = 0; + // uint32_t err = 0; int rc = 0; /* only store fields from the first certificate in the chain */ if (processed_len == 0) { - /* coverity[tainted_data] */ - cert = DecodeDer(input, cert_len, &err); - if (cert == NULL) { - TlsDecodeHSCertificateErrSetEvent(ssl_state, err); + char * str; + int64_t not_before, not_after; + + x509 = rs_x509_decode(input, cert_len); + if (x509 == NULL) { + TlsDecodeHSCertificateErrSetEvent(ssl_state, ERR_DER_GENERIC); goto next; } - rc = TlsDecodeHSCertificateSubject(ssl_state, cert); - if (rc != 0) + str = rs_x509_get_subject(x509); + if (str == NULL) goto error; + ssl_state->server_connp.cert0_subject = str; - rc = TlsDecodeHSCertificateIssuer(ssl_state, cert); - if (rc != 0) + str = rs_x509_get_issuer(x509); + if (str == NULL) goto error; + ssl_state->server_connp.cert0_issuerdn = str; - rc = TlsDecodeHSCertificateSerial(ssl_state, cert); - if (rc != 0) + str = rs_x509_get_serial(x509); + if (str == NULL) goto error; + ssl_state->server_connp.cert0_serial = str; - rc = TlsDecodeHSCertificateValidity(ssl_state, cert); + rc = rs_x509_get_validity(x509, ¬_before, ¬_after); if (rc != 0) goto error; + ssl_state->server_connp.cert0_not_before = (time_t)not_before; + ssl_state->server_connp.cert0_not_after = (time_t)not_after; + + rs_x509_free(x509); + x509 = NULL; rc = TlsDecodeHSCertificateFingerprint(ssl_state, input, cert_len); if (rc != 0) goto error; - - DerFree(cert); - cert = NULL; } rc = TlsDecodeHSCertificateAddCertToChain(ssl_state, input, cert_len); @@ -587,8 +509,8 @@ next: return (input - initial_input); error: - if (cert != NULL) - DerFree(cert); + if (x509 != NULL) + rs_x509_free(x509); return -1; invalid_cert: