--- /dev/null
+/* Copyright (C) 2023 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.
+ */
+
+use crate::jsonbuilder::JsonBuilder;
+use crate::x509::time::format_timestamp;
+use std::ffi::CStr;
+use std::os::raw::c_char;
+
+/// Helper function to log a TLS timestamp from C to JSON with the
+/// provided key. The format of the timestamp is ISO 8601 timestamp
+/// with no sub-second or offset information as UTC is assumed.
+///
+/// # Safety
+///
+/// FFI function that dereferences pointers from C.
+#[no_mangle]
+pub unsafe extern "C" fn sc_x509_log_timestamp(
+ jb: &mut JsonBuilder, key: *const c_char, timestamp: i64,
+) -> bool {
+ if let Ok(key) = CStr::from_ptr(key).to_str() {
+ if let Ok(timestamp) = format_timestamp(timestamp) {
+ return jb.set_string(key, ×tamp).is_ok();
+ }
+ }
+ false
+}
use std;
use std::os::raw::c_char;
use x509_parser::prelude::*;
+mod time;
+mod log;
#[repr(u32)]
pub enum X509DecodeError {
--- /dev/null
+/* Copyright (C) 2023 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.
+ */
+
+use std::ffi::CString;
+use std::os::raw::c_char;
+use time::macros::format_description;
+
+/// Format a timestamp in an ISO format suitable for TLS logging.
+///
+/// Negative timestamp values are used for dates prior to 1970.
+pub fn format_timestamp(timestamp: i64) -> Result<String, time::error::Error> {
+ let format = format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]");
+ let ts = time::OffsetDateTime::from_unix_timestamp(timestamp)?;
+ let formatted = ts.format(&format)?;
+ Ok(formatted)
+}
+
+/// Format a x509 ISO timestamp into the provided C buffer.
+///
+/// Returns false if an error occurs, otherwise true is returned if
+/// the timestamp is properly formatted into the provided buffer.
+///
+/// # Safety
+///
+/// Access buffers from C that are expected to be valid.
+#[no_mangle]
+pub unsafe extern "C" fn sc_x509_format_timestamp(
+ timestamp: i64, buf: *mut c_char, size: usize,
+) -> bool {
+ let ctimestamp = match format_timestamp(timestamp) {
+ Ok(ts) => match CString::new(ts) {
+ Ok(ts) => ts,
+ Err(_) => return false,
+ },
+ Err(_) => return false,
+ };
+ let bytes = ctimestamp.as_bytes_with_nul();
+
+ if size < bytes.len() {
+ false
+ } else {
+ // Convert buf into a slice we can copy into.
+ let buf = std::slice::from_raw_parts_mut(buf as *mut u8, size);
+ buf[0..bytes.len()].copy_from_slice(bytes);
+ true
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_format_timestamp() {
+ assert_eq!("1969-12-31T00:00:00", format_timestamp(-86400).unwrap());
+ assert_eq!("2038-12-31T00:10:03", format_timestamp(2177367003).unwrap());
+ }
+}
/* only store fields from the first certificate in the chain */
if (certn == 0 && connp->cert0_subject == NULL && connp->cert0_issuerdn == NULL &&
connp->cert0_serial == NULL) {
- int64_t not_before, not_after;
-
x509 = rs_x509_decode(input, cert_len, &err_code);
if (x509 == NULL) {
TlsDecodeHSCertificateErrSetEvent(ssl_state, err_code);
}
connp->cert0_serial = str;
- rc = rs_x509_get_validity(x509, ¬_before, ¬_after);
+ rc = rs_x509_get_validity(x509, &connp->cert0_not_before, &connp->cert0_not_after);
if (rc != 0) {
err_code = ERR_EXTRACT_VALIDITY;
goto error;
}
- connp->cert0_not_before = (time_t)not_before;
- connp->cert0_not_after = (time_t)not_after;
rs_x509_free(x509);
x509 = NULL;
char *cert0_subject;
char *cert0_issuerdn;
char *cert0_serial;
- time_t cert0_not_before;
- time_t cert0_not_after;
+ int64_t cert0_not_before;
+ int64_t cert0_not_after;
char *cert0_fingerprint;
/* ssl server name indication extension */
MemBufferWriteString(buffer, "VERSION='%s'", ssl_version);
}
-static void LogTlsLogDate(MemBuffer *buffer, const char *title, time_t *date)
+static void LogTlsLogDate(MemBuffer *buffer, const char *title, int64_t *date)
{
char timebuf[64] = {0};
- const SCTime_t ts = SCTIME_FROM_SECS(*date);
- CreateUtcIsoTimeString(ts, timebuf, sizeof(timebuf));
- MemBufferWriteString(buffer, "%s='%s'", title, timebuf);
+ if (sc_x509_format_timestamp(*date, timebuf, sizeof(timebuf))) {
+ MemBufferWriteString(buffer, "%s='%s'", title, timebuf);
+ }
}
static void LogTlsLogString(MemBuffer *buffer, const char *title,
static void JsonTlsLogNotBefore(JsonBuilder *js, SSLState *ssl_state)
{
if (ssl_state->server_connp.cert0_not_before != 0) {
- char timebuf[64];
- SCTime_t ts = SCTIME_FROM_SECS(ssl_state->server_connp.cert0_not_before);
- CreateUtcIsoTimeString(ts, timebuf, sizeof(timebuf));
- jb_set_string(js, "notbefore", timebuf);
+ sc_x509_log_timestamp(js, "notbefore", ssl_state->server_connp.cert0_not_before);
}
}
static void JsonTlsLogNotAfter(JsonBuilder *js, SSLState *ssl_state)
{
if (ssl_state->server_connp.cert0_not_after != 0) {
- char timebuf[64];
- SCTime_t ts = SCTIME_FROM_SECS(ssl_state->server_connp.cert0_not_after);
- CreateUtcIsoTimeString(ts, timebuf, sizeof(timebuf));
- jb_set_string(js, "notafter", timebuf);
+ sc_x509_log_timestamp(js, "notafter", ssl_state->server_connp.cert0_not_after);
}
}