]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
tls-store: now a separate module
authorEric Leblond <eric@regit.org>
Tue, 14 Jul 2015 19:22:31 +0000 (21:22 +0200)
committerVictor Julien <victor@inliniac.net>
Mon, 20 Jul 2015 09:45:21 +0000 (11:45 +0200)
An design error was made when doing the TLS storage module which
has been made dependant of the TLS logging. At the time there was
only one TLS logging module but there is now two different ones.

By putting the TLS store module in a separate module, we can now
use EVE output and TLS store at the same time.

src/Makefile.am
src/app-layer-ssl.h
src/log-tlslog.c
src/log-tlslog.h
src/log-tlsstore.c [new file with mode: 0644]
src/log-tlsstore.h [new file with mode: 0644]
src/suricata.c
src/tm-modules.c
src/tm-threads-common.h
suricata.yaml.in

index 819338427761261eb23ddfeac37a945856ce43f9..64ade15912408ef6338e5baac72751f6ce01e267 100644 (file)
@@ -230,6 +230,7 @@ log-pcap.c log-pcap.h \
 log-stats.c log-stats.h \
 log-tcp-data.c log-tcp-data.h \
 log-tlslog.c log-tlslog.h \
+log-tlsstore.c log-tlsstore.h \
 output.c output.h \
 output-file.c output-file.h \
 output-filedata.c output-filedata.h \
index 1e5bbebddb8d759dc6e6cb002ea633de8bcfe9ca..5c6fe5b153b5962b6ac68bbf9e89d7b5e1223966 100644 (file)
@@ -76,7 +76,10 @@ enum {
 /* flags specific to HeartBeat state */
 #define SSL_AL_FLAG_HB_INFLIGHT                 0x8000
 #define SSL_AL_FLAG_HB_CLIENT_INIT              0x10000
-#define SSL_AL_FLAG_HB_SERVER_INIT             0x20000
+#define SSL_AL_FLAG_HB_SERVER_INIT              0x20000
+
+/* flags for file storage */
+#define SSL_AL_FLAG_STATE_STORED                0x40000
 
 /* config flags */
 #define SSL_TLS_LOG_PEM                         (1 << 0)
index c2b17e7f1bf094e156877ffdc10705ca5c96023f..edb0ded2d0fead90c38bcf4882c0fb25a24471a9 100644 (file)
@@ -56,9 +56,6 @@
 
 #define DEFAULT_LOG_FILENAME "tls.log"
 
-static char tls_logfile_base_dir[PATH_MAX] = "/tmp";
-SC_ATOMIC_DECLARE(unsigned int, cert_id);
-
 #define MODULE_NAME "LogTlsLog"
 
 #define OUTPUT_BUFFER_SIZE 65535
@@ -79,8 +76,6 @@ typedef struct LogTlsLogThread_ {
     uint32_t tls_cnt;
 
     MemBuffer *buffer;
-    uint8_t*   enc_buf;
-    size_t     enc_buf_len;
 } LogTlsLogThread;
 
 static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState * state)
@@ -115,7 +110,7 @@ static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState * state)
     MemBufferWriteString(aft->buffer, "\n");
 }
 
-static int GetIPInformations(const Packet *p, char* srcip, size_t srcip_len,
+int TLSGetIPInformations(const Packet *p, char* srcip, size_t srcip_len,
                              Port* sp, char* dstip, size_t dstip_len,
                              Port* dp, int ipproto)
 {
@@ -153,162 +148,6 @@ static int GetIPInformations(const Packet *p, char* srcip, size_t srcip_len,
     return 1;
 }
 
-static int CreateFileName(LogTlsFileCtx *log, const Packet *p, SSLState *state, char *filename)
-{
-#define FILELEN 64  //filename len + extention + ending path / + some space
-
-    int filenamelen = FILELEN + strlen(tls_logfile_base_dir);
-    int file_id = SC_ATOMIC_ADD(cert_id, 1);
-
-    if (filenamelen + 1 > PATH_MAX) {
-        return 0;
-    }
-
-    /* Use format : packet time + incremental ID
-     * When running on same pcap it will overwrite
-     * On a live device, we will not be able to overwrite */
-    snprintf(filename, filenamelen, "%s/%ld.%ld-%d.pem",
-             tls_logfile_base_dir,
-             (long int)p->ts.tv_sec,
-             (long int)p->ts.tv_usec,
-             file_id);
-    return 1;
-}
-
-static void LogTlsLogPem(LogTlsLogThread *aft, const Packet *p, SSLState *state, LogTlsFileCtx *log, int ipproto)
-{
-#define PEMHEADER "-----BEGIN CERTIFICATE-----\n"
-#define PEMFOOTER "-----END CERTIFICATE-----\n"
-    //Logging pem certificate
-    char filename[PATH_MAX] = "";
-    FILE* fp = NULL;
-    FILE* fpmeta = NULL;
-    unsigned long pemlen;
-    unsigned char* pembase64ptr = NULL;
-    int ret;
-    uint8_t *ptmp;
-    SSLCertsChain *cert;
-
-    if ((state->server_connp.cert_input == NULL) || (state->server_connp.cert_input_len == 0))
-        SCReturn;
-
-    CreateFileName(log, p, state, filename);
-    if (strlen(filename) == 0) {
-        SCLogWarning(SC_ERR_FOPEN, "Can't create PEM filename");
-        SCReturn;
-    }
-
-    fp = fopen(filename, "w");
-    if (fp == NULL) {
-        SCLogWarning(SC_ERR_FOPEN, "Can't create PEM file: %s", filename);
-        SCReturn;
-    }
-
-    TAILQ_FOREACH(cert, &state->server_connp.certs, next) {
-        pemlen = (4 * (cert->cert_len + 2) / 3) +1;
-        if (pemlen > aft->enc_buf_len) {
-            ptmp = (uint8_t*) SCRealloc(aft->enc_buf, sizeof(uint8_t) * pemlen);
-            if (ptmp == NULL) {
-                SCFree(aft->enc_buf);
-                aft->enc_buf = NULL;
-                SCLogWarning(SC_ERR_MEM_ALLOC, "Can't allocate data for base64 encoding");
-                goto end_fp;
-            }
-            aft->enc_buf = ptmp;
-            aft->enc_buf_len = pemlen;
-        }
-
-        memset(aft->enc_buf, 0, aft->enc_buf_len);
-
-        ret = Base64Encode((unsigned char*) cert->cert_data, cert->cert_len, aft->enc_buf, &pemlen);
-        if (ret != SC_BASE64_OK) {
-            SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "Invalid return of Base64Encode function");
-            goto end_fwrite_fp;
-        }
-
-        if (fprintf(fp, PEMHEADER)  < 0)
-            goto end_fwrite_fp;
-
-        pembase64ptr = aft->enc_buf;
-        while (pemlen > 0) {
-            size_t loffset = pemlen >= 64 ? 64 : pemlen;
-            if (fwrite(pembase64ptr, 1, loffset, fp) != loffset)
-                goto end_fwrite_fp;
-            if (fwrite("\n", 1, 1, fp) != 1)
-                goto end_fwrite_fp;
-            pembase64ptr += 64;
-            if (pemlen < 64)
-                break;
-            pemlen -= 64;
-        }
-
-        if (fprintf(fp, PEMFOOTER) < 0)
-            goto end_fwrite_fp;
-    }
-    fclose(fp);
-
-    //Logging certificate informations
-    memcpy(filename + (strlen(filename) - 3), "meta", 4);
-    fpmeta = fopen(filename, "w");
-    if (fpmeta != NULL) {
-        #define PRINT_BUF_LEN 46
-        char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN];
-        char timebuf[64];
-        Port sp, dp;
-        CreateTimeString(&p->ts, timebuf, sizeof(timebuf));
-        if (!GetIPInformations(p, srcip, PRINT_BUF_LEN, &sp, dstip, PRINT_BUF_LEN, &dp, ipproto))
-            goto end_fwrite_fpmeta;
-        if (fprintf(fpmeta, "TIME:              %s\n", timebuf) < 0)
-            goto end_fwrite_fpmeta;
-        if (p->pcap_cnt > 0) {
-            if (fprintf(fpmeta, "PCAP PKT NUM:      %"PRIu64"\n", p->pcap_cnt) < 0)
-                goto end_fwrite_fpmeta;
-        }
-        if (fprintf(fpmeta, "SRC IP:            %s\n", srcip) < 0)
-            goto end_fwrite_fpmeta;
-        if (fprintf(fpmeta, "DST IP:            %s\n", dstip) < 0)
-            goto end_fwrite_fpmeta;
-        if (fprintf(fpmeta, "PROTO:             %" PRIu32 "\n", p->proto) < 0)
-            goto end_fwrite_fpmeta;
-        if (PKT_IS_TCP(p) || PKT_IS_UDP(p)) {
-            if (fprintf(fpmeta, "SRC PORT:          %" PRIu16 "\n", sp) < 0)
-                goto end_fwrite_fpmeta;
-            if (fprintf(fpmeta, "DST PORT:          %" PRIu16 "\n", dp) < 0)
-                goto end_fwrite_fpmeta;
-        }
-
-        if (fprintf(fpmeta, "TLS SUBJECT:       %s\n"
-                    "TLS ISSUERDN:      %s\n"
-                    "TLS FINGERPRINT:   %s\n",
-                state->server_connp.cert0_subject,
-                state->server_connp.cert0_issuerdn,
-                state->server_connp.cert0_fingerprint) < 0)
-            goto end_fwrite_fpmeta;
-
-        fclose(fpmeta);
-    } else {
-        SCLogWarning(SC_ERR_FOPEN, "Can't open meta file: %s",
-                     filename); 
-        SCReturn;
-    }
-
-    /* Reset the store flag */
-    state->server_connp.cert_log_flag &= ~SSL_TLS_LOG_PEM;
-    SCReturn;
-
-end_fwrite_fp:
-    fclose(fp);
-    SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate");
-end_fwrite_fpmeta:
-    if (fpmeta) {
-        fclose(fpmeta);
-        SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate metafile");
-    }
-    SCReturn;
-end_fp:
-    fclose(fp);
-}
-
 static TmEcode LogTlsLogThreadInit(ThreadVars *t, void *initdata, void **data)
 {
     LogTlsLogThread *aft = SCMalloc(sizeof(LogTlsLogThread));
@@ -322,39 +161,12 @@ static TmEcode LogTlsLogThreadInit(ThreadVars *t, void *initdata, void **data)
         return TM_ECODE_FAILED;
     }
 
-    struct stat stat_buf;
-    if (stat(tls_logfile_base_dir, &stat_buf) != 0) {
-        int ret;
-        ret = mkdir(tls_logfile_base_dir, S_IRWXU|S_IXGRP|S_IRGRP);
-        if (ret != 0) {
-            int err = errno;
-            if (err != EEXIST) {
-                SCLogError(SC_ERR_LOGDIR_CONFIG,
-                        "Cannot create certs drop directory %s: %s",
-                        tls_logfile_base_dir, strerror(err));
-                exit(EXIT_FAILURE);
-            }
-        } else {
-            SCLogInfo("Created certs drop directory %s",
-                    tls_logfile_base_dir);
-        }
-
-    }
-
     aft->buffer = MemBufferCreateNew(OUTPUT_BUFFER_SIZE);
     if (aft->buffer == NULL) {
         SCFree(aft);
         return TM_ECODE_FAILED;
     }
 
-    aft->enc_buf = SCMalloc(CERT_ENC_BUFFER_SIZE);
-    if (aft->enc_buf == NULL) {
-        SCFree(aft);
-        return TM_ECODE_FAILED;
-    }
-    aft->enc_buf_len = CERT_ENC_BUFFER_SIZE;
-    memset(aft->enc_buf, 0, aft->enc_buf_len);
-
     /* Use the Ouptut Context (file pointer and mutex) */
     aft->tlslog_ctx = ((OutputCtx *) initdata)->data;
 
@@ -417,24 +229,6 @@ static OutputCtx *LogTlsLogInitCtx(ConfNode *conf)
         return NULL;
     }
 
-    char *s_default_log_dir = NULL;
-    s_default_log_dir = ConfigGetLogDirectory();
-
-    const char *s_base_dir = NULL;
-    s_base_dir = ConfNodeLookupChildValue(conf, "certs-log-dir");
-    if (s_base_dir == NULL || strlen(s_base_dir) == 0) {
-        strlcpy(tls_logfile_base_dir,
-                s_default_log_dir, sizeof(tls_logfile_base_dir));
-    } else {
-        if (PathIsAbsolute(s_base_dir)) {
-            strlcpy(tls_logfile_base_dir,
-                    s_base_dir, sizeof(tls_logfile_base_dir));
-        } else {
-            snprintf(tls_logfile_base_dir, sizeof(tls_logfile_base_dir),
-                    "%s/%s", s_default_log_dir, s_base_dir);
-        }
-    }
-
     if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) {
         goto filectx_error;
     }
@@ -542,10 +336,6 @@ static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p)
     if (ssl_state->server_connp.cert0_issuerdn == NULL || ssl_state->server_connp.cert0_subject == NULL)
         goto end;
 
-    if (ssl_state->server_connp.cert_log_flag & SSL_TLS_LOG_PEM) {
-        LogTlsLogPem(aft, p, ssl_state, hlog, ipproto);
-    }
-
     /* Don't log again the state. If we are here it was because we had
      * to store the cert. */
     if (ssl_state->flags & SSL_AL_FLAG_STATE_LOGGED)
@@ -555,8 +345,8 @@ static int LogTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p)
 #define PRINT_BUF_LEN 46
     char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN];
     Port sp, dp;
-    if (!GetIPInformations(p, srcip, PRINT_BUF_LEN,
-                           &sp, dstip, PRINT_BUF_LEN, &dp, ipproto)) {
+    if (!TLSGetIPInformations(p, srcip, PRINT_BUF_LEN,
+                              &sp, dstip, PRINT_BUF_LEN, &dp, ipproto)) {
         goto end;
     }
 
@@ -600,6 +390,4 @@ void TmModuleLogTlsLogRegister(void)
 
     OutputRegisterPacketModule(MODULE_NAME, "tls-log", LogTlsLogInitCtx,
             LogTlsLogger, LogTlsCondition);
-
-    SC_ATOMIC_INIT(cert_id);
 }
index f339d5d81fb2dd2cf74aec81526e5f881886afbb..d3c9ce516b86c179c3eb223c215f5d443cefb7b3 100644 (file)
@@ -27,5 +27,9 @@
 
 void TmModuleLogTlsLogRegister (void);
 
+int TLSGetIPInformations(const Packet *p, char* srcip, size_t srcip_len,
+                             Port* sp, char* dstip, size_t dstip_len,
+                             Port* dp, int ipproto);
+
 #endif /* __LOG_TLSLOG_H__ */
 
diff --git a/src/log-tlsstore.c b/src/log-tlsstore.c
new file mode 100644 (file)
index 0000000..ddd4b80
--- /dev/null
@@ -0,0 +1,421 @@
+/* Copyright (C) 2014 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.
+ */
+
+/**
+ * \file
+ *
+ * \author Roliers Jean-Paul <popof.fpn@gmail.co>
+ * \author Eric Leblond <eric@regit.org>
+ * \author Victor Julien <victor@inliniac.net>
+ *
+ * Implements TLS store portion of the engine.
+ *
+ */
+
+#include "suricata-common.h"
+#include "debug.h"
+#include "detect.h"
+#include "pkt-var.h"
+#include "conf.h"
+
+#include "threads.h"
+#include "threadvars.h"
+#include "tm-threads.h"
+
+#include "util-print.h"
+#include "util-unittest.h"
+
+#include "util-debug.h"
+
+#include "output.h"
+#include "log-tlslog.h"
+#include "app-layer-ssl.h"
+#include "app-layer.h"
+#include "app-layer-parser.h"
+#include "util-privs.h"
+#include "util-buffer.h"
+
+#include "util-logopenfile.h"
+#include "util-crypt.h"
+#include "util-time.h"
+
+#define MODULE_NAME "LogTlsStoreLog"
+
+static char tls_logfile_base_dir[PATH_MAX] = "/tmp";
+SC_ATOMIC_DECLARE(unsigned int, cert_id);
+
+typedef struct LogTlsStoreLogThread_ {
+    uint32_t tls_cnt;
+
+    uint8_t*   enc_buf;
+    size_t     enc_buf_len;
+} LogTlsStoreLogThread;
+
+static int CreateFileName(const Packet *p, SSLState *state, char *filename)
+{
+#define FILELEN 64  //filename len + extention + ending path / + some space
+
+    int filenamelen = FILELEN + strlen(tls_logfile_base_dir);
+    int file_id = SC_ATOMIC_ADD(cert_id, 1);
+
+    if (filenamelen + 1 > PATH_MAX) {
+        return 0;
+    }
+
+    /* Use format : packet time + incremental ID
+     * When running on same pcap it will overwrite
+     * On a live device, we will not be able to overwrite */
+    snprintf(filename, filenamelen, "%s/%ld.%ld-%d.pem",
+             tls_logfile_base_dir,
+             (long int)p->ts.tv_sec,
+             (long int)p->ts.tv_usec,
+             file_id);
+    return 1;
+}
+
+static void LogTlsLogPem(LogTlsStoreLogThread *aft, const Packet *p, SSLState *state, int ipproto)
+{
+#define PEMHEADER "-----BEGIN CERTIFICATE-----\n"
+#define PEMFOOTER "-----END CERTIFICATE-----\n"
+    //Logging pem certificate
+    char filename[PATH_MAX] = "";
+    FILE* fp = NULL;
+    FILE* fpmeta = NULL;
+    unsigned long pemlen;
+    unsigned char* pembase64ptr = NULL;
+    int ret;
+    uint8_t *ptmp;
+    SSLCertsChain *cert;
+
+    if ((state->server_connp.cert_input == NULL) || (state->server_connp.cert_input_len == 0))
+        SCReturn;
+
+    CreateFileName(p, state, filename);
+    if (strlen(filename) == 0) {
+        SCLogWarning(SC_ERR_FOPEN, "Can't create PEM filename");
+        SCReturn;
+    }
+
+    fp = fopen(filename, "w");
+    if (fp == NULL) {
+        SCLogWarning(SC_ERR_FOPEN, "Can't create PEM file: %s", filename);
+        SCReturn;
+    }
+
+    TAILQ_FOREACH(cert, &state->server_connp.certs, next) {
+        pemlen = (4 * (cert->cert_len + 2) / 3) +1;
+        if (pemlen > aft->enc_buf_len) {
+            ptmp = (uint8_t*) SCRealloc(aft->enc_buf, sizeof(uint8_t) * pemlen);
+            if (ptmp == NULL) {
+                SCFree(aft->enc_buf);
+                aft->enc_buf = NULL;
+                SCLogWarning(SC_ERR_MEM_ALLOC, "Can't allocate data for base64 encoding");
+                goto end_fp;
+            }
+            aft->enc_buf = ptmp;
+            aft->enc_buf_len = pemlen;
+        }
+
+        memset(aft->enc_buf, 0, aft->enc_buf_len);
+
+        ret = Base64Encode((unsigned char*) cert->cert_data, cert->cert_len, aft->enc_buf, &pemlen);
+        if (ret != SC_BASE64_OK) {
+            SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "Invalid return of Base64Encode function");
+            goto end_fwrite_fp;
+        }
+
+        if (fprintf(fp, PEMHEADER) < 0)
+            goto end_fwrite_fp;
+
+        pembase64ptr = aft->enc_buf;
+        while (pemlen > 0) {
+            size_t loffset = pemlen >= 64 ? 64 : pemlen;
+            if (fwrite(pembase64ptr, 1, loffset, fp) != loffset)
+                goto end_fwrite_fp;
+            if (fwrite("\n", 1, 1, fp) != 1)
+                goto end_fwrite_fp;
+            pembase64ptr += 64;
+            if (pemlen < 64)
+                break;
+            pemlen -= 64;
+        }
+
+        if (fprintf(fp, PEMFOOTER) < 0)
+            goto end_fwrite_fp;
+    }
+    fclose(fp);
+
+    //Logging certificate informations
+    memcpy(filename + (strlen(filename) - 3), "meta", 4);
+    fpmeta = fopen(filename, "w");
+    if (fpmeta != NULL) {
+        #define PRINT_BUF_LEN 46
+        char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN];
+        char timebuf[64];
+        Port sp, dp;
+        CreateTimeString(&p->ts, timebuf, sizeof(timebuf));
+        if (!TLSGetIPInformations(p, srcip, PRINT_BUF_LEN, &sp, dstip, PRINT_BUF_LEN, &dp, ipproto))
+            goto end_fwrite_fpmeta;
+        if (fprintf(fpmeta, "TIME:              %s\n", timebuf) < 0)
+            goto end_fwrite_fpmeta;
+        if (p->pcap_cnt > 0) {
+            if (fprintf(fpmeta, "PCAP PKT NUM:      %"PRIu64"\n", p->pcap_cnt) < 0)
+                goto end_fwrite_fpmeta;
+        }
+        if (fprintf(fpmeta, "SRC IP:            %s\n", srcip) < 0)
+            goto end_fwrite_fpmeta;
+        if (fprintf(fpmeta, "DST IP:            %s\n", dstip) < 0)
+            goto end_fwrite_fpmeta;
+        if (fprintf(fpmeta, "PROTO:             %" PRIu32 "\n", p->proto) < 0)
+            goto end_fwrite_fpmeta;
+        if (PKT_IS_TCP(p) || PKT_IS_UDP(p)) {
+            if (fprintf(fpmeta, "SRC PORT:          %" PRIu16 "\n", sp) < 0)
+                goto end_fwrite_fpmeta;
+            if (fprintf(fpmeta, "DST PORT:          %" PRIu16 "\n", dp) < 0)
+                goto end_fwrite_fpmeta;
+        }
+
+        if (fprintf(fpmeta, "TLS SUBJECT:       %s\n"
+                    "TLS ISSUERDN:      %s\n"
+                    "TLS FINGERPRINT:   %s\n",
+                state->server_connp.cert0_subject,
+                state->server_connp.cert0_issuerdn,
+                state->server_connp.cert0_fingerprint) < 0)
+            goto end_fwrite_fpmeta;
+
+        fclose(fpmeta);
+    } else {
+        SCLogWarning(SC_ERR_FOPEN, "Can't open meta file: %s",
+                     filename);
+        SCReturn;
+    }
+
+    /* Reset the store flag */
+    state->server_connp.cert_log_flag &= ~SSL_TLS_LOG_PEM;
+    SCReturn;
+
+end_fwrite_fp:
+    fclose(fp);
+    SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate");
+end_fwrite_fpmeta:
+    if (fpmeta) {
+        fclose(fpmeta);
+        SCLogWarning(SC_ERR_FWRITE, "Unable to write certificate metafile");
+    }
+    SCReturn;
+end_fp:
+    fclose(fp);
+    SCReturn;
+}
+
+/** \internal
+ *  \brief Condition function for TLS logger
+ *  \retval bool true or false -- log now?
+ */
+static int LogTlsStoreCondition(ThreadVars *tv, const Packet *p)
+{
+    if (p->flow == NULL) {
+        return FALSE;
+    }
+
+    if (!(PKT_IS_TCP(p))) {
+        return FALSE;
+    }
+
+    FLOWLOCK_RDLOCK(p->flow);
+    uint16_t proto = FlowGetAppProtocol(p->flow);
+    if (proto != ALPROTO_TLS)
+        goto dontlog;
+
+    SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow);
+    if (ssl_state == NULL) {
+        SCLogDebug("no tls state, so no request logging");
+        goto dontlog;
+    }
+
+    /* we only log the state once if we don't have to write
+     * the cert due to tls.store keyword. */
+    if (!(ssl_state->server_connp.cert_log_flag & SSL_TLS_LOG_PEM) &&
+        (ssl_state->flags & SSL_AL_FLAG_STATE_STORED))
+        goto dontlog;
+
+    if (ssl_state->server_connp.cert0_issuerdn == NULL ||
+            ssl_state->server_connp.cert0_subject == NULL)
+        goto dontlog;
+
+    FLOWLOCK_UNLOCK(p->flow);
+    return TRUE;
+dontlog:
+    FLOWLOCK_UNLOCK(p->flow);
+    return FALSE;
+}
+
+static int LogTlsStoreLogger(ThreadVars *tv, void *thread_data, const Packet *p)
+{
+    LogTlsStoreLogThread *aft = (LogTlsStoreLogThread *)thread_data;
+    int ipproto = (PKT_IS_IPV4(p)) ? AF_INET : AF_INET6;
+    /* check if we have TLS state or not */
+    FLOWLOCK_WRLOCK(p->flow);
+    uint16_t proto = FlowGetAppProtocol(p->flow);
+    if (proto != ALPROTO_TLS)
+        goto end;
+
+    SSLState *ssl_state = (SSLState *)FlowGetAppState(p->flow);
+    if (unlikely(ssl_state == NULL)) {
+        goto end;
+    }
+
+    if (ssl_state->server_connp.cert_log_flag & SSL_TLS_LOG_PEM) {
+        LogTlsLogPem(aft, p, ssl_state, ipproto);
+    }
+
+    /* we only store the state once */
+    ssl_state->flags |= SSL_AL_FLAG_STATE_STORED;
+end:
+    FLOWLOCK_UNLOCK(p->flow);
+    return 0;
+}
+
+static TmEcode LogTlsStoreLogThreadInit(ThreadVars *t, void *initdata, void **data)
+{
+    LogTlsStoreLogThread *aft = SCMalloc(sizeof(LogTlsStoreLogThread));
+    if (unlikely(aft == NULL))
+        return TM_ECODE_FAILED;
+    memset(aft, 0, sizeof(LogTlsStoreLogThread));
+
+    if (initdata == NULL) {
+        SCLogDebug("Error getting context for LogTlsStore. \"initdata\" argument NULL");
+        SCFree(aft);
+        return TM_ECODE_FAILED;
+    }
+
+    struct stat stat_buf;
+    if (stat(tls_logfile_base_dir, &stat_buf) != 0) {
+        int ret;
+        ret = mkdir(tls_logfile_base_dir, S_IRWXU|S_IXGRP|S_IRGRP);
+        if (ret != 0) {
+            int err = errno;
+            if (err != EEXIST) {
+                SCLogError(SC_ERR_LOGDIR_CONFIG,
+                        "Cannot create certs drop directory %s: %s",
+                        tls_logfile_base_dir, strerror(err));
+                exit(EXIT_FAILURE);
+            }
+        } else {
+            SCLogInfo("Created certs drop directory %s",
+                    tls_logfile_base_dir);
+        }
+
+    }
+
+    *data = (void *)aft;
+    return TM_ECODE_OK;
+}
+
+static TmEcode LogTlsStoreLogThreadDeinit(ThreadVars *t, void *data)
+{
+    LogTlsStoreLogThread *aft = (LogTlsStoreLogThread *)data;
+    if (aft == NULL) {
+        return TM_ECODE_OK;
+    }
+
+    /* clear memory */
+    memset(aft, 0, sizeof(LogTlsStoreLogThread));
+
+    SCFree(aft);
+    return TM_ECODE_OK;
+}
+
+static void LogTlsStoreLogExitPrintStats(ThreadVars *tv, void *data)
+{
+    LogTlsStoreLogThread *aft = (LogTlsStoreLogThread *)data;
+    if (aft == NULL) {
+        return;
+    }
+
+    SCLogInfo("(%s) certificates extracted %" PRIu32 "", tv->name, aft->tls_cnt);
+}
+
+/**
+ *  \internal
+ *
+ *  \brief deinit the log ctx and write out the waldo
+ *
+ *  \param output_ctx output context to deinit
+ */
+static void LogTlsStoreLogDeInitCtx(OutputCtx *output_ctx)
+{
+    SCFree(output_ctx);
+}
+
+/** \brief Create a new http log LogFilestoreCtx.
+ *  \param conf Pointer to ConfNode containing this loggers configuration.
+ *  \return NULL if failure, LogFilestoreCtx* to the file_ctx if succesful
+ * */
+static OutputCtx *LogTlsStoreLogInitCtx(ConfNode *conf)
+{
+
+    OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
+    if (unlikely(output_ctx == NULL))
+        return NULL;
+
+    output_ctx->data = NULL;
+    output_ctx->DeInit = LogTlsStoreLogDeInitCtx;
+
+    /* FIXME we need to implement backward compability here */
+    char *s_default_log_dir = NULL;
+    s_default_log_dir = ConfigGetLogDirectory();
+
+    const char *s_base_dir = NULL;
+    s_base_dir = ConfNodeLookupChildValue(conf, "certs-log-dir");
+    if (s_base_dir == NULL || strlen(s_base_dir) == 0) {
+        strlcpy(tls_logfile_base_dir,
+                s_default_log_dir, sizeof(tls_logfile_base_dir));
+    } else {
+        if (PathIsAbsolute(s_base_dir)) {
+            strlcpy(tls_logfile_base_dir,
+                    s_base_dir, sizeof(tls_logfile_base_dir));
+        } else {
+            snprintf(tls_logfile_base_dir, sizeof(tls_logfile_base_dir),
+                    "%s/%s", s_default_log_dir, s_base_dir);
+        }
+    }
+
+    SCLogInfo("storing certs in %s", tls_logfile_base_dir);
+
+    SCReturnPtr(output_ctx, "OutputCtx");
+}
+
+void TmModuleLogTlsStoreRegister (void)
+{
+    tmm_modules[TMM_TLSSTORE].name = MODULE_NAME;
+    tmm_modules[TMM_TLSSTORE].ThreadInit = LogTlsStoreLogThreadInit;
+    tmm_modules[TMM_TLSSTORE].Func = NULL;
+    tmm_modules[TMM_TLSSTORE].ThreadExitPrintStats = LogTlsStoreLogExitPrintStats;
+    tmm_modules[TMM_TLSSTORE].ThreadDeinit = LogTlsStoreLogThreadDeinit;
+    tmm_modules[TMM_TLSSTORE].RegisterTests = NULL;
+    tmm_modules[TMM_TLSSTORE].cap_flags = 0;
+    tmm_modules[TMM_TLSSTORE].flags = TM_FLAG_LOGAPI_TM;
+    tmm_modules[TMM_TLSSTORE].priority = 10;
+
+    OutputRegisterPacketModule(MODULE_NAME, "tls-store", LogTlsStoreLogInitCtx,
+            LogTlsStoreLogger, LogTlsStoreCondition);
+
+    SC_ATOMIC_INIT(cert_id);
+
+    SCLogDebug("registered");
+}
diff --git a/src/log-tlsstore.h b/src/log-tlsstore.h
new file mode 100644 (file)
index 0000000..6cbacab
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2015 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.
+ */
+
+/**
+ * \file
+ *
+ * \author Victor Julien <victor@inliniac.net>
+ */
+
+#ifndef __LOG_TLSSTORE_H__
+#define __LOG_TLSSTORE_H__
+
+void TmModuleLogTlsStoreRegister (void);
+
+#endif /* __LOG_TLSSTORE_H__ */
index c7f2ffe9491c094842675000186d2d78a849007f..e571c796bc15acad28d1ea70cf4e80665f34f5a3 100644 (file)
@@ -88,6 +88,7 @@
 #include "log-dnslog.h"
 #include "output-json-dns.h"
 #include "log-tlslog.h"
+#include "log-tlsstore.h"
 #include "output-json-tls.h"
 #include "output-json-ssh.h"
 #include "log-pcap.h"
@@ -872,6 +873,7 @@ void RegisterAllModules()
     /* tls log */
     TmModuleLogTlsLogRegister();
     TmModuleJsonTlsLogRegister();
+    TmModuleLogTlsStoreRegister();
     /* ssh */
     TmModuleJsonSshLogRegister();
     /* pcap log */
index 7d29551fd930a58219893823b0f51e12d60ca585..c6f8c9ac76d68bef7c0e53c7d85cb0dee90a65dc 100644 (file)
@@ -273,6 +273,7 @@ const char * TmModuleTmmIdToString(TmmId id)
         CASE_CODE (TMM_LOGSTATSLOG);
         CASE_CODE (TMM_RECEIVENETMAP);
         CASE_CODE (TMM_DECODENETMAP);
+        CASE_CODE (TMM_TLSSTORE);
 
         CASE_CODE (TMM_SIZE);
     }
index 17ea053d15dea37b2e5d1f2f79e57e3e88b320e3..e59c2a8764f7f038c5e60de03f0526d61e209aba 100644 (file)
@@ -108,6 +108,7 @@ typedef enum {
     TMM_UNIXMANAGER,
 
     TMM_LUALOG,
+    TMM_TLSSTORE,
     TMM_SIZE,
 } TmmId;
 
index 64a8182a298b8d8c6022b472bdd4444040b8b164..415afacc11d6d6e27456d9ad70e9a4a5c3d92d6e 100644 (file)
@@ -200,7 +200,11 @@ outputs:
       append: yes
       #filetype: regular # 'regular', 'unix_stream' or 'unix_dgram'
       #extended: yes # Log extended information like fingerprint
-      certs-log-dir: certs # directory to store the certificates files
+
+  # output module to store certificates chain to disk
+  - tls-store:
+      enabled: no
+      #certs-log-dir: certs # directory to store the certificates files
 
   # a line based log of DNS requests and/or replies (no alerts)
   - dns-log: