mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00

This commit changes the SSL and X.509 logging formats to something that, hopefully, slowly approaches what they will look like in the future. X.509 log is not yet deduplicated; this will come in the future. This commit introduces two new options, which determine if certificate issuers and subjects are still logged in ssl.log. The default is to have the host subject/issuer logged, but to remove client-certificate information. Client-certificates are not a typically used feature nowadays.
201 lines
5.5 KiB
Text
201 lines
5.5 KiB
Text
##! Log information about certificates while attempting to avoid duplicate
|
|
##! logging.
|
|
|
|
@load base/utils/directions-and-hosts
|
|
@load base/protocols/ssl
|
|
@load base/files/x509
|
|
@load base/frameworks/cluster
|
|
|
|
module Known;
|
|
|
|
export {
|
|
redef enum Log::ID += { CERTS_LOG };
|
|
|
|
global log_policy_certs: Log::PolicyHook;
|
|
|
|
type CertsInfo: record {
|
|
## The timestamp when the certificate was detected.
|
|
ts: time &log;
|
|
## The address that offered the certificate.
|
|
host: addr &log;
|
|
## If the certificate was handed out by a server, this is the
|
|
## port that the server was listening on.
|
|
port_num: port &log &optional;
|
|
## Certificate subject.
|
|
subject: string &log &optional;
|
|
## Certificate issuer subject.
|
|
issuer_subject: string &log &optional;
|
|
## Serial number for the certificate.
|
|
serial: string &log &optional;
|
|
};
|
|
|
|
## The certificates whose existence should be logged and tracked.
|
|
## Choices are: LOCAL_HOSTS, REMOTE_HOSTS, ALL_HOSTS, NO_HOSTS.
|
|
option cert_tracking = LOCAL_HOSTS;
|
|
|
|
## Toggles between different implementations of this script.
|
|
## When true, use a Broker data store, else use a regular Zeek set
|
|
## with keys uniformly distributed over proxy nodes in cluster
|
|
## operation.
|
|
const use_cert_store = T &redef;
|
|
|
|
type AddrCertHashPair: record {
|
|
host: addr;
|
|
hash: string;
|
|
};
|
|
|
|
## Holds the set of all known certificates. Keys in the store are of
|
|
## type :zeek:type:`Known::AddrCertHashPair` and their associated value is
|
|
## always the boolean value of "true".
|
|
global cert_store: Cluster::StoreInfo;
|
|
|
|
## The Broker topic name to use for :zeek:see:`Known::cert_store`.
|
|
const cert_store_name = "zeek/known/certs" &redef;
|
|
|
|
## The expiry interval of new entries in :zeek:see:`Known::cert_store`.
|
|
## This also changes the interval at which certs get logged.
|
|
option cert_store_expiry = 1day;
|
|
|
|
## The timeout interval to use for operations against
|
|
## :zeek:see:`Known::cert_store`.
|
|
option cert_store_timeout = 15sec;
|
|
|
|
## The set of all known certificates to store for preventing duplicate
|
|
## logging. It can also be used from other scripts to
|
|
## inspect if a certificate has been seen in use. The string value
|
|
## in the set is for storing the DER formatted certificate' SHA1 hash.
|
|
##
|
|
## In cluster operation, this set is uniformly distributed across
|
|
## proxy nodes.
|
|
global certs: set[addr, string] &create_expire=1day &redef;
|
|
|
|
## Event that can be handled to access the loggable record as it is sent
|
|
## on to the logging framework.
|
|
global log_known_certs: event(rec: CertsInfo);
|
|
}
|
|
|
|
event zeek_init()
|
|
{
|
|
if ( ! Known::use_cert_store )
|
|
return;
|
|
|
|
Known::cert_store = Cluster::create_store(Known::cert_store_name);
|
|
}
|
|
|
|
event Known::cert_found(info: CertsInfo, hash: string)
|
|
{
|
|
if ( ! Known::use_cert_store )
|
|
return;
|
|
|
|
local key = AddrCertHashPair($host = info$host, $hash = hash);
|
|
|
|
when ( local r = Broker::put_unique(Known::cert_store$store, key,
|
|
T, Known::cert_store_expiry) )
|
|
{
|
|
if ( r$status == Broker::SUCCESS )
|
|
{
|
|
if ( r$result as bool )
|
|
Log::write(Known::CERTS_LOG, info);
|
|
}
|
|
else
|
|
Reporter::error(fmt("%s: data store put_unique failure",
|
|
Known::cert_store_name));
|
|
}
|
|
timeout Known::cert_store_timeout
|
|
{
|
|
# Can't really tell if master store ended up inserting a key.
|
|
Log::write(Known::CERTS_LOG, info);
|
|
}
|
|
}
|
|
|
|
event known_cert_add(info: CertsInfo, hash: string)
|
|
{
|
|
if ( Known::use_cert_store )
|
|
return;
|
|
|
|
if ( [info$host, hash] in Known::certs )
|
|
return;
|
|
|
|
add Known::certs[info$host, hash];
|
|
|
|
@if ( ! Cluster::is_enabled() ||
|
|
Cluster::local_node_type() == Cluster::PROXY )
|
|
Log::write(Known::CERTS_LOG, info);
|
|
@endif
|
|
}
|
|
|
|
event Known::cert_found(info: CertsInfo, hash: string)
|
|
{
|
|
if ( Known::use_cert_store )
|
|
return;
|
|
|
|
if ( [info$host, hash] in Known::certs )
|
|
return;
|
|
|
|
local key = cat(info$host, hash);
|
|
Cluster::publish_hrw(Cluster::proxy_pool, key, known_cert_add, info, hash);
|
|
event known_cert_add(info, hash);
|
|
}
|
|
|
|
event Cluster::node_up(name: string, id: string)
|
|
{
|
|
if ( Known::use_cert_store )
|
|
return;
|
|
|
|
if ( Cluster::local_node_type() != Cluster::WORKER )
|
|
return;
|
|
|
|
# Drop local suppression cache on workers to force HRW key repartitioning.
|
|
Known::certs = table();
|
|
}
|
|
|
|
event Cluster::node_down(name: string, id: string)
|
|
{
|
|
if ( Known::use_cert_store )
|
|
return;
|
|
|
|
if ( Cluster::local_node_type() != Cluster::WORKER )
|
|
return;
|
|
|
|
# Drop local suppression cache on workers to force HRW key repartitioning.
|
|
Known::certs = table();
|
|
}
|
|
|
|
event ssl_established(c: connection) &priority=3
|
|
{
|
|
if ( ! c$ssl?$cert_chain )
|
|
return;
|
|
|
|
if ( |c$ssl$cert_chain| < 1 )
|
|
return;
|
|
|
|
if ( ! c$ssl$cert_chain[0]?$x509 )
|
|
return;
|
|
|
|
local fuid = c$ssl$cert_chain[0]$fuid;
|
|
|
|
if ( ! c$ssl$cert_chain[0]?$sha1 )
|
|
{
|
|
Reporter::error(fmt("Certificate with fuid %s did not contain sha1 hash when checking for known certs. Aborting",
|
|
fuid));
|
|
return;
|
|
}
|
|
|
|
local host = c$id$resp_h;
|
|
|
|
if ( ! addr_matches_host(host, cert_tracking) )
|
|
return;
|
|
|
|
local hash = c$ssl$cert_chain[0]$sha1;
|
|
local cert = c$ssl$cert_chain[0]$x509$certificate;
|
|
local info = CertsInfo($ts = network_time(), $host = host,
|
|
$port_num = c$id$resp_p, $subject = cert$subject,
|
|
$issuer_subject = cert$issuer,
|
|
$serial = cert$serial);
|
|
event Known::cert_found(info, hash);
|
|
}
|
|
|
|
event zeek_init() &priority=5
|
|
{
|
|
Log::create_stream(Known::CERTS_LOG, [$columns=CertsInfo, $ev=log_known_certs, $path="known_certs", $policy=log_policy_certs]);
|
|
}
|