Merge remote-tracking branch 'origin/topic/johanna/gh-859'

* origin/topic/johanna/gh-859:
  Add X509/SSL changes to NEWS
  X509: add check if function succeeds
  GH-1634: Address feedback
  Small indentation fixes in ssl-log-ext.zeek
  Fix memory leak in x509_check_cert_hostname bif
  Small bugfix and updates for external test hashes (SSL/X509)
  Baseline updates for recent SSL changes.
  Add ability to check if hostname is valid for a specific cert
  Add ssl_history field to ssl.log
  Add policy script suppressing certificate events
  Add new ssl-log-ext policy script
  Deprecate extract-certs-pem.zeek and add log-certs-base64.zeek
  Implement X509 certificate log caching
  Deprecate ICSI SSL notary script.
  Change SSL and X.509 logging format
  Enable OCSP logging by default.
  Split the code that handles X509 event hashing into its own file

Closes GH-859
This commit is contained in:
Johanna Amann 2021-07-05 10:06:59 +01:00
commit 7ec50bf434
130 changed files with 2358 additions and 711 deletions

View file

@ -107,7 +107,8 @@ event ssl_established(c: connection) &priority=5
function data_channel_initial_criteria(c: connection): bool
{
return ( c?$ssl && c$ssl?$client_subject && c$ssl?$subject &&
return ( c?$ssl && c$ssl?$cert_chain && c$ssl?$client_cert_chain &&
|c$ssl$cert_chain| > 0 && |c$ssl$client_cert_chain| > 0 &&
c$ssl?$cipher && /WITH_NULL/ in c$ssl$cipher );
}

View file

@ -6,27 +6,37 @@
module SSL;
export {
## Set this to true to includd the server certificate subject and
## issuer from the SSL log file. This information is still available
## in x509.log.
const log_include_server_certificate_subject_issuer = F &redef;
## Set this to true to include the client certificate subject
## and issuer in the SSL logfile. This information is rarely present
## and probably only interesting in very specific circumstances
const log_include_client_certificate_subject_issuer = F &redef;
redef record Info += {
## Chain of certificates offered by the server to validate its
## complete signing chain.
cert_chain: vector of Files::Info &optional;
## An ordered vector of all certificate file unique IDs for the
## An ordered vector of all certificate fingerprints for the
## certificates offered by the server.
cert_chain_fuids: vector of string &optional &log;
cert_chain_fps: vector of string &optional &log;
## Chain of certificates offered by the client to validate its
## complete signing chain.
client_cert_chain: vector of Files::Info &optional;
## An ordered vector of all certificate file unique IDs for the
## An ordered vector of all certificate fingerprints for the
## certificates offered by the client.
client_cert_chain_fuids: vector of string &optional &log;
client_cert_chain_fps: vector of string &optional &log;
## Subject of the X.509 certificate offered by the server.
subject: string &log &optional;
## Subject of the signer of the X.509 certificate offered by the
## Issuer of the signer of the X.509 certificate offered by the
## server.
issuer: string &log &optional;
@ -37,6 +47,11 @@ export {
## client.
client_issuer: string &log &optional;
## Set to true if the hostname sent in the SNI matches the certificate.
## Set to false if they do not match. Unset if the client did not send
## an SNI.
sni_matches_cert: bool &log &optional;
## Current number of certificates seen from either side. Used
## to create file handles.
server_depth: count &default=0;
@ -88,6 +103,25 @@ event zeek_init() &priority=5
Files::register_protocol(Analyzer::ANALYZER_DTLS,
[$get_file_handle = SSL::get_file_handle,
$describe = SSL::describe_file]);
local ssl_filter = Log::get_filter(SSL::LOG, "default");
if ( ssl_filter$name != "<not found>" )
{
if ( ! ssl_filter?$exclude )
ssl_filter$exclude = set();
if ( ! log_include_server_certificate_subject_issuer )
{
add ssl_filter$exclude["subject"];
add ssl_filter$exclude["issuer"];
}
if ( ! log_include_client_certificate_subject_issuer )
{
add ssl_filter$exclude["client_subject"];
add ssl_filter$exclude["client_issuer"];
}
Log::add_filter(SSL::LOG, ssl_filter);
}
}
event file_sniff(f: fa_file, meta: fa_metadata) &priority=5
@ -114,28 +148,39 @@ event file_sniff(f: fa_file, meta: fa_metadata) &priority=5
{
c$ssl$cert_chain = vector();
c$ssl$client_cert_chain = vector();
c$ssl$cert_chain_fuids = string_vec();
c$ssl$client_cert_chain_fuids = string_vec();
c$ssl$cert_chain_fps = string_vec();
c$ssl$client_cert_chain_fps = string_vec();
}
if ( f$is_orig )
{
c$ssl$client_cert_chain += f$info;
c$ssl$client_cert_chain_fuids += f$id;
}
else
{
c$ssl$cert_chain += f$info;
c$ssl$cert_chain_fuids += f$id;
}
}
event ssl_established(c: connection) &priority=6
hook ssl_finishing(c: connection) &priority=20
{
# update subject and issuer information
if ( c$ssl?$cert_chain)
for ( i in c$ssl$cert_chain )
if ( c$ssl$cert_chain[i]?$x509 && c$ssl$cert_chain[i]$x509?$fingerprint )
c$ssl$cert_chain_fps += c$ssl$cert_chain[i]$x509$fingerprint;
if ( c$ssl?$client_cert_chain )
for ( i in c$ssl$client_cert_chain )
if ( c$ssl$client_cert_chain[i]?$x509 && c$ssl$client_cert_chain[i]$x509?$fingerprint )
c$ssl$client_cert_chain_fps += c$ssl$client_cert_chain[i]$x509$fingerprint;
if ( c$ssl?$cert_chain && |c$ssl$cert_chain| > 0 &&
c$ssl$cert_chain[0]?$x509 )
{
if ( c$ssl?$server_name )
{
if ( x509_check_cert_hostname(c$ssl$cert_chain[0]$x509$handle, c$ssl$server_name) != "" )
c$ssl$sni_matches_cert = T;
else
c$ssl$sni_matches_cert = F;
}
c$ssl$subject = c$ssl$cert_chain[0]$x509$certificate$subject;
c$ssl$issuer = c$ssl$cert_chain[0]$x509$certificate$issuer;
}

View file

@ -68,6 +68,36 @@ export {
## Flag to indicate if this record already has been logged, to
## prevent duplicates.
logged: bool &default=F;
## SSL history showing which types of packets we received in which order.
## Letters have the following meaning with client-sent letters being capitalized:
## H hello_request
## C client_hello
## S server_hello
## V hello_verify_request
## T NewSessionTicket
## X certificate
## K server_key_exchange
## R certificate_request
## N server_hello_done
## Y certificate_verify
## G client_key_exchange
## F finished
## W certificate_url
## U certificate_status
## A supplemental_data
## Z unassigned_handshake_type
## I change_cipher_spec
## B heartbeat
## D application_data
## E end_of_early_data
## O encrypted_extensions
## P key_update
## M message_hash
## J hello_retry_request
## L alert
## Q unknown_content_type
ssl_history: string &log &default="";
};
## The default root CA bundle. By default, the mozilla-ca-list.zeek
@ -145,7 +175,8 @@ const dtls_ports = { 443/udp };
redef likely_server_ports += { ssl_ports, dtls_ports };
event zeek_init() &priority=5
# Priority needs to be higher than priority of zeek_init in ssl/files.zeek
event zeek_init() &priority=6
{
Log::create_stream(SSL::LOG, [$columns=Info, $ev=log_ssl, $path="ssl", $policy=log_policy]);
Analyzer::register_for_ports(Analyzer::ANALYZER_SSL, ssl_ports);
@ -161,6 +192,14 @@ function set_session(c: connection)
}
}
function add_to_history(c: connection, is_orig: bool, char: string)
{
if ( is_orig )
c$ssl$ssl_history = c$ssl$ssl_history+to_upper(char);
else
c$ssl$ssl_history = c$ssl$ssl_history+to_lower(char);
}
function delay_log(info: Info, token: string)
{
if ( ! info?$delay_tokens )
@ -295,6 +334,75 @@ event ssl_handshake_message(c: connection, is_orig: bool, msg_type: count, lengt
if ( is_orig && msg_type == SSL::CLIENT_KEY_EXCHANGE )
c$ssl$client_key_exchange_seen = T;
switch ( msg_type )
{
case SSL::HELLO_REQUEST:
add_to_history(c, is_orig, "h");
break;
case SSL::CLIENT_HELLO:
add_to_history(c, is_orig, "c");
break;
case SSL::SERVER_HELLO:
add_to_history(c, is_orig, "s");
break;
case SSL::HELLO_VERIFY_REQUEST:
add_to_history(c, is_orig, "v");
break;
case SSL::SESSION_TICKET:
add_to_history(c, is_orig, "t");
break;
# end of early data
case 5:
add_to_history(c, is_orig, "e");
break;
case SSL::HELLO_RETRY_REQUEST:
add_to_history(c, is_orig, "j");
break;
case SSL::ENCRYPTED_EXTENSIONS:
add_to_history(c, is_orig, "o");
break;
case SSL::CERTIFICATE:
add_to_history(c, is_orig, "x");
break;
case SSL::SERVER_KEY_EXCHANGE:
add_to_history(c, is_orig, "k");
break;
case SSL::CERTIFICATE_REQUEST:
add_to_history(c, is_orig, "r");
break;
case SSL::SERVER_HELLO_DONE:
add_to_history(c, is_orig, "n");
break;
case SSL::CERTIFICATE_VERIFY:
add_to_history(c, is_orig, "y");
break;
case SSL::CLIENT_KEY_EXCHANGE:
add_to_history(c, is_orig, "g");
break;
case SSL::FINISHED:
add_to_history(c, is_orig, "f");
break;
case SSL::CERTIFICATE_URL:
add_to_history(c, is_orig, "w");
break;
case SSL::CERTIFICATE_STATUS:
add_to_history(c, is_orig, "u");
break;
case SSL::SUPPLEMENTAL_DATA:
add_to_history(c, is_orig, "a");
break;
case SSL::KEY_UPDATE:
add_to_history(c, is_orig, "p");
break;
# message hash
case 254:
add_to_history(c, is_orig, "m");
break;
default:
add_to_history(c, is_orig, "z");
break;
}
}
# Extension event is fired _before_ the respective client or server hello.
@ -318,6 +426,7 @@ event ssl_extension(c: connection, is_orig: bool, code: count, val: string) &pri
event ssl_change_cipher_spec(c: connection, is_orig: bool) &priority=5
{
set_session(c);
add_to_history(c, is_orig, "i");
if ( is_orig && c$ssl$client_ticket_empty_session_seen && ! c$ssl$client_key_exchange_seen )
c$ssl$resumed = T;
@ -326,10 +435,17 @@ event ssl_change_cipher_spec(c: connection, is_orig: bool) &priority=5
event ssl_alert(c: connection, is_orig: bool, level: count, desc: count) &priority=5
{
set_session(c);
add_to_history(c, is_orig, "l");
c$ssl$last_alert = alert_descriptions[desc];
}
event ssl_heartbeat(c: connection, is_orig: bool, length: count, heartbeat_type: count, payload_length: count, payload: string)
{
set_session(c);
add_to_history(c, is_orig, "b");
}
event ssl_established(c: connection) &priority=7
{
c$ssl$established = T;