output/tls: Allow logging of sv-handshake params

Ticket: 6695

"server_handshake" which logs the following:
1. TLS version used during handshake
2. The chosen cipher suite, excluding GREASE
3. TLS extensions, excluding GREASE
pull/13251/head
Richard McConnell 1 year ago committed by Victor Julien
parent 94c8be22d4
commit d81b76d852

@ -1056,6 +1056,8 @@ In addition to this, custom logging also allows the following fields:
* "client_handshake": structure containing "version", "ciphers" ([u16]), "exts" ([u16]), "sig_algs" ([u16]), * "client_handshake": structure containing "version", "ciphers" ([u16]), "exts" ([u16]), "sig_algs" ([u16]),
for client hello supported cipher suites, extensions, and signature algorithms, for client hello supported cipher suites, extensions, and signature algorithms,
respectively, in the order that they're mentioned (ie. unsorted) respectively, in the order that they're mentioned (ie. unsorted)
* "server_handshake": structure containing "version", "chosen cipher", "exts" ([u16]), for server hello
in the order that they're mentioned (ie. unsorted)
Examples Examples
~~~~~~~~ ~~~~~~~~

@ -7102,6 +7102,27 @@
} }
} }
}, },
"server_handshake": {
"type": "object",
"properties": {
"version": {
"description": "TLS version in server hello",
"type": "string"
},
"cipher": {
"description": "TLS server's chosen cipher",
"type": "integer"
},
"exts": {
"description": "TLS server extension(s)",
"type": "array",
"minItems": 1,
"items": {
"type": "integer"
}
}
}
},
"server_alpns": { "server_alpns": {
"description": "TLS server ALPN field(s)", "description": "TLS server ALPN field(s)",
"type": "array", "type": "array",

@ -146,6 +146,12 @@ impl HandshakeParams {
Ok(()) Ok(())
} }
fn log_first_cipher(&self, js: &mut JsonBuilder) -> Result<(), JsonError> {
let chosen = self.ciphersuites.first().map(|&v| *v).unwrap_or(0);
js.set_uint("cipher", chosen)?;
Ok(())
}
fn log_ciphers(&self, js: &mut JsonBuilder) -> Result<(), JsonError> { fn log_ciphers(&self, js: &mut JsonBuilder) -> Result<(), JsonError> {
if self.ciphersuites.is_empty() { if self.ciphersuites.is_empty() {
return Ok(()); return Ok(());
@ -242,6 +248,14 @@ pub unsafe extern "C" fn SCTLSHandshakeLogCiphers(hs: &HandshakeParams, js: *mut
return hs.log_ciphers(js.as_mut().unwrap()).is_ok() return hs.log_ciphers(js.as_mut().unwrap()).is_ok()
} }
#[no_mangle]
pub unsafe extern "C" fn SCTLSHandshakeLogFirstCipher(hs: &HandshakeParams, js: *mut JsonBuilder) -> bool {
if js.is_null() {
return false;
}
return hs.log_first_cipher(js.as_mut().unwrap()).is_ok()
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn SCTLSHandshakeLogExtensions(hs: &HandshakeParams, js: *mut JsonBuilder) -> bool { pub unsafe extern "C" fn SCTLSHandshakeLogExtensions(hs: &HandshakeParams, js: *mut JsonBuilder) -> bool {
if js.is_null() { if js.is_null() {

@ -664,7 +664,8 @@ static inline int TLSDecodeHSHelloVersion(SSLState *ssl_state,
uint16_t version = (uint16_t)(*input << 8) | *(input + 1); uint16_t version = (uint16_t)(*input << 8) | *(input + 1);
ssl_state->curr_connp->version = version; ssl_state->curr_connp->version = version;
if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { if (ssl_state->current_flags &
(SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_STATE_SERVER_HELLO)) {
SCTLSHandshakeSetTLSVersion(ssl_state->curr_connp->hs, version); SCTLSHandshakeSetTLSVersion(ssl_state->curr_connp->hs, version);
} }
@ -836,7 +837,8 @@ static inline int TLSDecodeHSHelloCipherSuites(SSLState *ssl_state,
input += 2; input += 2;
if (TLSDecodeValueIsGREASE(cipher_suite) != 1) { if (TLSDecodeValueIsGREASE(cipher_suite) != 1) {
if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { if (ssl_state->current_flags &
(SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_STATE_SERVER_HELLO)) {
SCTLSHandshakeAddCipher(ssl_state->curr_connp->hs, cipher_suite); SCTLSHandshakeAddCipher(ssl_state->curr_connp->hs, cipher_suite);
} }
if (enable_ja3) { if (enable_ja3) {
@ -1428,7 +1430,8 @@ static inline int TLSDecodeHSHelloExtensions(SSLState *ssl_state,
} }
} }
if (ssl_state->current_flags & SSL_AL_FLAG_STATE_CLIENT_HELLO) { if (ssl_state->current_flags &
(SSL_AL_FLAG_STATE_CLIENT_HELLO | SSL_AL_FLAG_STATE_SERVER_HELLO)) {
if (TLSDecodeValueIsGREASE(ext_type) != 1) { if (TLSDecodeValueIsGREASE(ext_type) != 1) {
SCTLSHandshakeAddExtension(ssl_state->curr_connp->hs, ext_type); SCTLSHandshakeAddExtension(ssl_state->curr_connp->hs, ext_type);
} }

@ -58,6 +58,7 @@
#define LOG_TLS_FIELD_CLIENT_ALPNS BIT_U64(18) #define LOG_TLS_FIELD_CLIENT_ALPNS BIT_U64(18)
#define LOG_TLS_FIELD_SERVER_ALPNS BIT_U64(19) #define LOG_TLS_FIELD_SERVER_ALPNS BIT_U64(19)
#define LOG_TLS_FIELD_CLIENT_HANDSHAKE BIT_U64(20) #define LOG_TLS_FIELD_CLIENT_HANDSHAKE BIT_U64(20)
#define LOG_TLS_FIELD_SERVER_HANDSHAKE BIT_U64(21)
typedef struct { typedef struct {
const char *name; const char *name;
@ -87,6 +88,7 @@ TlsFields tls_fields[] = {
{ "client_alpns", LOG_TLS_FIELD_CLIENT_ALPNS }, { "client_alpns", LOG_TLS_FIELD_CLIENT_ALPNS },
{ "server_alpns", LOG_TLS_FIELD_SERVER_ALPNS }, { "server_alpns", LOG_TLS_FIELD_SERVER_ALPNS },
{ "client_handshake", LOG_TLS_FIELD_CLIENT_HANDSHAKE }, { "client_handshake", LOG_TLS_FIELD_CLIENT_HANDSHAKE },
{ "server_handshake", LOG_TLS_FIELD_SERVER_HANDSHAKE },
{ NULL, -1 }, { NULL, -1 },
// clang-format on // clang-format on
}; };
@ -383,6 +385,25 @@ static void JsonTlsLogClientHandshake(SCJsonBuilder *js, SSLState *ssl_state)
SCJbClose(js); SCJbClose(js);
} }
static void JsonTlsLogServerHandshake(SCJsonBuilder *js, SSLState *ssl_state)
{
if (ssl_state->server_connp.hs == NULL) {
return;
}
if (SCTLSHandshakeIsEmpty(ssl_state->server_connp.hs)) {
return;
}
SCJbOpenObject(js, "server_handshake");
SCTLSHandshakeLogVersion(ssl_state->server_connp.hs, js);
SCTLSHandshakeLogFirstCipher(ssl_state->server_connp.hs, js);
SCTLSHandshakeLogExtensions(ssl_state->server_connp.hs, js);
SCJbClose(js);
}
static void JsonTlsLogFields(SCJsonBuilder *js, SSLState *ssl_state, uint64_t fields) static void JsonTlsLogFields(SCJsonBuilder *js, SSLState *ssl_state, uint64_t fields)
{ {
/* tls subject */ /* tls subject */
@ -458,6 +479,10 @@ static void JsonTlsLogFields(SCJsonBuilder *js, SSLState *ssl_state, uint64_t fi
if (fields & LOG_TLS_FIELD_CLIENT_HANDSHAKE) if (fields & LOG_TLS_FIELD_CLIENT_HANDSHAKE)
JsonTlsLogClientHandshake(js, ssl_state); JsonTlsLogClientHandshake(js, ssl_state);
/* tls server handshake parameters */
if (fields & LOG_TLS_FIELD_SERVER_HANDSHAKE)
JsonTlsLogServerHandshake(js, ssl_state);
if (fields & LOG_TLS_FIELD_CLIENT) { if (fields & LOG_TLS_FIELD_CLIENT) {
const bool log_cert = (fields & LOG_TLS_FIELD_CLIENT_CERT) != 0; const bool log_cert = (fields & LOG_TLS_FIELD_CLIENT_CERT) != 0;
const bool log_chain = (fields & LOG_TLS_FIELD_CLIENT_CHAIN) != 0; const bool log_chain = (fields & LOG_TLS_FIELD_CLIENT_CHAIN) != 0;

@ -288,7 +288,7 @@ outputs:
#session-resumption: no #session-resumption: no
# custom controls which TLS fields that are included in eve-log # custom controls which TLS fields that are included in eve-log
# WARNING: enabling custom disables extended logging. # WARNING: enabling custom disables extended logging.
#custom: [subject, issuer, session_resumed, serial, fingerprint, sni, version, not_before, not_after, certificate, chain, ja3, ja3s, ja4, subjectaltname, client, client_certificate, client_chain, client_alpns, server_alpns, client_handshake] #custom: [subject, issuer, session_resumed, serial, fingerprint, sni, version, not_before, not_after, certificate, chain, ja3, ja3s, ja4, subjectaltname, client, client_certificate, client_chain, client_alpns, server_alpns, client_handshake, server_handshake]
- files: - files:
force-magic: no # force logging magic on all logged files force-magic: no # force logging magic on all logged files
# force logging of checksums, available hash functions are md5, # force logging of checksums, available hash functions are md5,

Loading…
Cancel
Save