--- /dev/null
+/* 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 <chifflier@wzdftpd.net>
+
+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));
+}
}
}
-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)
{
const uint8_t *input = (uint8_t *)initial_input;
- Asn1Generic *cert = NULL;
+ X509 *x509 = NULL;
if (!(HAS_SPACE(3)))
return 1;
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);
return (input - initial_input);
error:
- if (cert != NULL)
- DerFree(cert);
+ if (x509 != NULL)
+ rs_x509_free(x509);
return -1;
invalid_cert: