SSL Analyzer: track connection direction by messages

This PR changes the way in which the SSL analyzer tracks the direction
of connections. So far, the SSL analyzer assumed that the originator of
a connection would send the client hello (and other associated
client-side events), and that the responder would be the SSL servers.

In some circumstances this is not true, and the initiator of a
connection is the server, with the responder being the client. So far
this confused some of the internal statekeeping logic and could lead to
mis-parsing of extensions.

This reversal of roles can happen in DTLS, if a connection uses STUN -
and potentially in some StartTLS protocols.

This PR tracks the direction of a TLS connection using the hello
request, client hello and server hello handshake messages. Furthermore,
it changes the SSL events from providing is_orig to providing is_client,
where is_client is true for the client_side of a connection. Since the
argument positioning in the event has not changed, old scripts will
continue to work seamlessly - the new semantics are what everyone
writing SSL scripts will have expected in any case.

There is a new event that is raised when a connection is flipped. A
weird is raised if a flip happens repeatedly.

Addresses GH-2198.
This commit is contained in:
Johanna Amann 2022-06-24 19:27:13 +02:00 committed by Johanna Amann
parent a7aa345c76
commit e14eddeb97
30 changed files with 344 additions and 179 deletions

View file

@ -2,6 +2,7 @@
# @TEST-EXEC: btest-diff ssl.log
# @TEST-EXEC: touch dpd.log
# @TEST-EXEC: btest-diff dpd.log
# @TEST-EXEC: btest-diff .stdout
@load base/protocols/ssl
@load base/frameworks/dpd
@ -14,3 +15,7 @@ event ssl_client_hello(c: connection, version: count, record_version: count, pos
print version, client_random, session_id, ciphers;
}
event ssl_extension(c: connection, is_client: bool, code: count, val: string)
{
print is_client, code;
}

View file

@ -12,22 +12,22 @@ event ssl_established(c: connection)
print "Established", c$id$orig_h, c$id$resp_h;
}
event ssl_handshake_message(c: connection, is_orig: bool, msg_type: count, length: count)
event ssl_handshake_message(c: connection, is_client: bool, msg_type: count, length: count)
{
print "Handshake", c$id$orig_h, c$id$resp_h, is_orig, msg_type, length;
print "Handshake", c$id$orig_h, c$id$resp_h, is_client, msg_type, length;
}
event ssl_change_cipher_spec(c: connection, is_orig: bool)
event ssl_change_cipher_spec(c: connection, is_client: bool)
{
print "CCS", c$id$orig_h, c$id$resp_h, is_orig;
print "CCS", c$id$orig_h, c$id$resp_h, is_client;
}
event ssl_plaintext_data(c: connection, is_orig: bool, record_version: count, content_type: count, length: count)
event ssl_plaintext_data(c: connection, is_client: bool, record_version: count, content_type: count, length: count)
{
print "Plaintext data", c$id$orig_h, c$id$resp_h, is_orig, SSL::version_strings[record_version], content_type, length;
print "Plaintext data", c$id$orig_h, c$id$resp_h, is_client, SSL::version_strings[record_version], content_type, length;
}
event ssl_encrypted_data(c: connection, is_orig: bool, record_version: count, content_type: count, length: count)
event ssl_encrypted_data(c: connection, is_client: bool, record_version: count, content_type: count, length: count)
{
print "Encrypted data", c$id$orig_h, c$id$resp_h, is_orig, SSL::version_strings[record_version], content_type, length;
print "Encrypted data", c$id$orig_h, c$id$resp_h, is_client, SSL::version_strings[record_version], content_type, length;
}

View file

@ -7,12 +7,12 @@ redef SSL::root_certs += {
["OU=Class 3 Public Primary Certification Authority,O=VeriSign\, Inc.,C=US"] = "\x30\x82\x02\x3C\x30\x82\x01\xA5\x02\x10\x70\xBA\xE4\x1D\x10\xD9\x29\x34\xB6\x38\xCA\x7B\x03\xCC\xBA\xBF\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x02\x05\x00\x30\x5F\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x17\x30\x15\x06\x03\x55\x04\x0A\x13\x0E\x56\x65\x72\x69\x53\x69\x67\x6E\x2C\x20\x49\x6E\x63\x2E\x31\x37\x30\x35\x06\x03\x55\x04\x0B\x13\x2E\x43\x6C\x61\x73\x73\x20\x33\x20\x50\x75\x62\x6C\x69\x63\x20\x50\x72\x69\x6D\x61\x72\x79\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x1E\x17\x0D\x39\x36\x30\x31\x32\x39\x30\x30\x30\x30\x30\x30\x5A\x17\x0D\x32\x38\x30\x38\x30\x31\x32\x33\x35\x39\x35\x39\x5A\x30\x5F\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x17\x30\x15\x06\x03\x55\x04\x0A\x13\x0E\x56\x65\x72\x69\x53\x69\x67\x6E\x2C\x20\x49\x6E\x63\x2E\x31\x37\x30\x35\x06\x03\x55\x04\x0B\x13\x2E\x43\x6C\x61\x73\x73\x20\x33\x20\x50\x75\x62\x6C\x69\x63\x20\x50\x72\x69\x6D\x61\x72\x79\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6F\x6E\x20\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x30\x81\x9F\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x03\x81\x8D\x00\x30\x81\x89\x02\x81\x81\x00\xC9\x5C\x59\x9E\xF2\x1B\x8A\x01\x14\xB4\x10\xDF\x04\x40\xDB\xE3\x57\xAF\x6A\x45\x40\x8F\x84\x0C\x0B\xD1\x33\xD9\xD9\x11\xCF\xEE\x02\x58\x1F\x25\xF7\x2A\xA8\x44\x05\xAA\xEC\x03\x1F\x78\x7F\x9E\x93\xB9\x9A\x00\xAA\x23\x7D\xD6\xAC\x85\xA2\x63\x45\xC7\x72\x27\xCC\xF4\x4C\xC6\x75\x71\xD2\x39\xEF\x4F\x42\xF0\x75\xDF\x0A\x90\xC6\x8E\x20\x6F\x98\x0F\xF8\xAC\x23\x5F\x70\x29\x36\xA4\xC9\x86\xE7\xB1\x9A\x20\xCB\x53\xA5\x85\xE7\x3D\xBE\x7D\x9A\xFE\x24\x45\x33\xDC\x76\x15\xED\x0F\xA2\x71\x64\x4C\x65\x2E\x81\x68\x45\xA7\x02\x03\x01\x00\x01\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x02\x05\x00\x03\x81\x81\x00\xBB\x4C\x12\x2B\xCF\x2C\x26\x00\x4F\x14\x13\xDD\xA6\xFB\xFC\x0A\x11\x84\x8C\xF3\x28\x1C\x67\x92\x2F\x7C\xB6\xC5\xFA\xDF\xF0\xE8\x95\xBC\x1D\x8F\x6C\x2C\xA8\x51\xCC\x73\xD8\xA4\xC0\x53\xF0\x4E\xD6\x26\xC0\x76\x01\x57\x81\x92\x5E\x21\xF1\xD1\xB1\xFF\xE7\xD0\x21\x58\xCD\x69\x17\xE3\x44\x1C\x9C\x19\x44\x39\x89\x5C\xDC\x9C\x00\x0F\x56\x8D\x02\x99\xED\xA2\x90\x45\x4C\xE4\xBB\x10\xA4\x3D\xF0\x32\x03\x0E\xF1\xCE\xF8\xE8\xC9\x51\x8C\xE6\x62\x9F\xE6\x9F\xC0\x7D\xB7\x72\x9C\xC9\x36\x3A\x6B\x9F\x4E\xA8\xFF\x64\x0D\x64",
};
event ssl_stapled_ocsp(c: connection, is_orig: bool, response: string)
event ssl_stapled_ocsp(c: connection, is_client: bool, response: string)
{
local chain: vector of opaque of x509 = vector();
for ( i in c$ssl$cert_chain )
chain[i] = c$ssl$cert_chain[i]$x509$handle;
print is_orig, |response|;
print is_client, |response|;
print x509_ocsp_verify(chain, response, SSL::root_certs);
}

View file

@ -26,7 +26,7 @@ redef record SSL::Info += {
ct_proofs: vector of LogInfo &default=vector();
};
event ssl_extension_signed_certificate_timestamp(c: connection, is_orig: bool, version: count, logid: string, timestamp: count, signature_and_hashalgorithm: SSL::SignatureAndHashAlgorithm, signature: string)
event ssl_extension_signed_certificate_timestamp(c: connection, is_client: bool, version: count, logid: string, timestamp: count, signature_and_hashalgorithm: SSL::SignatureAndHashAlgorithm, signature: string)
{
print version, SSL::ct_logs[logid]$description, double_to_time(timestamp/1000.0), signature_and_hashalgorithm;
c$ssl$ct_proofs[|c$ssl$ct_proofs|] = LogInfo($version=version, $logid=logid, $timestamp=timestamp, $sig_alg=signature_and_hashalgorithm$SignatureAlgorithm, $hash_alg=signature_and_hashalgorithm$HashAlgorithm, $signature=signature);

View file

@ -5,31 +5,31 @@
@load base/protocols/ssl
event ssl_extension_elliptic_curves(c: connection, is_orig: bool, curves: index_vec)
event ssl_extension_elliptic_curves(c: connection, is_client: bool, curves: index_vec)
{
print "Curves", c$id$orig_h, c$id$resp_h;
for ( i in curves )
print SSL::ec_curves[curves[i]];
}
event ssl_extension_ec_point_formats(c: connection, is_orig: bool, point_formats: index_vec)
event ssl_extension_ec_point_formats(c: connection, is_client: bool, point_formats: index_vec)
{
print "Point formats", c$id$orig_h, c$id$resp_h, is_orig;
print "Point formats", c$id$orig_h, c$id$resp_h, is_client;
for ( i in point_formats )
print SSL::ec_point_formats[point_formats[i]];
}
event ssl_extension_application_layer_protocol_negotiation(c: connection, is_orig: bool, protocols: string_vec)
event ssl_extension_application_layer_protocol_negotiation(c: connection, is_client: bool, protocols: string_vec)
{
print "ALPN", c$id$orig_h, c$id$resp_h, protocols;
}
event ssl_extension_server_name(c: connection, is_orig: bool, names: string_vec)
event ssl_extension_server_name(c: connection, is_client: bool, names: string_vec)
{
print "server_name", c$id$orig_h, c$id$resp_h, names;
}
event ssl_extension_signature_algorithm(c: connection, is_orig: bool, signature_algorithms: vector of SSL::SignatureAndHashAlgorithm)
event ssl_extension_signature_algorithm(c: connection, is_client: bool, signature_algorithms: vector of SSL::SignatureAndHashAlgorithm)
{
print "signature_algorithm", c$id$orig_h, c$id$resp_h;
for ( i in signature_algorithms)
@ -38,26 +38,26 @@ event ssl_extension_signature_algorithm(c: connection, is_orig: bool, signature_
}
}
event ssl_extension_supported_versions(c: connection, is_orig: bool, versions: index_vec)
event ssl_extension_supported_versions(c: connection, is_client: bool, versions: index_vec)
{
print "supported_versions", c$id$orig_h, c$id$resp_h;
for ( i in versions )
print SSL::version_strings[versions[i]];
}
event ssl_extension_psk_key_exchange_modes(c: connection, is_orig: bool, modes: index_vec)
event ssl_extension_psk_key_exchange_modes(c: connection, is_client: bool, modes: index_vec)
{
print "psk_key_exchange_modes", c$id$orig_h, c$id$resp_h;
for ( i in modes )
print modes[i];
}
event ssl_extension_pre_shared_key_client_hello(c: connection, is_orig: bool, identities: psk_identity_vec, binders: string_vec)
event ssl_extension_pre_shared_key_client_hello(c: connection, is_client: bool, identities: psk_identity_vec, binders: string_vec)
{
print "pre_shared_key client hello", c$id$orig_h, c$id$resp_h, identities, binders;
}
event ssl_extension_pre_shared_key_server_hello(c: connection, is_orig: bool, selected_identity: count)
event ssl_extension_pre_shared_key_server_hello(c: connection, is_client: bool, selected_identity: count)
{
print "pre_shared_key server hello", c$id$orig_h, c$id$resp_h, selected_identity;
}

View file

@ -14,8 +14,8 @@
@load base/protocols/ssl
event ssl_extension(c: connection, is_orig: bool, code: count, val: string)
event ssl_extension(c: connection, is_client: bool, code: count, val: string)
{
if ( ! is_orig && code == 43 )
if ( ! is_client && code == 43 )
print bytestring_to_hexstr(val);
}

View file

@ -23,9 +23,9 @@
redef SSL::disable_analyzer_after_detection=F;
event ssl_extension_key_share(c: connection, is_orig: bool, curves: index_vec)
event ssl_extension_key_share(c: connection, is_client: bool, curves: index_vec)
{
print "key_share", c$id, is_orig;
print "key_share", c$id, is_client;
for ( i in curves )
{
print SSL::ec_curves[curves[i]];
@ -37,9 +37,9 @@ event ssl_established(c: connection)
print "established", c$id;
}
event ssl_encrypted_data(c: connection, is_orig: bool, record_version: count, content_type: count, length: count)
event ssl_encrypted_data(c: connection, is_client: bool, record_version: count, content_type: count, length: count)
{
print "encrypted", c$id, is_orig, SSL::version_strings[record_version], content_type;
print "encrypted", c$id, is_client, SSL::version_strings[record_version], content_type;
}
event ssl_client_hello(c: connection, version: count, record_version: count, possible_ts: time, client_random: string, session_id: string, ciphers: index_vec, comp_methods: index_vec) &priority=5

View file

@ -6,9 +6,9 @@
redef SSL::disable_analyzer_after_detection=F;
event ssl_encrypted_data(c: connection, is_orig: bool, record_version: count, content_type: count, length: count)
event ssl_encrypted_data(c: connection, is_client: bool, record_version: count, content_type: count, length: count)
{
print "encrypted", c$id, is_orig, SSL::version_strings[record_version], content_type;
print "encrypted", c$id, is_client, SSL::version_strings[record_version], content_type;
}
event ssl_established(c: connection)
@ -16,7 +16,7 @@ event ssl_established(c: connection)
print "Established!";
}
event ssl_probable_encrypted_handshake_message(c: connection, is_orig: bool, length: count)
event ssl_probable_encrypted_handshake_message(c: connection, is_client: bool, length: count)
{
print "Probable handshake", is_orig, length;
print "Probable handshake", is_client, length;
}