suricata
output-json-tls.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2024 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18/**
19 * \file
20 *
21 * \author Tom DeCanio <td@npulsetech.com>
22 *
23 * Implements TLS JSON logging portion of the engine.
24 */
25
26#include "suricata-common.h"
27
28#include "app-layer-parser.h"
29#include "app-layer-ssl.h"
30#include "app-layer.h"
31#include "conf.h"
32#include "output-json-tls.h"
33#include "output-json.h"
34#include "output.h"
35#include "threadvars.h"
36#include "util-debug.h"
37#include "util-ja3.h"
38#include "util-time.h"
39
40#define LOG_TLS_FIELD_VERSION BIT_U64(0)
41#define LOG_TLS_FIELD_SUBJECT BIT_U64(1)
42#define LOG_TLS_FIELD_ISSUER BIT_U64(2)
43#define LOG_TLS_FIELD_SERIAL BIT_U64(3)
44#define LOG_TLS_FIELD_FINGERPRINT BIT_U64(4)
45#define LOG_TLS_FIELD_NOTBEFORE BIT_U64(5)
46#define LOG_TLS_FIELD_NOTAFTER BIT_U64(6)
47#define LOG_TLS_FIELD_SNI BIT_U64(7)
48#define LOG_TLS_FIELD_CERTIFICATE BIT_U64(8)
49#define LOG_TLS_FIELD_CHAIN BIT_U64(9)
50#define LOG_TLS_FIELD_SESSION_RESUMED BIT_U64(10)
51#define LOG_TLS_FIELD_JA3 BIT_U64(11)
52#define LOG_TLS_FIELD_JA3S BIT_U64(12)
53#define LOG_TLS_FIELD_CLIENT BIT_U64(13) /**< client fields (issuer, subject, etc) */
54#define LOG_TLS_FIELD_CLIENT_CERT BIT_U64(14)
55#define LOG_TLS_FIELD_CLIENT_CHAIN BIT_U64(15)
56#define LOG_TLS_FIELD_JA4 BIT_U64(16)
57#define LOG_TLS_FIELD_SUBJECTALTNAME BIT_U64(17)
58#define LOG_TLS_FIELD_CLIENT_ALPNS BIT_U64(18)
59#define LOG_TLS_FIELD_SERVER_ALPNS BIT_U64(19)
60#define LOG_TLS_FIELD_CLIENT_HANDSHAKE BIT_U64(20)
61#define LOG_TLS_FIELD_SERVER_HANDSHAKE BIT_U64(21)
62
63typedef struct {
64 const char *name;
65 uint64_t flag;
66} TlsFields;
67
69 // clang-format off
70 { "version", LOG_TLS_FIELD_VERSION },
71 { "subject", LOG_TLS_FIELD_SUBJECT },
72 { "issuer", LOG_TLS_FIELD_ISSUER },
73 { "serial", LOG_TLS_FIELD_SERIAL },
74 { "fingerprint", LOG_TLS_FIELD_FINGERPRINT },
75 { "not_before", LOG_TLS_FIELD_NOTBEFORE },
76 { "not_after", LOG_TLS_FIELD_NOTAFTER },
77 { "sni", LOG_TLS_FIELD_SNI },
78 { "certificate", LOG_TLS_FIELD_CERTIFICATE },
79 { "chain", LOG_TLS_FIELD_CHAIN },
80 { "session_resumed", LOG_TLS_FIELD_SESSION_RESUMED },
81 { "ja3", LOG_TLS_FIELD_JA3 },
82 { "ja3s", LOG_TLS_FIELD_JA3S },
83 { "client", LOG_TLS_FIELD_CLIENT },
84 { "client_certificate", LOG_TLS_FIELD_CLIENT_CERT },
85 { "client_chain", LOG_TLS_FIELD_CLIENT_CHAIN },
86 // accept if as nop if we do not HAVE_JA4
87 { "ja4", LOG_TLS_FIELD_JA4 },
88 { "subjectaltname", LOG_TLS_FIELD_SUBJECTALTNAME },
89 { "client_alpns", LOG_TLS_FIELD_CLIENT_ALPNS },
90 { "server_alpns", LOG_TLS_FIELD_SERVER_ALPNS },
91 { "client_handshake", LOG_TLS_FIELD_CLIENT_HANDSHAKE },
92 { "server_handshake", LOG_TLS_FIELD_SERVER_HANDSHAKE },
93 { NULL, -1 },
94 // clang-format on
95};
96
97// clang-format off
98#define BASIC_FIELDS \
99 (LOG_TLS_FIELD_SUBJECT | \
100 LOG_TLS_FIELD_ISSUER | \
101 LOG_TLS_FIELD_SUBJECTALTNAME)
102// clang-format on
103
104// clang-format off
105#define EXTENDED_FIELDS \
106 (BASIC_FIELDS | \
107 LOG_TLS_FIELD_VERSION | \
108 LOG_TLS_FIELD_SERIAL | \
109 LOG_TLS_FIELD_FINGERPRINT | \
110 LOG_TLS_FIELD_NOTBEFORE | \
111 LOG_TLS_FIELD_NOTAFTER | \
112 LOG_TLS_FIELD_JA3 | \
113 LOG_TLS_FIELD_JA3S | \
114 LOG_TLS_FIELD_JA4 | \
115 LOG_TLS_FIELD_CLIENT | \
116 LOG_TLS_FIELD_CLIENT_ALPNS | \
117 LOG_TLS_FIELD_SERVER_ALPNS | \
118 LOG_TLS_FIELD_SNI)
119// clang-format on
120
121typedef struct OutputTlsCtx_ {
122 uint64_t fields; /** Store fields */
126
131
132static void JsonTlsLogSubject(SCJsonBuilder *js, SSLState *ssl_state)
133{
134 if (ssl_state->server_connp.cert0_subject) {
135 SCJbSetString(js, "subject", ssl_state->server_connp.cert0_subject);
136 }
137}
138
139static void JsonTlsLogIssuer(SCJsonBuilder *js, SSLState *ssl_state)
140{
141 if (ssl_state->server_connp.cert0_issuerdn) {
142 SCJbSetString(js, "issuerdn", ssl_state->server_connp.cert0_issuerdn);
143 }
144}
145
146static void JsonTlsLogSAN(SCJsonBuilder *js, SSLState *ssl_state)
147{
148 if (ssl_state->server_connp.cert0_sans_len > 0) {
149 SCJbOpenArray(js, "subjectaltname");
150 for (uint16_t i = 0; i < ssl_state->server_connp.cert0_sans_len; i++) {
151 SCJbAppendString(js, ssl_state->server_connp.cert0_sans[i]);
152 }
153 SCJbClose(js);
154 }
155}
156
157static void JsonTlsLogSessionResumed(SCJsonBuilder *js, SSLState *ssl_state)
158{
159 if (ssl_state->flags & SSL_AL_FLAG_SESSION_RESUMED) {
160 /* Only log a session as 'resumed' if a certificate has not
161 been seen, and the session is not TLSv1.3 or later. */
162 if ((ssl_state->server_connp.cert0_issuerdn == NULL &&
163 ssl_state->server_connp.cert0_subject == NULL) &&
164 (ssl_state->flags & SSL_AL_FLAG_STATE_SERVER_HELLO) &&
165 ((ssl_state->flags & SSL_AL_FLAG_LOG_WITHOUT_CERT) == 0)) {
166 SCJbSetBool(js, "session_resumed", true);
167 }
168 }
169}
170
171static void JsonTlsLogFingerprint(SCJsonBuilder *js, SSLState *ssl_state)
172{
173 if (ssl_state->server_connp.cert0_fingerprint) {
174 SCJbSetString(js, "fingerprint", ssl_state->server_connp.cert0_fingerprint);
175 }
176}
177
178static void JsonTlsLogSni(SCJsonBuilder *js, SSLState *ssl_state)
179{
180 if (ssl_state->client_connp.sni) {
181 SCJbSetString(js, "sni", ssl_state->client_connp.sni);
182 }
183}
184
185static void JsonTlsLogSerial(SCJsonBuilder *js, SSLState *ssl_state)
186{
187 if (ssl_state->server_connp.cert0_serial) {
188 SCJbSetString(js, "serial", ssl_state->server_connp.cert0_serial);
189 }
190}
191
192static void JsonTlsLogVersion(SCJsonBuilder *js, SSLState *ssl_state)
193{
194 char ssl_version[SSL_VERSION_MAX_STRLEN];
195 SSLVersionToString(ssl_state->server_connp.version, ssl_version);
196 SCJbSetString(js, "version", ssl_version);
197}
198
199static void JsonTlsLogNotBefore(SCJsonBuilder *js, SSLState *ssl_state)
200{
201 if (ssl_state->server_connp.cert0_not_before != 0) {
202 sc_x509_log_timestamp(js, "notbefore", ssl_state->server_connp.cert0_not_before);
203 }
204}
205
206static void JsonTlsLogNotAfter(SCJsonBuilder *js, SSLState *ssl_state)
207{
208 if (ssl_state->server_connp.cert0_not_after != 0) {
209 sc_x509_log_timestamp(js, "notafter", ssl_state->server_connp.cert0_not_after);
210 }
211}
212
213static void JsonTlsLogJa3Hash(SCJsonBuilder *js, SSLState *ssl_state)
214{
215 if (ssl_state->client_connp.ja3_hash != NULL) {
216 SCJbSetString(js, "hash", ssl_state->client_connp.ja3_hash);
217 }
218}
219
220static void JsonTlsLogJa3String(SCJsonBuilder *js, SSLState *ssl_state)
221{
222 if ((ssl_state->client_connp.ja3_str != NULL) &&
223 ssl_state->client_connp.ja3_str->data != NULL) {
224 SCJbSetString(js, "string", ssl_state->client_connp.ja3_str->data);
225 }
226}
227
228static void JsonTlsLogJa3(SCJsonBuilder *js, SSLState *ssl_state)
229{
230 if ((ssl_state->client_connp.ja3_hash != NULL) ||
231 ((ssl_state->client_connp.ja3_str != NULL) &&
232 ssl_state->client_connp.ja3_str->data != NULL)) {
233 SCJbOpenObject(js, "ja3");
234
235 JsonTlsLogJa3Hash(js, ssl_state);
236 JsonTlsLogJa3String(js, ssl_state);
237
238 SCJbClose(js);
239 }
240}
241
242static void JsonTlsLogSCJA4(SCJsonBuilder *js, SSLState *ssl_state)
243{
244#ifdef HAVE_JA4
245 if (ssl_state->client_connp.hs != NULL) {
246 uint8_t buffer[JA4_HEX_LEN];
247 /* JA4 hash has 36 characters */
248 SCJA4GetHash(ssl_state->client_connp.hs, (uint8_t(*)[JA4_HEX_LEN])buffer);
249 SCJbSetStringFromBytes(js, "ja4", buffer, JA4_HEX_LEN);
250 }
251#endif
252}
253
254static void JsonTlsLogJa3SHash(SCJsonBuilder *js, SSLState *ssl_state)
255{
256 if (ssl_state->server_connp.ja3_hash != NULL) {
257 SCJbSetString(js, "hash", ssl_state->server_connp.ja3_hash);
258 }
259}
260
261static void JsonTlsLogJa3SString(SCJsonBuilder *js, SSLState *ssl_state)
262{
263 if ((ssl_state->server_connp.ja3_str != NULL) &&
264 ssl_state->server_connp.ja3_str->data != NULL) {
265 SCJbSetString(js, "string", ssl_state->server_connp.ja3_str->data);
266 }
267}
268
269static void JsonTlsLogJa3S(SCJsonBuilder *js, SSLState *ssl_state)
270{
271 if ((ssl_state->server_connp.ja3_hash != NULL) ||
272 ((ssl_state->server_connp.ja3_str != NULL) &&
273 ssl_state->server_connp.ja3_str->data != NULL)) {
274 SCJbOpenObject(js, "ja3s");
275
276 JsonTlsLogJa3SHash(js, ssl_state);
277 JsonTlsLogJa3SString(js, ssl_state);
278
279 SCJbClose(js);
280 }
281}
282
283static void JsonTlsLogAlpns(SCJsonBuilder *js, SSLStateConnp *connp, const char *object)
284{
285 if (connp->hs == NULL) {
286 return;
287 }
288
289 if (SCTLSHandshakeIsEmpty(connp->hs)) {
290 return;
291 }
292 SCTLSHandshakeLogALPNs(connp->hs, js, object);
293}
294
295static void JsonTlsLogCertificate(SCJsonBuilder *js, SSLStateConnp *connp)
296{
297 if (TAILQ_EMPTY(&connp->certs)) {
298 return;
299 }
300
301 SSLCertsChain *cert = TAILQ_FIRST(&connp->certs);
302 if (cert == NULL) {
303 return;
304 }
305
306 SCJbSetBase64(js, "certificate", cert->cert_data, cert->cert_len);
307}
308
309static void JsonTlsLogChain(SCJsonBuilder *js, SSLStateConnp *connp)
310{
311 if (TAILQ_EMPTY(&connp->certs)) {
312 return;
313 }
314
315 SCJbOpenArray(js, "chain");
316
317 SSLCertsChain *cert;
318 TAILQ_FOREACH (cert, &connp->certs, next) {
319 SCJbAppendBase64(js, cert->cert_data, cert->cert_len);
320 }
321
322 SCJbClose(js);
323}
324
325static bool HasClientCert(SSLStateConnp *connp)
326{
327 if (connp->cert0_subject || connp->cert0_issuerdn)
328 return true;
329 return false;
330}
331
332static void JsonTlsLogClientCert(
333 SCJsonBuilder *js, SSLStateConnp *connp, const bool log_cert, const bool log_chain)
334{
335 if (connp->cert0_subject != NULL) {
336 SCJbSetString(js, "subject", connp->cert0_subject);
337 }
338 if (connp->cert0_issuerdn != NULL) {
339 SCJbSetString(js, "issuerdn", connp->cert0_issuerdn);
340 }
341 if (connp->cert0_fingerprint) {
342 SCJbSetString(js, "fingerprint", connp->cert0_fingerprint);
343 }
344 if (connp->cert0_serial) {
345 SCJbSetString(js, "serial", connp->cert0_serial);
346 }
347 if (connp->cert0_not_before != 0) {
348 char timebuf[64];
350 CreateUtcIsoTimeString(ts, timebuf, sizeof(timebuf));
351 SCJbSetString(js, "notbefore", timebuf);
352 }
353 if (connp->cert0_not_after != 0) {
354 char timebuf[64];
356 CreateUtcIsoTimeString(ts, timebuf, sizeof(timebuf));
357 SCJbSetString(js, "notafter", timebuf);
358 }
359
360 if (log_cert) {
361 JsonTlsLogCertificate(js, connp);
362 }
363 if (log_chain) {
364 JsonTlsLogChain(js, connp);
365 }
366}
367
368static void JsonTlsLogClientHandshake(SCJsonBuilder *js, SSLState *ssl_state)
369{
370 if (ssl_state->client_connp.hs == NULL) {
371 return;
372 }
373
374 // Don't write an empty handshake
375 if (SCTLSHandshakeIsEmpty(ssl_state->client_connp.hs)) {
376 return;
377 }
378
379 SCJbOpenObject(js, "client_handshake");
380
381 SCTLSHandshakeLogVersion(ssl_state->client_connp.hs, js);
382 SCTLSHandshakeLogCiphers(ssl_state->client_connp.hs, js);
383 SCTLSHandshakeLogExtensions(ssl_state->client_connp.hs, js);
384 SCTLSHandshakeLogSigAlgs(ssl_state->client_connp.hs, js);
385
386 SCJbClose(js);
387}
388
389static void JsonTlsLogServerHandshake(SCJsonBuilder *js, SSLState *ssl_state)
390{
391 if (ssl_state->server_connp.hs == NULL) {
392 return;
393 }
394
395 if (SCTLSHandshakeIsEmpty(ssl_state->server_connp.hs)) {
396 return;
397 }
398
399 SCJbOpenObject(js, "server_handshake");
400
401 SCTLSHandshakeLogVersion(ssl_state->server_connp.hs, js);
402 SCTLSHandshakeLogFirstCipher(ssl_state->server_connp.hs, js);
403 SCTLSHandshakeLogExtensions(ssl_state->server_connp.hs, js);
404
405 SCJbClose(js);
406}
407
408static void JsonTlsLogFields(SCJsonBuilder *js, SSLState *ssl_state, uint64_t fields)
409{
410 /* tls subject */
411 if (fields & LOG_TLS_FIELD_SUBJECT)
412 JsonTlsLogSubject(js, ssl_state);
413
414 /* tls issuerdn */
415 if (fields & LOG_TLS_FIELD_ISSUER)
416 JsonTlsLogIssuer(js, ssl_state);
417
418 /* tls subjectaltname */
419 if (fields & LOG_TLS_FIELD_SUBJECTALTNAME)
420 JsonTlsLogSAN(js, ssl_state);
421
422 /* tls session resumption */
424 JsonTlsLogSessionResumed(js, ssl_state);
425
426 /* tls serial */
427 if (fields & LOG_TLS_FIELD_SERIAL)
428 JsonTlsLogSerial(js, ssl_state);
429
430 /* tls fingerprint */
431 if (fields & LOG_TLS_FIELD_FINGERPRINT)
432 JsonTlsLogFingerprint(js, ssl_state);
433
434 /* tls sni */
435 if (fields & LOG_TLS_FIELD_SNI)
436 JsonTlsLogSni(js, ssl_state);
437
438 /* tls version */
439 if (fields & LOG_TLS_FIELD_VERSION) {
440 JsonTlsLogVersion(js, ssl_state);
441 }
442
443 /* tls notbefore */
444 if (fields & LOG_TLS_FIELD_NOTBEFORE)
445 JsonTlsLogNotBefore(js, ssl_state);
446
447 /* tls notafter */
448 if (fields & LOG_TLS_FIELD_NOTAFTER)
449 JsonTlsLogNotAfter(js, ssl_state);
450
451 /* tls certificate */
452 if (fields & LOG_TLS_FIELD_CERTIFICATE)
453 JsonTlsLogCertificate(js, &ssl_state->server_connp);
454
455 /* tls chain */
456 if (fields & LOG_TLS_FIELD_CHAIN)
457 JsonTlsLogChain(js, &ssl_state->server_connp);
458
459 /* tls ja3_hash */
460 if (fields & LOG_TLS_FIELD_JA3)
461 JsonTlsLogJa3(js, ssl_state);
462
463 /* tls ja3s */
464 if (fields & LOG_TLS_FIELD_JA3S)
465 JsonTlsLogJa3S(js, ssl_state);
466
467 /* tls ja4 */
468 if (fields & LOG_TLS_FIELD_JA4)
469 JsonTlsLogSCJA4(js, ssl_state);
470
471 if (fields & LOG_TLS_FIELD_CLIENT_ALPNS) {
472 JsonTlsLogAlpns(js, &ssl_state->client_connp, "client_alpns");
473 }
474
475 if (fields & LOG_TLS_FIELD_SERVER_ALPNS) {
476 JsonTlsLogAlpns(js, &ssl_state->server_connp, "server_alpns");
477 }
478
479 /* tls client handshake parameters */
481 JsonTlsLogClientHandshake(js, ssl_state);
482
483 /* tls server handshake parameters */
485 JsonTlsLogServerHandshake(js, ssl_state);
486
487 if (fields & LOG_TLS_FIELD_CLIENT) {
488 const bool log_cert = (fields & LOG_TLS_FIELD_CLIENT_CERT) != 0;
489 const bool log_chain = (fields & LOG_TLS_FIELD_CLIENT_CHAIN) != 0;
490 if (HasClientCert(&ssl_state->client_connp)) {
491 SCJbOpenObject(js, "client");
492 JsonTlsLogClientCert(js, &ssl_state->client_connp, log_cert, log_chain);
493 SCJbClose(js);
494 }
495 }
496}
497
498bool JsonTlsLogJSONExtended(void *vtx, SCJsonBuilder *tjs)
499{
500 SSLState *state = (SSLState *)vtx;
501 SCJbOpenObject(tjs, "tls");
502 JsonTlsLogFields(tjs, state, EXTENDED_FIELDS);
503 return SCJbClose(tjs);
504}
505
506static int JsonTlsLogger(ThreadVars *tv, void *thread_data, const Packet *p,
507 Flow *f, void *state, void *txptr, uint64_t tx_id)
508{
509 JsonTlsLogThread *aft = (JsonTlsLogThread *)thread_data;
510 OutputTlsCtx *tls_ctx = aft->tlslog_ctx;
511
512 SSLState *ssl_state = (SSLState *)state;
513 if (unlikely(ssl_state == NULL)) {
514 return 0;
515 }
516
517 if ((ssl_state->server_connp.cert0_issuerdn == NULL ||
518 ssl_state->server_connp.cert0_subject == NULL) &&
519 ((ssl_state->flags & SSL_AL_FLAG_SESSION_RESUMED) == 0 ||
520 (!tls_ctx->session_resumed)) &&
521 ((ssl_state->flags & SSL_AL_FLAG_LOG_WITHOUT_CERT) == 0)) {
522 return 0;
523 }
524
525 SCJsonBuilder *js = CreateEveHeader(p, LOG_DIR_FLOW, "tls", NULL, aft->tlslog_ctx->eve_ctx);
526 if (unlikely(js == NULL)) {
527 return 0;
528 }
529
530 SCJbOpenObject(js, "tls");
531
532 JsonTlsLogFields(js, ssl_state, tls_ctx->fields);
533
534 /* print original application level protocol when it have been changed
535 because of STARTTLS, HTTP CONNECT, or similar. */
536 if (f->alproto_orig != ALPROTO_UNKNOWN) {
537 SCJbSetString(js, "from_proto", AppLayerGetProtoName(f->alproto_orig));
538 }
539
540 /* Close the tls object. */
541 SCJbClose(js);
542
543 OutputJsonBuilderBuffer(tv, p, p->flow, js, aft->ctx);
544 SCJbFree(js);
545
546 return 0;
547}
548
549static TmEcode JsonTlsLogThreadInit(ThreadVars *t, const void *initdata, void **data)
550{
551 JsonTlsLogThread *aft = SCCalloc(1, sizeof(JsonTlsLogThread));
552 if (unlikely(aft == NULL)) {
553 return TM_ECODE_FAILED;
554 }
555
556 if (initdata == NULL) {
557 SCLogDebug("Error getting context for eve-log tls 'initdata' argument NULL");
558 goto error_exit;
559 }
560
561 /* use the Output Context (file pointer and mutex) */
562 aft->tlslog_ctx = ((OutputCtx *)initdata)->data;
563
564 aft->ctx = CreateEveThreadCtx(t, aft->tlslog_ctx->eve_ctx);
565 if (!aft->ctx) {
566 goto error_exit;
567 }
568 *data = (void *)aft;
569 return TM_ECODE_OK;
570
571error_exit:
572 SCFree(aft);
573 return TM_ECODE_FAILED;
574}
575
576static TmEcode JsonTlsLogThreadDeinit(ThreadVars *t, void *data)
577{
578 JsonTlsLogThread *aft = (JsonTlsLogThread *)data;
579 if (aft == NULL) {
580 return TM_ECODE_OK;
581 }
582
583 FreeEveThreadCtx(aft->ctx);
584
585 /* clear memory */
586 memset(aft, 0, sizeof(JsonTlsLogThread));
587
588 SCFree(aft);
589 return TM_ECODE_OK;
590}
591
592static OutputTlsCtx *OutputTlsInitCtx(SCConfNode *conf)
593{
594 OutputTlsCtx *tls_ctx = SCCalloc(1, sizeof(OutputTlsCtx));
595 if (unlikely(tls_ctx == NULL))
596 return NULL;
597
598 tls_ctx->fields = BASIC_FIELDS;
599 tls_ctx->session_resumed = false;
600
601 if (conf == NULL)
602 return tls_ctx;
603
604 const char *extended = SCConfNodeLookupChildValue(conf, "extended");
605 if (extended) {
606 if (SCConfValIsTrue(extended)) {
607 tls_ctx->fields = EXTENDED_FIELDS;
608 }
609 }
610
611 SCConfNode *custom = SCConfNodeLookupChild(conf, "custom");
612 if (custom) {
613 tls_ctx->fields = 0;
614 SCConfNode *field;
615 TAILQ_FOREACH(field, &custom->head, next)
616 {
617 bool valid = false;
618 TlsFields *valid_fields = tls_fields;
619 for ( ; valid_fields->name != NULL; valid_fields++) {
620 if (strcasecmp(field->val, valid_fields->name) == 0) {
621 tls_ctx->fields |= valid_fields->flag;
622 SCLogDebug("enabled %s", field->val);
623 valid = true;
624 break;
625 }
626 }
627 if (!valid) {
628 SCLogWarning("eve.tls: unknown 'custom' field '%s'", field->val);
629 }
630 }
631 }
632
633 const char *session_resumption = SCConfNodeLookupChildValue(conf, "session-resumption");
634 if (session_resumption == NULL || SCConfValIsTrue(session_resumption)) {
636 tls_ctx->session_resumed = true;
637 }
638
639 if ((tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) &&
640 (tls_ctx->fields & LOG_TLS_FIELD_CHAIN)) {
641 SCLogWarning("Both 'certificate' and 'chain' contains the top "
642 "certificate, so only one of them should be enabled "
643 "at a time");
644 }
645 if ((tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CERT) &&
646 (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CHAIN)) {
647 SCLogWarning("Both 'client_certificate' and 'client_chain' contains the top "
648 "certificate, so only one of them should be enabled "
649 "at a time");
650 }
651
652 if ((tls_ctx->fields & LOG_TLS_FIELD_CLIENT) == 0) {
653 if (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CERT) {
654 SCLogConfig("enabling \"client\" as a dependency of \"client_certificate\"");
655 tls_ctx->fields |= LOG_TLS_FIELD_CLIENT;
656 }
657 if (tls_ctx->fields & LOG_TLS_FIELD_CLIENT_CHAIN) {
658 SCLogConfig("enabling \"client\" as a dependency of \"client_chain\"");
659 tls_ctx->fields |= LOG_TLS_FIELD_CLIENT;
660 }
661 }
662
663 return tls_ctx;
664}
665
666static void OutputTlsLogDeinitSub(OutputCtx *output_ctx)
667{
668 OutputTlsCtx *tls_ctx = output_ctx->data;
669 SCFree(tls_ctx);
670 SCFree(output_ctx);
671}
672
673static OutputInitResult OutputTlsLogInitSub(SCConfNode *conf, OutputCtx *parent_ctx)
674{
675 OutputInitResult result = { NULL, false };
676 OutputJsonCtx *ojc = parent_ctx->data;
677
678 OutputTlsCtx *tls_ctx = OutputTlsInitCtx(conf);
679 if (unlikely(tls_ctx == NULL))
680 return result;
681
682 OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
683 if (unlikely(output_ctx == NULL)) {
684 SCFree(tls_ctx);
685 return result;
686 }
687
688 tls_ctx->eve_ctx = ojc;
689
690 if ((tls_ctx->fields & LOG_TLS_FIELD_CERTIFICATE) &&
691 (tls_ctx->fields & LOG_TLS_FIELD_CHAIN)) {
692 SCLogWarning("Both 'certificate' and 'chain' contains the top "
693 "certificate, so only one of them should be enabled "
694 "at a time");
695 }
696
697 output_ctx->data = tls_ctx;
698 output_ctx->DeInit = OutputTlsLogDeinitSub;
699
701
702 result.ctx = output_ctx;
703 result.ok = true;
704 return result;
705}
706
708{
709 /* register as child of eve-log */
710 OutputRegisterTxSubModuleWithProgress(LOGGER_JSON_TX, "eve-log", "JsonTlsLog", "eve-log.tls",
711 OutputTlsLogInitSub, ALPROTO_TLS, JsonTlsLogger, TLS_STATE_SERVER_HANDSHAKE_DONE,
712 TLS_STATE_CLIENT_HANDSHAKE_DONE, JsonTlsLogThreadInit, JsonTlsLogThreadDeinit);
713}
struct HtpBodyChunk_ * next
void SCAppLayerParserRegisterLogger(uint8_t ipproto, AppProto alproto)
@ ALPROTO_TLS
@ ALPROTO_UNKNOWN
#define SSL_AL_FLAG_STATE_SERVER_HELLO
#define SSL_AL_FLAG_LOG_WITHOUT_CERT
#define SSL_AL_FLAG_SESSION_RESUMED
@ TLS_STATE_CLIENT_HANDSHAKE_DONE
@ TLS_STATE_SERVER_HANDSHAKE_DONE
const char * AppLayerGetProtoName(AppProto alproto)
Given the internal protocol id, returns a string representation of the protocol.
Definition app-layer.c:1009
SCConfNode * SCConfNodeLookupChild(const SCConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition conf.c:796
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition conf.c:551
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition conf.c:824
ThreadVars * tv
@ LOG_DIR_FLOW
OutputJsonThreadCtx * CreateEveThreadCtx(ThreadVars *t, OutputJsonCtx *ctx)
void FreeEveThreadCtx(OutputJsonThreadCtx *ctx)
#define LOG_TLS_FIELD_SERVER_ALPNS
#define LOG_TLS_FIELD_JA4
#define LOG_TLS_FIELD_CLIENT_ALPNS
#define EXTENDED_FIELDS
#define LOG_TLS_FIELD_SUBJECTALTNAME
struct JsonTlsLogThread_ JsonTlsLogThread
#define LOG_TLS_FIELD_JA3S
#define LOG_TLS_FIELD_CLIENT_CERT
#define LOG_TLS_FIELD_SERIAL
#define LOG_TLS_FIELD_SNI
#define LOG_TLS_FIELD_SERVER_HANDSHAKE
#define LOG_TLS_FIELD_SESSION_RESUMED
#define LOG_TLS_FIELD_VERSION
#define BASIC_FIELDS
#define LOG_TLS_FIELD_CHAIN
#define LOG_TLS_FIELD_NOTBEFORE
#define LOG_TLS_FIELD_SUBJECT
#define LOG_TLS_FIELD_CLIENT_HANDSHAKE
TlsFields tls_fields[]
struct OutputTlsCtx_ OutputTlsCtx
#define LOG_TLS_FIELD_ISSUER
#define LOG_TLS_FIELD_CERTIFICATE
#define LOG_TLS_FIELD_CLIENT_CHAIN
#define LOG_TLS_FIELD_CLIENT
#define LOG_TLS_FIELD_JA3
void JsonTlsLogRegister(void)
#define LOG_TLS_FIELD_FINGERPRINT
bool JsonTlsLogJSONExtended(void *vtx, SCJsonBuilder *tjs)
#define LOG_TLS_FIELD_NOTAFTER
SCJsonBuilder * CreateEveHeader(const Packet *p, enum SCOutputJsonLogDirection dir, const char *event_type, JsonAddrInfo *addr, OutputJsonCtx *eve_ctx)
void OutputJsonBuilderBuffer(ThreadVars *tv, const Packet *p, Flow *f, SCJsonBuilder *js, OutputJsonThreadCtx *ctx)
void OutputRegisterTxSubModuleWithProgress(LoggerId id, const char *parent_name, const char *name, const char *conf_name, OutputInitSubFunc InitFunc, AppProto alproto, TxLogger TxLogFunc, int tc_log_progress, int ts_log_progress, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit)
Definition output.c:381
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:252
#define TAILQ_FIRST(head)
Definition queue.h:250
#define TAILQ_EMPTY(head)
Definition queue.h:248
uint64_t ts
Flow data structure.
Definition flow.h:356
AppProto alproto_orig
Definition flow.h:456
char * data
Definition util-ja3.h:32
OutputTlsCtx * tlslog_ctx
OutputJsonThreadCtx * ctx
void * data
Definition tm-modules.h:91
void(* DeInit)(struct OutputCtx_ *)
Definition tm-modules.h:94
OutputCtx * ctx
Definition output.h:47
OutputJsonCtx * eve_ctx
struct Flow_ * flow
Definition decode.h:546
char * val
Definition conf.h:39
uint8_t * cert_data
char * cert0_fingerprint
uint16_t cert0_sans_len
int64_t cert0_not_after
JA3Buffer * ja3_str
int64_t cert0_not_before
HandshakeParams * hs
SSLv[2.0|3.[0|1|2|3]] state structure.
SSLStateConnp server_connp
SSLStateConnp client_connp
uint32_t flags
Per thread variable structure.
Definition threadvars.h:58
const char * name
uint64_t flag
@ LOGGER_JSON_TX
@ TM_ECODE_FAILED
@ TM_ECODE_OK
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition util-debug.h:255
#define SCLogConfig(...)
Definition util-debug.h:229
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define unlikely(expr)
void CreateUtcIsoTimeString(const SCTime_t ts, char *str, size_t size)
Definition util-time.c:230
#define SCTIME_FROM_SECS(s)
Definition util-time.h:69