]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
tls: adding store option for TLS
authorJean-Paul Roliers <popof.fpn@gmail.com>
Sat, 4 Feb 2012 16:37:41 +0000 (17:37 +0100)
committerEric Leblond <eric@regit.org>
Fri, 24 Aug 2012 10:59:12 +0000 (12:59 +0200)
This patch adds a TLS store option to save certificate in PEM format.
Each time the store action is met, a file and a metafile are created.

Reworked-by: Eric Leblond <eric@regit.org>
src/app-layer-ssl.c
src/app-layer-ssl.h
src/app-layer-tls-handshake.c
src/detect-tls.c
src/detect.h
src/log-tlslog.c
suricata.yaml.in

index c092a5f98b8aaba1d58b987025a0ee24039784eb..6c71a44c19839d5ccf9b815cdf516e39543c867c 100644 (file)
@@ -860,6 +860,8 @@ void *SSLStateAlloc(void)
     if (ssl_state == NULL)
         return NULL;
     memset(ssl_state, 0, sizeof(SSLState));
+    ((SSLState*)ssl_state)->client_connp.cert_log_flag = 0;
+    ((SSLState*)ssl_state)->server_connp.cert_log_flag = 0;
 
     return ssl_state;
 }
index 85da873c1fe1e36fab866734a2627006b07a10c0..1d6f1f81bbcfe20c59910928ac8d13c43e8d33a0 100644 (file)
@@ -64,6 +64,9 @@ enum {
 #define SSL_AL_FLAG_STATE_SERVER_KEYX           0x1000
 #define SSL_AL_FLAG_STATE_UNKNOWN               0x2000
 
+#define SSL_TLS_LOG_PEM                         (1 << 0)
+
+
 
 /* SSL versions.  We'll use a unified format for all, with the top byte
  * holding the major version and the lower byte the minor version */
@@ -102,6 +105,11 @@ typedef struct SSLStateConnp_ {
     char *cert0_issuerdn;
     char *cert0_fingerprint;
 
+    uint8_t *cert_input;
+    uint32_t cert_input_len;
+
+    uint32_t cert_log_flag;
+
     /* buffer for the tls record.
      * We use a malloced buffer, if the record is fragmented */
     uint8_t *trec;
index ce0349cafdea9403bd7b241c9cef531a9b65cc01..8c086cbeec9e3d7b01beb2c3fd70d33309fe8abc 100644 (file)
@@ -124,8 +124,8 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin
             } else {
                 //SCLogInfo("TLS Cert %d: %s\n", i, buffer);
                 if (i==0) {
-                    ssl_state->curr_connp->cert0_subject = SCStrdup(buffer);
-                    if (ssl_state->curr_connp->cert0_subject == NULL) {
+                    ssl_state->server_connp.cert0_subject = SCStrdup(buffer);
+                    if (ssl_state->server_connp.cert0_subject == NULL) {
                         DerFree(cert);
                         return -1;
                     }
@@ -137,8 +137,8 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin
             } else {
                 //SCLogInfo("TLS IssuerDN %d: %s\n", i, buffer);
                 if (i==0) {
-                    ssl_state->curr_connp->cert0_issuerdn = SCStrdup(buffer);
-                    if (ssl_state->curr_connp->cert0_issuerdn == NULL) {
+                    ssl_state->server_connp.cert0_issuerdn = SCStrdup(buffer);
+                    if (ssl_state->server_connp.cert0_issuerdn == NULL) {
                         DerFree(cert);
                         return -1;
                     }
@@ -169,6 +169,9 @@ int DecodeTLSHandshakeServerCertificate(SSLState *ssl_state, uint8_t *input, uin
                         SCLogWarning(SC_ERR_MEM_ALLOC, "Can not allocate fingerprint string");
                     }
                 }
+
+                ssl_state->server_connp.cert_input = input;
+                ssl_state->server_connp.cert_input_len = cur_cert_length;
             }
 
         }
index ba88083f7b74d698bd48bc5e3b2ef79e8a97e0e2..2075494bd6145894dfb50c41bcc6ecf69058b48c 100644 (file)
@@ -85,6 +85,9 @@ static void DetectTlsIssuerDNFree(void *);
 static int DetectTlsFingerprintMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *);
 static int DetectTlsFingerprintSetup (DetectEngineCtx *, Signature *, char *);
 static void DetectTlsFingerprintFree(void *);
+static int DetectTlsStoreSetup (DetectEngineCtx *, Signature *, char *);
+static int DetectTlsStoreMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, uint8_t, void *, Signature *, SigMatch *);
+
 /**
  * \brief Registration function for keyword: tls.version
  */
@@ -113,6 +116,15 @@ void DetectTlsRegister (void) {
     sigmatch_table[DETECT_AL_TLS_FINGERPRINT].Free  = DetectTlsFingerprintFree;
     sigmatch_table[DETECT_AL_TLS_FINGERPRINT].RegisterTests = NULL;
 
+    sigmatch_table[DETECT_AL_TLS_STORE].name = "tls.store";
+    sigmatch_table[DETECT_AL_TLS_STORE].Match = NULL;
+    sigmatch_table[DETECT_AL_TLS_STORE].AppLayerMatch = DetectTlsStoreMatch;
+    sigmatch_table[DETECT_AL_TLS_STORE].alproto = ALPROTO_TLS;
+    sigmatch_table[DETECT_AL_TLS_STORE].Setup = DetectTlsStoreSetup;
+    sigmatch_table[DETECT_AL_TLS_STORE].Free  = NULL;
+    sigmatch_table[DETECT_AL_TLS_STORE].RegisterTests = NULL;
+    sigmatch_table[DETECT_AL_TLS_STORE].flags |= SIGMATCH_NOOPT;
+
     const char *eb;
     int eo;
     int opts = 0;
@@ -745,6 +757,64 @@ static void DetectTlsFingerprintFree(void *ptr) {
     SCFree(id_d);
 }
 
+/**
+ * \brief this function is used to add the parsed "store" option
+ * \brief into the current signature
+ *
+ * \param de_ctx pointer to the Detection Engine Context
+ * \param s pointer to the Current Signature
+ * \param idstr pointer to the user provided "store" option
+ *
+ * \retval 0 on Success
+ * \retval -1 on Failure
+ */
+static int DetectTlsStoreSetup (DetectEngineCtx *de_ctx, Signature *s, char *str)
+{
+    SigMatch *sm = NULL;
+
+    s->flags |= SIG_FLAG_TLSSTORE;
+
+    sm = SigMatchAlloc();
+    if (sm == NULL)
+        goto error;
+
+    sm->type = DETECT_AL_TLS_STORE;
+    SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH);
+
+    if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_TLS) {
+        SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords.");
+        goto error;
+    }
+
+    s->alproto = ALPROTO_TLS;
+    return 0;
+
+error:
+    if (sm != NULL) SCFree(sm);
+        return -1;
+
+}
+
+static int DetectTlsStoreMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m)
+{
+    SCEnter();
+
+    SSLState *ssl_state = (SSLState *)state;
+    if (ssl_state == NULL) {
+        SCLogDebug("no tls state, no match");
+        SCReturnInt(1);
+    }
+
+    FLOWLOCK_WRLOCK(f);
+    if (s->flags & SIG_FLAG_TLSSTORE) {
+        ssl_state->server_connp.cert_log_flag |= SSL_TLS_LOG_PEM;
+    }
+
+    FLOWLOCK_UNLOCK(f);
+    SCReturnInt(1);
+}
+
+
 /**
  * \brief this function registers unit tests for DetectTlsIssuerDN
  */
index 86ca8d3ff09b956142bd72614837eb6264787107..be9607e45950abfdddf72b04746d0e5a222121f1 100644 (file)
@@ -261,6 +261,8 @@ typedef struct DetectPort_ {
 #define SIG_FLAG_TOSERVER               (1<<19)
 #define SIG_FLAG_TOCLIENT               (1<<20)
 
+#define SIG_FLAG_TLSSTORE               (1<<21)
+
 /* signature init flags */
 #define SIG_FLAG_INIT_DEONLY         1  /**< decode event only signature */
 #define SIG_FLAG_INIT_PACKET         (1<<1)  /**< signature has matches against a packet (as opposed to app layer) */
@@ -996,6 +998,7 @@ enum {
     DETECT_AL_TLS_SUBJECT,
     DETECT_AL_TLS_ISSUERDN,
     DETECT_AL_TLS_FINGERPRINT,
+    DETECT_AL_TLS_STORE,
 
     DETECT_AL_HTTP_COOKIE,
     DETECT_AL_HTTP_METHOD,
index bb1fae1b6ae9e92cd06e7bd38927c0c8cdd6a621..b7514c17b5f63880ae9924a8912f273787f67ba2 100644 (file)
 #include "util-buffer.h"
 
 #include "util-logopenfile.h"
+#include "util-crypt.h"
 
 #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
+#define CERT_ENC_BUFFER_SIZE 2048
 
 #define LOG_TLS_DEFAULT     0
 #define LOG_TLS_EXTENDED    1
@@ -79,6 +84,8 @@ void TmModuleLogTlsLogRegister(void)
 
     /* enable the logger for the app layer */
     AppLayerRegisterLogger(ALPROTO_TLS);
+
+    SC_ATOMIC_INIT(cert_id);
 }
 
 void TmModuleLogTlsLogIPv4Register(void)
@@ -109,10 +116,13 @@ typedef struct LogTlsFileCtx_ {
 
 typedef struct LogTlsLogThread_ {
     LogTlsFileCtx *tlslog_ctx;
+
     /** LogTlsFileCtx has the pointer to the file and a mutex to allow multithreading */
     uint32_t tls_cnt;
 
     MemBuffer *buffer;
+    uint8_t*   enc_buf;
+    size_t     enc_buf_len;
 } LogTlsLogThread;
 
 static void CreateTimeString(const struct timeval *ts, char *str, size_t size)
@@ -121,7 +131,9 @@ static void CreateTimeString(const struct timeval *ts, char *str, size_t size)
     struct tm local_tm;
     struct tm *t = (struct tm *) localtime_r(&time, &local_tm);
 
-    snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec);
+    snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u",
+        t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour,
+            t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec);
 }
 
 static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState * state)
@@ -131,6 +143,194 @@ static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState * state)
     }
 }
 
+static int GetIPInformations(Packet *p, char* srcip, size_t srcip_len,
+                             Port* sp, char* dstip, size_t dstip_len,
+                             Port* dp, int ipproto)
+{
+    if ((PKT_IS_TOSERVER(p))) {
+        switch (ipproto) {
+            case AF_INET:
+                PrintInet(AF_INET, (const void *) GET_IPV4_SRC_ADDR_PTR(p), srcip, srcip_len);
+                PrintInet(AF_INET, (const void *) GET_IPV4_DST_ADDR_PTR(p), dstip, dstip_len);
+                break;
+            case AF_INET6:
+                PrintInet(AF_INET6, (const void *) GET_IPV6_SRC_ADDR(p), srcip, srcip_len);
+                PrintInet(AF_INET6, (const void *) GET_IPV6_DST_ADDR(p), dstip, dstip_len);
+                break;
+            default:
+                return 0;
+        }
+        *sp = p->sp;
+        *dp = p->dp;
+    } else {
+        switch (ipproto) {
+            case AF_INET:
+                PrintInet(AF_INET, (const void *) GET_IPV4_DST_ADDR_PTR(p), srcip, srcip_len);
+                PrintInet(AF_INET, (const void *) GET_IPV4_SRC_ADDR_PTR(p), dstip, dstip_len);
+                break;
+            case AF_INET6:
+                PrintInet(AF_INET6, (const void *) GET_IPV6_DST_ADDR(p), srcip, srcip_len);
+                PrintInet(AF_INET6, (const void *) GET_IPV6_SRC_ADDR(p), dstip, dstip_len);
+                break;
+            default:
+                return 0;
+        }
+        *sp = p->dp;
+        *dp = p->sp;
+    }
+    return 1;
+}
+
+static int CreateFileName(LogTlsFileCtx *log, 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,
+             p->ts.tv_sec,
+             p->ts.tv_usec,
+             file_id);
+    return 1;
+}
+
+
+static void LogTlsLogPem(LogTlsLogThread *aft, 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;
+
+    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;
+    }
+
+    pemlen = (4 * (state->server_connp.cert_input_len + 2) / 3) +1;
+    if (pemlen > aft->enc_buf_len) {
+        aft->enc_buf = (uint8_t*) SCRealloc(aft->enc_buf, sizeof(uint8_t) * pemlen);
+        if (aft->enc_buf == NULL) {
+            SCLogWarning(SC_ERR_MEM_ALLOC, "Can't allocate data for base64 encoding");
+            goto end_fp;
+        }
+        aft->enc_buf_len = pemlen;
+    }
+
+    memset(aft->enc_buf, 0, aft->enc_buf_len);
+
+    ret = Base64Encode((unsigned char*) state->server_connp.cert_input, state->server_connp.cert_input_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");
+    }
+end_fp:
+    fclose(fp);
+}
+
+
 static TmEcode LogTlsLogIPWrapper(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq, int ipproto)
 {
 
@@ -151,12 +351,6 @@ static TmEcode LogTlsLogIPWrapper(ThreadVars *tv, Packet *p, void *data, PacketQ
     if (proto != ALPROTO_TLS)
         goto end;
 
-    int r = AppLayerTransactionGetLoggedId(p->flow);
-
-    if (r != 0) {
-        goto end;
-    }
-
     SSLState *ssl_state = (SSLState *) AppLayerGetProtoStateFromPacket(p);
     if (ssl_state == NULL) {
         SCLogDebug("no tls state, so no request logging");
@@ -166,39 +360,23 @@ static TmEcode LogTlsLogIPWrapper(ThreadVars *tv, Packet *p, void *data, PacketQ
     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);
+    }
+
+    int r = AppLayerTransactionGetLoggedId(p->flow);
+
+    if (r != 0) {
+        goto end;
+    }
+
     CreateTimeString(&p->ts, timebuf, sizeof(timebuf));
-    char srcip[46], dstip[46];
+    #define PRINT_BUF_LEN 46
+    char srcip[PRINT_BUF_LEN], dstip[PRINT_BUF_LEN];
     Port sp, dp;
-    if ((PKT_IS_TOSERVER(p))) {
-        switch (ipproto) {
-        case AF_INET:
-            PrintInet(AF_INET, (const void *) GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip));
-            PrintInet(AF_INET, (const void *) GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip));
-            break;
-        case AF_INET6:
-            PrintInet(AF_INET6, (const void *) GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip));
-            PrintInet(AF_INET6, (const void *) GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip));
-            break;
-        default:
-            goto end;
-        }
-        sp = p->sp;
-        dp = p->dp;
-    } else {
-        switch (ipproto) {
-        case AF_INET:
-            PrintInet(AF_INET, (const void *) GET_IPV4_DST_ADDR_PTR(p), srcip, sizeof(srcip));
-            PrintInet(AF_INET, (const void *) GET_IPV4_SRC_ADDR_PTR(p), dstip, sizeof(dstip));
-            break;
-        case AF_INET6:
-            PrintInet(AF_INET6, (const void *) GET_IPV6_DST_ADDR(p), srcip, sizeof(srcip));
-            PrintInet(AF_INET6, (const void *) GET_IPV6_SRC_ADDR(p), dstip, sizeof(dstip));
-            break;
-        default:
-            goto end;
-        }
-        sp = p->dp;
-        dp = p->sp;
+    if (!GetIPInformations(p, srcip, PRINT_BUF_LEN,
+                           &sp, dstip, PRINT_BUF_LEN, &dp, ipproto)) {
+        goto end;
     }
 
     /* reset */
@@ -210,6 +388,7 @@ static TmEcode LogTlsLogIPWrapper(ThreadVars *tv, Packet *p, void *data, PacketQ
                          ssl_state->server_connp.cert0_subject, ssl_state->server_connp.cert0_issuerdn);
 
     AppLayerTransactionUpdateLoggedId(p->flow);
+
     if (hlog->flags & LOG_TLS_EXTENDED) {
         LogTlsLogExtended(aft, ssl_state);
     } else {
@@ -280,6 +459,14 @@ TmEcode LogTlsLogThreadInit(ThreadVars *t, void *initdata, void **data)
         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;
 
@@ -326,6 +513,26 @@ OutputCtx *LogTlsLogInitCtx(ConfNode *conf)
         return NULL;
     }
 
+    char *s_default_log_dir = NULL;
+    if (ConfGet("default-log-dir", &s_default_log_dir) != 1)
+        s_default_log_dir = DEFAULT_LOG_DIR;
+
+    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);
+        }
+    }
+
+    /* FIXME config variable here */
     if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME) < 0) {
         LogFileFreeCtx(file_ctx);
         return NULL;
@@ -345,7 +552,6 @@ OutputCtx *LogTlsLogInitCtx(ConfNode *conf)
         }
     }
 
-
     OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
     if (output_ctx == NULL)
         return NULL;
index e6ce8bacc9616649c0e58ace91a929a1dbee81f4..c0526405ca0bd4c17fbc779c023d5bfd62abad31 100644 (file)
@@ -80,6 +80,7 @@ outputs:
       enabled: no  # Log TLS connections.
       filename: tls.log # File to store TLS logs.
       #extended: yes # Log extended information like fingerprint
+      certs-log-dir: certs # directory to store the certificates files
 
   # a line based log to used with pcap file study.
   # this module is dedicated to offline pcap parsing (empty output