|
|
|
@ -53,11 +53,6 @@
|
|
|
|
|
|
|
|
|
|
SC_ATOMIC_EXTERN(unsigned int, cert_id);
|
|
|
|
|
|
|
|
|
|
#define LOG_TLS_DEFAULT 0
|
|
|
|
|
#define LOG_TLS_EXTENDED (1 << 0)
|
|
|
|
|
#define LOG_TLS_CUSTOM (1 << 1)
|
|
|
|
|
#define LOG_TLS_SESSION_RESUMPTION (1 << 2)
|
|
|
|
|
|
|
|
|
|
#define LOG_TLS_FIELD_VERSION (1 << 0)
|
|
|
|
|
#define LOG_TLS_FIELD_SUBJECT (1 << 1)
|
|
|
|
|
#define LOG_TLS_FIELD_ISSUER (1 << 2)
|
|
|
|
@ -110,13 +105,36 @@ TlsFields tls_fields[] = {
|
|
|
|
|
// clang-format on
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
|
static const uint64_t BASIC_FIELDS = \
|
|
|
|
|
LOG_TLS_FIELD_SUBJECT |
|
|
|
|
|
LOG_TLS_FIELD_ISSUER |
|
|
|
|
|
LOG_TLS_FIELD_SUBJECTALTNAME;
|
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
|
static const uint64_t EXTENDED_FIELDS = \
|
|
|
|
|
BASIC_FIELDS |
|
|
|
|
|
LOG_TLS_FIELD_VERSION |
|
|
|
|
|
LOG_TLS_FIELD_SERIAL |
|
|
|
|
|
LOG_TLS_FIELD_FINGERPRINT |
|
|
|
|
|
LOG_TLS_FIELD_NOTBEFORE |
|
|
|
|
|
LOG_TLS_FIELD_NOTAFTER |
|
|
|
|
|
LOG_TLS_FIELD_JA3 |
|
|
|
|
|
LOG_TLS_FIELD_JA3S |
|
|
|
|
|
LOG_TLS_FIELD_JA4 |
|
|
|
|
|
LOG_TLS_FIELD_CLIENT |
|
|
|
|
|
LOG_TLS_FIELD_CLIENT_ALPNS |
|
|
|
|
|
LOG_TLS_FIELD_SERVER_ALPNS |
|
|
|
|
|
LOG_TLS_FIELD_SNI;
|
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
|
|
typedef struct OutputTlsCtx_ {
|
|
|
|
|
uint32_t flags; /** Store mode */
|
|
|
|
|
uint64_t fields; /** Store fields */
|
|
|
|
|
bool session_resumed;
|
|
|
|
|
OutputJsonCtx *eve_ctx;
|
|
|
|
|
} OutputTlsCtx;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct JsonTlsLogThread_ {
|
|
|
|
|
OutputTlsCtx *tlslog_ctx;
|
|
|
|
|
OutputJsonThreadCtx *ctx;
|
|
|
|
@ -371,95 +389,79 @@ static void JsonTlsLogClientCert(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void JsonTlsLogJSONBasic(JsonBuilder *js, SSLState *ssl_state)
|
|
|
|
|
static void JsonTlsLogFields(JsonBuilder *js, SSLState *ssl_state, uint64_t fields)
|
|
|
|
|
{
|
|
|
|
|
/* tls subject */
|
|
|
|
|
JsonTlsLogSubject(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
/* tls issuerdn */
|
|
|
|
|
JsonTlsLogIssuer(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
/* tls subjectaltname */
|
|
|
|
|
JsonTlsLogSAN(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
/* tls session resumption */
|
|
|
|
|
JsonTlsLogSessionResumed(js, ssl_state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void JsonTlsLogJSONCustom(OutputTlsCtx *tls_ctx, JsonBuilder *js,
|
|
|
|
|
SSLState *ssl_state)
|
|
|
|
|
{
|
|
|
|
|
/* tls subject */
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_SUBJECT)
|
|
|
|
|
if (fields & LOG_TLS_FIELD_SUBJECT)
|
|
|
|
|
JsonTlsLogSubject(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
/* tls issuerdn */
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_ISSUER)
|
|
|
|
|
if (fields & LOG_TLS_FIELD_ISSUER)
|
|
|
|
|
JsonTlsLogIssuer(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
/* tls subjectaltname */
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_SUBJECTALTNAME)
|
|
|
|
|
if (fields & LOG_TLS_FIELD_SUBJECTALTNAME)
|
|
|
|
|
JsonTlsLogSAN(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
/* tls session resumption */
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_SESSION_RESUMED)
|
|
|
|
|
if (fields & LOG_TLS_FIELD_SESSION_RESUMED)
|
|
|
|
|
JsonTlsLogSessionResumed(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
/* tls serial */
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_SERIAL)
|
|
|
|
|
if (fields & LOG_TLS_FIELD_SERIAL)
|
|
|
|
|
JsonTlsLogSerial(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
/* tls fingerprint */
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_FINGERPRINT)
|
|
|
|
|
if (fields & LOG_TLS_FIELD_FINGERPRINT)
|
|
|
|
|
JsonTlsLogFingerprint(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
/* tls sni */
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_SNI)
|
|
|
|
|
if (fields & LOG_TLS_FIELD_SNI)
|
|
|
|
|
JsonTlsLogSni(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
/* tls version */
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_VERSION)
|
|
|
|
|
if (fields & LOG_TLS_FIELD_VERSION)
|
|
|
|
|
JsonTlsLogVersion(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
/* tls notbefore */
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_NOTBEFORE)
|
|
|
|
|
if (fields & LOG_TLS_FIELD_NOTBEFORE)
|
|
|
|
|
JsonTlsLogNotBefore(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
/* tls notafter */
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_NOTAFTER)
|
|
|
|
|
if (fields & LOG_TLS_FIELD_NOTAFTER)
|
|
|
|
|
JsonTlsLogNotAfter(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
/* tls certificate */
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE)
|
|
|
|
|
if (fields & LOG_TLS_FIELD_CERTIFICATE)
|
|
|
|
|
JsonTlsLogCertificate(js, &ssl_state->server_connp);
|
|
|
|
|
|
|
|
|
|
/* tls chain */
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_CHAIN)
|
|
|
|
|
if (fields & LOG_TLS_FIELD_CHAIN)
|
|
|
|
|
JsonTlsLogChain(js, &ssl_state->server_connp);
|
|
|
|
|
|
|
|
|
|
/* tls ja3_hash */
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_JA3)
|
|
|
|
|
if (fields & LOG_TLS_FIELD_JA3)
|
|
|
|
|
JsonTlsLogJa3(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
/* tls ja3s */
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_JA3S)
|
|
|
|
|
if (fields & LOG_TLS_FIELD_JA3S)
|
|
|
|
|
JsonTlsLogJa3S(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
/* tls ja4 */
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_JA4)
|
|
|
|
|
if (fields & LOG_TLS_FIELD_JA4)
|
|
|
|
|
JsonTlsLogSCJA4(js, ssl_state);
|
|
|
|
|
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_ALPNS) {
|
|
|
|
|
if (fields & LOG_TLS_FIELD_CLIENT_ALPNS) {
|
|
|
|
|
JsonTlsLogAlpns(js, &ssl_state->client_connp, "client_alpns");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tls_ctx->fields & LOG_TLS_FIELD_SERVER_ALPNS) {
|
|
|
|
|
if (fields & LOG_TLS_FIELD_SERVER_ALPNS) {
|
|
|
|
|
JsonTlsLogAlpns(js, &ssl_state->server_connp, "server_alpns");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 (fields & LOG_TLS_FIELD_CLIENT) {
|
|
|
|
|
const bool log_cert = (fields & LOG_TLS_FIELD_CLIENT_CERT) != 0;
|
|
|
|
|
const bool log_chain = (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);
|
|
|
|
@ -468,55 +470,12 @@ static void JsonTlsLogJSONCustom(OutputTlsCtx *tls_ctx, JsonBuilder *js,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool JsonTlsLogJSONExtendedAux(void *vtx, JsonBuilder *tjs)
|
|
|
|
|
{
|
|
|
|
|
SSLState *state = (SSLState *)vtx;
|
|
|
|
|
JsonTlsLogJSONBasic(tjs, state);
|
|
|
|
|
|
|
|
|
|
/* tls serial */
|
|
|
|
|
JsonTlsLogSerial(tjs, state);
|
|
|
|
|
|
|
|
|
|
/* tls fingerprint */
|
|
|
|
|
JsonTlsLogFingerprint(tjs, state);
|
|
|
|
|
|
|
|
|
|
/* tls sni */
|
|
|
|
|
JsonTlsLogSni(tjs, state);
|
|
|
|
|
|
|
|
|
|
/* tls version */
|
|
|
|
|
JsonTlsLogVersion(tjs, state);
|
|
|
|
|
|
|
|
|
|
/* tls notbefore */
|
|
|
|
|
JsonTlsLogNotBefore(tjs, state);
|
|
|
|
|
|
|
|
|
|
/* tls notafter */
|
|
|
|
|
JsonTlsLogNotAfter(tjs, state);
|
|
|
|
|
|
|
|
|
|
/* tls ja3 */
|
|
|
|
|
JsonTlsLogJa3(tjs, state);
|
|
|
|
|
|
|
|
|
|
/* tls ja3s */
|
|
|
|
|
JsonTlsLogJa3S(tjs, state);
|
|
|
|
|
|
|
|
|
|
/* tls ja4 */
|
|
|
|
|
JsonTlsLogSCJA4(tjs, state);
|
|
|
|
|
|
|
|
|
|
JsonTlsLogAlpns(tjs, &state->client_connp, "client_alpns");
|
|
|
|
|
JsonTlsLogAlpns(tjs, &state->server_connp, "server_alpns");
|
|
|
|
|
|
|
|
|
|
if (HasClientCert(&state->client_connp)) {
|
|
|
|
|
jb_open_object(tjs, "client");
|
|
|
|
|
JsonTlsLogClientCert(tjs, &state->client_connp, false, false);
|
|
|
|
|
jb_close(tjs);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool JsonTlsLogJSONExtended(void *vtx, JsonBuilder *tjs)
|
|
|
|
|
{
|
|
|
|
|
SSLState *state = (SSLState *)vtx;
|
|
|
|
|
jb_open_object(tjs, "tls");
|
|
|
|
|
bool r = JsonTlsLogJSONExtendedAux(vtx, tjs);
|
|
|
|
|
jb_close(tjs);
|
|
|
|
|
return r;
|
|
|
|
|
JsonTlsLogFields(tjs, state, EXTENDED_FIELDS);
|
|
|
|
|
return jb_close(tjs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p,
|
|
|
|
@ -531,9 +490,9 @@ static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((ssl_state->server_connp.cert0_issuerdn == NULL ||
|
|
|
|
|
ssl_state->server_connp.cert0_subject == NULL) &&
|
|
|
|
|
ssl_state->server_connp.cert0_subject == NULL) &&
|
|
|
|
|
((ssl_state->flags & SSL_AL_FLAG_SESSION_RESUMED) == 0 ||
|
|
|
|
|
(tls_ctx->flags & LOG_TLS_SESSION_RESUMPTION) == 0) &&
|
|
|
|
|
(!tls_ctx->session_resumed)) &&
|
|
|
|
|
((ssl_state->flags & SSL_AL_FLAG_LOG_WITHOUT_CERT) == 0)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -545,18 +504,7 @@ static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p,
|
|
|
|
|
|
|
|
|
|
jb_open_object(js, "tls");
|
|
|
|
|
|
|
|
|
|
/* log custom fields */
|
|
|
|
|
if (tls_ctx->flags & LOG_TLS_CUSTOM) {
|
|
|
|
|
JsonTlsLogJSONCustom(tls_ctx, js, ssl_state);
|
|
|
|
|
}
|
|
|
|
|
/* log extended */
|
|
|
|
|
else if (tls_ctx->flags & LOG_TLS_EXTENDED) {
|
|
|
|
|
JsonTlsLogJSONExtendedAux(ssl_state, js);
|
|
|
|
|
}
|
|
|
|
|
/* log basic */
|
|
|
|
|
else {
|
|
|
|
|
JsonTlsLogJSONBasic(js, ssl_state);
|
|
|
|
|
}
|
|
|
|
|
JsonTlsLogFields(js, ssl_state, tls_ctx->fields);
|
|
|
|
|
|
|
|
|
|
/* print original application level protocol when it have been changed
|
|
|
|
|
because of STARTTLS, HTTP CONNECT, or similar. */
|
|
|
|
@ -619,12 +567,12 @@ static TmEcode JsonTlsLogThreadDeinit(ThreadVars *t, void *data)
|
|
|
|
|
|
|
|
|
|
static OutputTlsCtx *OutputTlsInitCtx(ConfNode *conf)
|
|
|
|
|
{
|
|
|
|
|
OutputTlsCtx *tls_ctx = SCMalloc(sizeof(OutputTlsCtx));
|
|
|
|
|
OutputTlsCtx *tls_ctx = SCCalloc(1, sizeof(OutputTlsCtx));
|
|
|
|
|
if (unlikely(tls_ctx == NULL))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
tls_ctx->flags = LOG_TLS_DEFAULT;
|
|
|
|
|
tls_ctx->fields = 0;
|
|
|
|
|
tls_ctx->fields = BASIC_FIELDS;
|
|
|
|
|
tls_ctx->session_resumed = false;
|
|
|
|
|
|
|
|
|
|
if (conf == NULL)
|
|
|
|
|
return tls_ctx;
|
|
|
|
@ -632,13 +580,13 @@ static OutputTlsCtx *OutputTlsInitCtx(ConfNode *conf)
|
|
|
|
|
const char *extended = ConfNodeLookupChildValue(conf, "extended");
|
|
|
|
|
if (extended) {
|
|
|
|
|
if (ConfValIsTrue(extended)) {
|
|
|
|
|
tls_ctx->flags = LOG_TLS_EXTENDED;
|
|
|
|
|
tls_ctx->fields = EXTENDED_FIELDS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ConfNode *custom = ConfNodeLookupChild(conf, "custom");
|
|
|
|
|
if (custom) {
|
|
|
|
|
tls_ctx->flags = LOG_TLS_CUSTOM;
|
|
|
|
|
tls_ctx->fields = 0;
|
|
|
|
|
ConfNode *field;
|
|
|
|
|
TAILQ_FOREACH(field, &custom->head, next)
|
|
|
|
|
{
|
|
|
|
@ -660,7 +608,8 @@ static OutputTlsCtx *OutputTlsInitCtx(ConfNode *conf)
|
|
|
|
|
|
|
|
|
|
const char *session_resumption = ConfNodeLookupChildValue(conf, "session-resumption");
|
|
|
|
|
if (session_resumption == NULL || ConfValIsTrue(session_resumption)) {
|
|
|
|
|
tls_ctx->flags |= LOG_TLS_SESSION_RESUMPTION;
|
|
|
|
|
tls_ctx->fields |= LOG_TLS_FIELD_SESSION_RESUMED;
|
|
|
|
|
tls_ctx->session_resumed = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) &&
|
|
|
|
|