zeek/scripts/policy/files/x509/disable-certificate-events-known-certs.zeek
Patrick Kelley 8fd444092b initial
2025-05-07 15:35:15 -04:00

85 lines
3.0 KiB
Plaintext

##! This script disables repeat certificate events for hosts for hosts for which the same
##! certificate was seen in the recent past;
##!
##! This script specifically plugs into the event caching mechanism that is set up by the
##! base X509 script certificate-event-cache.zeek. It adds another layer of tracking that
##! checks if the same certificate was seen for the server IP address before, when the same
##! SNI was used to connect. If the certificate is in the event cache and all of these conditions
##! apply, then no certificate related events will be raised.
##!
##! Please note that while this optimization can lead to a considerable reduction of load in some
##! settings, it also means that certain detection scripts that rely on the certificate events being
##! raised do no longer work - since the events will not be raised for all connections.
##!
##! Currently this script only works for X509 certificates that are sent via SSL/TLS connections.
##!
##! If you use any script that requires certificate events for each single connection,
##! you should not load this script.
@load base/protocols/ssl
@load base/files/x509
module DisableX509Events;
## Let's be a bit more generous with the number of certificates that we allow to be put into
## the cache.
redef X509::certificate_cache_max_entries = 100000;
type CacheIndex: record {
## IP address of the server the certificate was seen on.
ip: addr;
## SNI the client sent in the connection
sni: string &optional;
## sha256 of the certificate
sha256: string;
};
redef record SSL::Info += {
## Set to true to force certificate events to always be raised for this connection.
always_raise_x509_events: bool &default=F;
};
redef record X509::Info += {
## Set to true to force certificate events to always be raised for this certificate.
always_raise_x509_events: bool &default=F;
};
global certificate_replay_tracking: set[CacheIndex] &read_expire=X509::certificate_cache_minimum_eviction_interval;
hook X509::x509_certificate_cache_replay(f: fa_file, e: X509::Info, sha256: string) &priority=5
{
# Bail out if x509 is already set - or if the file tells us that we should always raise events.
if ( f$info?$x509 || e$always_raise_x509_events )
return;
local raise_events = F;
# not sure how that could happen - but let's be safe...
if ( |f$conns| == 0 )
return;
for ( c in f$conns )
{
if ( ! f$conns[c]?$ssl )
return;
local test = CacheIndex($ip=f$conns[c]$id$resp_h, $sha256=sha256);
if ( f$conns[c]$ssl?$server_name )
test$sni = f$conns[c]$ssl$server_name;
if ( test !in certificate_replay_tracking || f$conns[c]$ssl$always_raise_x509_events )
{
raise_events = T;
add certificate_replay_tracking[test];
}
}
if ( ! raise_events )
{
# We don't have to raise the events. :).
# Instead we just already set f$x509. That makes the data available to scripts that might need them - and the x509_certificate_cache_replayh
# hook in certificate-event-cache will just abort.
f$info$x509 = e;
}
}