]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
eve/tls: implement client cert logging
authorVictor Julien <vjulien@oisf.net>
Tue, 23 Aug 2022 09:35:41 +0000 (11:35 +0200)
committerVictor Julien <vjulien@oisf.net>
Wed, 21 Sep 2022 04:43:48 +0000 (06:43 +0200)
Enable client logging in extended mode.

Add "client", "client_certificate" and "client_chain", where the latter two
depend on "client".

src/output-json-tls.c

index 972ce02c1e1e3afd481105f31b3fb39d02dba772..f825fe38c69dc497f02e01a8909dfa4ad09cde7c 100644 (file)
@@ -73,28 +73,24 @@ SC_ATOMIC_EXTERN(unsigned int, cert_id);
 #define LOG_TLS_FIELD_SESSION_RESUMED   (1 << 10)
 #define LOG_TLS_FIELD_JA3               (1 << 11)
 #define LOG_TLS_FIELD_JA3S              (1 << 12)
+#define LOG_TLS_FIELD_CLIENT            (1 << 13) /**< client fields (issuer, subject, etc) */
+#define LOG_TLS_FIELD_CLIENT_CERT       (1 << 14)
+#define LOG_TLS_FIELD_CLIENT_CHAIN      (1 << 15)
 
 typedef struct {
     const char *name;
     uint64_t flag;
 } TlsFields;
 
-TlsFields tls_fields[] = {
-    { "version",         LOG_TLS_FIELD_VERSION },
-    { "subject",         LOG_TLS_FIELD_SUBJECT },
-    { "issuer",          LOG_TLS_FIELD_ISSUER },
-    { "serial",          LOG_TLS_FIELD_SERIAL },
-    { "fingerprint",     LOG_TLS_FIELD_FINGERPRINT },
-    { "not_before",      LOG_TLS_FIELD_NOTBEFORE },
-    { "not_after",       LOG_TLS_FIELD_NOTAFTER },
-    { "sni",             LOG_TLS_FIELD_SNI },
-    { "certificate",     LOG_TLS_FIELD_CERTIFICATE },
-    { "chain",           LOG_TLS_FIELD_CHAIN },
-    { "session_resumed", LOG_TLS_FIELD_SESSION_RESUMED },
-    { "ja3",             LOG_TLS_FIELD_JA3 },
-    { "ja3s",            LOG_TLS_FIELD_JA3S },
-    { NULL,              -1 }
-};
+TlsFields tls_fields[] = { { "version", LOG_TLS_FIELD_VERSION },
+    { "subject", LOG_TLS_FIELD_SUBJECT }, { "issuer", LOG_TLS_FIELD_ISSUER },
+    { "serial", LOG_TLS_FIELD_SERIAL }, { "fingerprint", LOG_TLS_FIELD_FINGERPRINT },
+    { "not_before", LOG_TLS_FIELD_NOTBEFORE }, { "not_after", LOG_TLS_FIELD_NOTAFTER },
+    { "sni", LOG_TLS_FIELD_SNI }, { "certificate", LOG_TLS_FIELD_CERTIFICATE },
+    { "chain", LOG_TLS_FIELD_CHAIN }, { "session_resumed", LOG_TLS_FIELD_SESSION_RESUMED },
+    { "ja3", LOG_TLS_FIELD_JA3 }, { "ja3s", LOG_TLS_FIELD_JA3S },
+    { "client", LOG_TLS_FIELD_CLIENT }, { "client_certificate", LOG_TLS_FIELD_CLIENT_CERT },
+    { "client_chain", LOG_TLS_FIELD_CLIENT_CHAIN }, { NULL, -1 } };
 
 typedef struct OutputTlsCtx_ {
     uint32_t flags;  /** Store mode */
@@ -285,6 +281,53 @@ static void JsonTlsLogChain(JsonBuilder *js, SSLStateConnp *connp)
     jb_close(js);
 }
 
+static bool HasClientCert(SSLStateConnp *connp)
+{
+    if (connp->cert0_subject || connp->cert0_issuerdn)
+        return true;
+    return false;
+}
+
+static void JsonTlsLogClientCert(
+        JsonBuilder *js, SSLStateConnp *connp, const bool log_cert, const bool log_chain)
+{
+    if (connp->cert0_subject != NULL) {
+        jb_set_string(js, "subject", connp->cert0_subject);
+    }
+    if (connp->cert0_issuerdn != NULL) {
+        jb_set_string(js, "issuerdn", connp->cert0_issuerdn);
+    }
+    if (connp->cert0_fingerprint) {
+        jb_set_string(js, "fingerprint", connp->cert0_fingerprint);
+    }
+    if (connp->cert0_serial) {
+        jb_set_string(js, "serial", connp->cert0_serial);
+    }
+    if (connp->cert0_not_before != 0) {
+        char timebuf[64];
+        struct timeval tv;
+        tv.tv_sec = connp->cert0_not_before;
+        tv.tv_usec = 0;
+        CreateUtcIsoTimeString(&tv, timebuf, sizeof(timebuf));
+        jb_set_string(js, "notbefore", timebuf);
+    }
+    if (connp->cert0_not_after != 0) {
+        char timebuf[64];
+        struct timeval tv;
+        tv.tv_sec = connp->cert0_not_after;
+        tv.tv_usec = 0;
+        CreateUtcIsoTimeString(&tv, timebuf, sizeof(timebuf));
+        jb_set_string(js, "notafter", timebuf);
+    }
+
+    if (log_cert) {
+        JsonTlsLogCertificate(js, connp);
+    }
+    if (log_chain) {
+        JsonTlsLogChain(js, connp);
+    }
+}
+
 void JsonTlsLogJSONBasic(JsonBuilder *js, SSLState *ssl_state)
 {
     /* tls subject */
@@ -351,6 +394,16 @@ static void JsonTlsLogJSONCustom(OutputTlsCtx *tls_ctx, JsonBuilder *js,
     /* tls ja3s */
     if (tls_ctx->fields & LOG_TLS_FIELD_JA3S)
         JsonTlsLogJa3S(js, ssl_state);
+
+    if (tls_ctx->fields & LOG_TLS_FIELD_CLIENT) {
+        const bool log_cert = (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CERT) != 0;
+        const bool log_chain = (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CHAIN) != 0;
+        if (HasClientCert(&ssl_state->client_connp)) {
+            jb_open_object(js, "client");
+            JsonTlsLogClientCert(js, &ssl_state->client_connp, log_cert, log_chain);
+            jb_close(js);
+        }
+    }
 }
 
 void JsonTlsLogJSONExtended(JsonBuilder *tjs, SSLState * state)
@@ -380,6 +433,12 @@ void JsonTlsLogJSONExtended(JsonBuilder *tjs, SSLState * state)
 
     /* tls ja3s */
     JsonTlsLogJa3S(tjs, state);
+
+    if (HasClientCert(&state->client_connp)) {
+        jb_open_object(tjs, "client");
+        JsonTlsLogClientCert(tjs, &state->client_connp, false, false);
+        jb_close(tjs);
+    }
 }
 
 static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p,
@@ -540,6 +599,24 @@ static OutputTlsCtx *OutputTlsInitCtx(ConfNode *conf)
                      "certificate, so only one of them should be enabled "
                      "at a time");
     }
+    if ((tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CERT) &&
+            (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CHAIN)) {
+        SCLogWarning(SC_WARN_DUPLICATE_OUTPUT,
+                "Both 'client_certificate' and 'client_chain' contains the top "
+                "certificate, so only one of them should be enabled "
+                "at a time");
+    }
+
+    if ((tls_ctx->fields & LOG_TLS_FIELD_CLIENT) == 0) {
+        if (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CERT) {
+            SCLogConfig("enabling \"client\" as a dependency of \"client_certificate\"");
+            tls_ctx->fields |= LOG_TLS_FIELD_CLIENT;
+        }
+        if (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CHAIN) {
+            SCLogConfig("enabling \"client\" as a dependency of \"client_chain\"");
+            tls_ctx->fields |= LOG_TLS_FIELD_CLIENT;
+        }
+    }
 
     return tls_ctx;
 }