mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Add Kerberos support for PKINIT (x509 cert authentication)
This commit is contained in:
parent
3c3920bfbc
commit
b8376ca733
5 changed files with 313 additions and 42 deletions
|
@ -1,2 +1,3 @@
|
|||
@load ./main
|
||||
@load ./files
|
||||
@load-sigs ./dpd.sig
|
142
scripts/base/protocols/krb/files.bro
Normal file
142
scripts/base/protocols/krb/files.bro
Normal file
|
@ -0,0 +1,142 @@
|
|||
@load ./main
|
||||
@load base/utils/conn-ids
|
||||
@load base/frameworks/files
|
||||
@load base/files/x509
|
||||
|
||||
module KRB;
|
||||
|
||||
export {
|
||||
redef record Info += {
|
||||
# Client certificate
|
||||
client_cert: Files::Info &optional;
|
||||
# Subject of client certificate, if any
|
||||
client_cert_subject:string &log &optional;
|
||||
# File unique ID of client cert, if any
|
||||
client_cert_fuid: string &log &optional;
|
||||
|
||||
# Server certificate
|
||||
server_cert: Files::Info &optional;
|
||||
# Subject of server certificate, if any
|
||||
server_cert_subject:string &log &optional;
|
||||
# File unique ID of server cert, if any
|
||||
server_cert_fuid: string &log &optional;
|
||||
};
|
||||
|
||||
## Default file handle provider for KRB.
|
||||
global get_file_handle: function(c: connection, is_orig: bool): string;
|
||||
|
||||
## Default file describer for KRB.
|
||||
global describe_file: function(f: fa_file): string;
|
||||
}
|
||||
|
||||
function get_file_handle(c: connection, is_orig: bool): string
|
||||
{
|
||||
# Unused. File handles are generated in the analyzer.
|
||||
return "";
|
||||
}
|
||||
|
||||
function describe_file(f: fa_file): string
|
||||
{
|
||||
if ( f$source != "KRB_TCP" && f$source != "KRB" )
|
||||
return "";
|
||||
|
||||
if ( ! f?$info || ! f$info?$x509 || ! f$info$x509?$certificate )
|
||||
return "";
|
||||
|
||||
# It is difficult to reliably describe a certificate - especially since
|
||||
# we do not know when this function is called (hence, if the data structures
|
||||
# are already populated).
|
||||
#
|
||||
# Just return a bit of our connection information and hope that that is good enough.
|
||||
for ( cid in f$conns )
|
||||
{
|
||||
if ( f$conns[cid]?$krb )
|
||||
{
|
||||
local c = f$conns[cid];
|
||||
return cat(c$id$resp_h, ":", c$id$resp_p);
|
||||
}
|
||||
}
|
||||
|
||||
return cat("Serial: ", f$info$x509$certificate$serial, " Subject: ",
|
||||
f$info$x509$certificate$subject, " Issuer: ",
|
||||
f$info$x509$certificate$issuer);
|
||||
}
|
||||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Files::register_protocol(Analyzer::ANALYZER_KRB_TCP,
|
||||
[$get_file_handle = KRB::get_file_handle,
|
||||
$describe = KRB::describe_file]);
|
||||
|
||||
Files::register_protocol(Analyzer::ANALYZER_KRB,
|
||||
[$get_file_handle = KRB::get_file_handle,
|
||||
$describe = KRB::describe_file]);
|
||||
}
|
||||
|
||||
event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5
|
||||
{
|
||||
if ( f$source != "KRB_TCP" && f$source != "KRB" )
|
||||
return;
|
||||
|
||||
local info: Info;
|
||||
|
||||
if ( ! c?$krb )
|
||||
{
|
||||
info$ts = network_time();
|
||||
info$uid = c$uid;
|
||||
info$id = c$id;
|
||||
}
|
||||
else
|
||||
info = c$krb;
|
||||
|
||||
if ( is_orig )
|
||||
{
|
||||
info$client_cert = f$info;
|
||||
info$client_cert_fuid = f$id;
|
||||
}
|
||||
else
|
||||
{
|
||||
info$server_cert = f$info;
|
||||
info$server_cert_fuid = f$id;
|
||||
}
|
||||
|
||||
c$krb = info;
|
||||
|
||||
Files::add_analyzer(f, Files::ANALYZER_X509);
|
||||
# always calculate hashes. They are not necessary for base scripts
|
||||
# but very useful for identification, and required for policy scripts
|
||||
Files::add_analyzer(f, Files::ANALYZER_MD5);
|
||||
Files::add_analyzer(f, Files::ANALYZER_SHA1);
|
||||
}
|
||||
|
||||
function fill_in_subjects(c: connection)
|
||||
{
|
||||
if ( !c?$krb )
|
||||
return;
|
||||
|
||||
if ( c$krb?$client_cert && c$krb$client_cert?$x509 && c$krb$client_cert$x509?$certificate )
|
||||
c$krb$client_cert_subject = c$krb$client_cert$x509$certificate$subject;
|
||||
|
||||
if ( c$krb?$server_cert && c$krb$server_cert?$x509 && c$krb$server_cert$x509?$certificate )
|
||||
c$krb$server_cert_subject = c$krb$server_cert$x509$certificate$subject;
|
||||
}
|
||||
|
||||
event krb_error(c: connection, msg: Error_Msg)
|
||||
{
|
||||
fill_in_subjects(c);
|
||||
}
|
||||
|
||||
event krb_as_rep(c: connection, msg: KDC_Reply)
|
||||
{
|
||||
fill_in_subjects(c);
|
||||
}
|
||||
|
||||
event krb_tgs_rep(c: connection, msg: KDC_Reply)
|
||||
{
|
||||
fill_in_subjects(c);
|
||||
}
|
||||
|
||||
event connection_state_remove(c: connection)
|
||||
{
|
||||
fill_in_subjects(c);
|
||||
}
|
|
@ -63,7 +63,7 @@ export {
|
|||
} &redef;
|
||||
|
||||
## Event that can be handled to access the KRB record as it is sent on
|
||||
## to the loggin framework.
|
||||
## to the logging framework.
|
||||
global log_krb: event(rec: Info);
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ event bro_init() &priority=5
|
|||
Analyzer::register_for_ports(Analyzer::ANALYZER_KRB_TCP, tcp_ports);
|
||||
}
|
||||
|
||||
event krb_error(c: connection, msg: Error_Msg)
|
||||
event krb_error(c: connection, msg: Error_Msg) &priority=5
|
||||
{
|
||||
local info: Info;
|
||||
|
||||
|
@ -123,21 +123,30 @@ event krb_error(c: connection, msg: Error_Msg)
|
|||
info$error_msg = error_msg[msg$error_code];
|
||||
}
|
||||
|
||||
Log::write(KRB::LOG, info);
|
||||
info$logged = T;
|
||||
|
||||
c$krb = info;
|
||||
}
|
||||
|
||||
event krb_as_req(c: connection, msg: KDC_Request)
|
||||
event krb_error(c: connection, msg: Error_Msg) &priority=-5
|
||||
{
|
||||
Log::write(KRB::LOG, c$krb);
|
||||
c$krb$logged = T;
|
||||
}
|
||||
|
||||
event krb_as_req(c: connection, msg: KDC_Request) &priority=5
|
||||
{
|
||||
if ( c?$krb && c$krb$logged )
|
||||
return;
|
||||
|
||||
local info: Info;
|
||||
|
||||
if ( !c?$krb )
|
||||
{
|
||||
info$ts = network_time();
|
||||
info$uid = c$uid;
|
||||
info$id = c$id;
|
||||
}
|
||||
else
|
||||
info = c$krb;
|
||||
|
||||
info$client = fmt("%s/%s", msg$client_name, msg$service_realm);
|
||||
info$service = msg$service_name;
|
||||
|
@ -174,7 +183,7 @@ event krb_as_req(c: connection, msg: KDC_Request)
|
|||
c$krb = info;
|
||||
}
|
||||
|
||||
event krb_tgs_req(c: connection, msg: KDC_Request)
|
||||
event krb_tgs_req(c: connection, msg: KDC_Request) &priority=5
|
||||
{
|
||||
if ( c?$krb && c$krb$logged )
|
||||
return;
|
||||
|
@ -191,7 +200,7 @@ event krb_tgs_req(c: connection, msg: KDC_Request)
|
|||
c$krb = info;
|
||||
}
|
||||
|
||||
event krb_as_rep(c: connection, msg: KDC_Reply)
|
||||
event krb_as_rep(c: connection, msg: KDC_Reply) &priority=5
|
||||
{
|
||||
local info: Info;
|
||||
|
||||
|
@ -214,13 +223,17 @@ event krb_as_rep(c: connection, msg: KDC_Reply)
|
|||
info$service = msg$ticket$service_name;
|
||||
info$result = "success";
|
||||
|
||||
Log::write(KRB::LOG, info);
|
||||
info$logged = T;
|
||||
|
||||
c$krb = info;
|
||||
}
|
||||
|
||||
event krb_tgs_rep(c: connection, msg: KDC_Reply)
|
||||
event krb_as_rep(c: connection, msg: KDC_Reply) &priority=-5
|
||||
{
|
||||
|
||||
Log::write(KRB::LOG, c$krb);
|
||||
c$krb$logged = T;
|
||||
}
|
||||
|
||||
event krb_tgs_rep(c: connection, msg: KDC_Reply) &priority=5
|
||||
{
|
||||
local info: Info;
|
||||
|
||||
|
@ -243,13 +256,16 @@ event krb_tgs_rep(c: connection, msg: KDC_Reply)
|
|||
info$service = msg$ticket$service_name;
|
||||
info$result = "success";
|
||||
|
||||
Log::write(KRB::LOG, info);
|
||||
info$logged = T;
|
||||
|
||||
c$krb = info;
|
||||
}
|
||||
|
||||
event connection_state_remove(c: connection)
|
||||
event krb_tgs_rep(c: connection, msg: KDC_Reply) &priority=-5
|
||||
{
|
||||
Log::write(KRB::LOG, c$krb);
|
||||
c$krb$logged = T;
|
||||
}
|
||||
|
||||
event connection_state_remove(c: connection) &priority=-5
|
||||
{
|
||||
if ( c?$krb && ! c$krb$logged )
|
||||
Log::write(KRB::LOG, c$krb);
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
%extern{
|
||||
#include "file_analysis/Manager.h"
|
||||
%}
|
||||
|
||||
|
||||
%header{
|
||||
Val* GetTimeFromAsn1(const KRB_Time* atime);
|
||||
Val* GetTimeFromAsn1(StringVal* atime);
|
||||
|
@ -132,6 +137,29 @@ refine connection KRB_Conn += {
|
|||
type_val->Assign(0, new Val(${msg.padata.padata_elems[i].data_type}, TYPE_COUNT));
|
||||
type_val->Assign(1, bytestring_to_val(${msg.padata.padata_elems[i].pa_data_element.pa_pw_salt.encoding.content}));
|
||||
padata->Assign(padata->Size(), type_val);
|
||||
break;
|
||||
}
|
||||
case 16:
|
||||
{
|
||||
const bytestring& cert = ${msg.padata.padata_elems[i].pa_data_element.pa_pk_as_req.cert};
|
||||
|
||||
ODesc common;
|
||||
common.AddRaw("Analyzer::ANALYZER_KRB");
|
||||
common.Add(bro_analyzer()->Conn()->StartTime());
|
||||
common.AddRaw("T", 1);
|
||||
bro_analyzer()->Conn()->IDString(&common);
|
||||
|
||||
ODesc file_handle;
|
||||
file_handle.Add(common.Description());
|
||||
file_handle.Add(0);
|
||||
|
||||
string file_id = file_mgr->HashHandle(file_handle.Description());
|
||||
|
||||
file_mgr->DataIn(reinterpret_cast<const u_char*>(cert.data()),
|
||||
cert.length(), bro_analyzer()->GetAnalyzerTag(),
|
||||
bro_analyzer()->Conn(), true, file_id);
|
||||
file_mgr->EndOfFile(file_id);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -292,6 +320,29 @@ refine connection KRB_Conn += {
|
|||
type_val->Assign(0, new Val(${msg.padata.padata_elems[i].data_type}, TYPE_COUNT));
|
||||
type_val->Assign(1, bytestring_to_val(${msg.padata.padata_elems[i].pa_data_element.pa_pw_salt.encoding.content}));
|
||||
padata->Assign(padata->Size(), type_val);
|
||||
break;
|
||||
}
|
||||
case 17:
|
||||
{
|
||||
const bytestring& cert = ${msg.padata.padata_elems[i].pa_data_element.pa_pk_as_rep.cert};
|
||||
|
||||
ODesc common;
|
||||
common.AddRaw("Analyzer::ANALYZER_KRB");
|
||||
common.Add(bro_analyzer()->Conn()->StartTime());
|
||||
common.AddRaw("F", 1);
|
||||
bro_analyzer()->Conn()->IDString(&common);
|
||||
|
||||
ODesc file_handle;
|
||||
file_handle.Add(common.Description());
|
||||
file_handle.Add(1);
|
||||
|
||||
string file_id = file_mgr->HashHandle(file_handle.Description());
|
||||
|
||||
file_mgr->DataIn(reinterpret_cast<const u_char*>(cert.data()),
|
||||
cert.length(), bro_analyzer()->GetAnalyzerTag(),
|
||||
bro_analyzer()->Conn(), false, file_id);
|
||||
file_mgr->EndOfFile(file_id);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -507,3 +558,4 @@ refine typeattr KRB_CRED_MSG += &let {
|
|||
#refine typeattr ASN1EncodingMeta += &let {
|
||||
# proc: bool = $context.connection.debug_asn1_encoding_meta(this);
|
||||
#};
|
||||
|
||||
|
|
|
@ -89,9 +89,69 @@ type KRB_PA_Data = record {
|
|||
type KRB_PA_Data_Element(type: int64, length: uint64) = case type of {
|
||||
1 -> pa_tgs_req : KRB_AP_REQ;
|
||||
3 -> pa_pw_salt : ASN1OctetString;
|
||||
16 -> pa_pk_as_req : KRB_PA_PK_AS_Req &length=length;
|
||||
17 -> pa_pk_as_rep : KRB_PA_PK_AS_Rep &length=length;
|
||||
default -> unknown : bytestring &length=length;
|
||||
};
|
||||
|
||||
# Octet string metadata
|
||||
# -- Sequence metadata
|
||||
# ---- [0] metadata
|
||||
# ------ Sequence metadata
|
||||
# -------- OID
|
||||
# ---------- [0] metadata
|
||||
# ------------ Sequence metadata
|
||||
# -------------- version
|
||||
# -------------- digestAlgorithms
|
||||
# -------------- signedData
|
||||
# -------------- certificates
|
||||
type KRB_PA_PK_AS_Req = record {
|
||||
string_meta : ASN1EncodingMeta;
|
||||
seq_meta1 : ASN1EncodingMeta;
|
||||
elem_0_meta1: ASN1EncodingMeta;
|
||||
seq_meta2 : ASN1EncodingMeta;
|
||||
oid : ASN1Encoding;
|
||||
elem_0_meta2: ASN1EncodingMeta;
|
||||
seq_meta3 : ASN1EncodingMeta;
|
||||
version : ASN1Encoding;
|
||||
digest_algs : ASN1Encoding;
|
||||
signed_data : ASN1Encoding;
|
||||
cert_meta : ASN1EncodingMeta;
|
||||
cert : bytestring &length=cert_meta.length;
|
||||
# Ignore everything else
|
||||
: bytestring &restofdata &transient;
|
||||
};
|
||||
|
||||
# Octet string metadata
|
||||
# -- [0] metadata
|
||||
# ---- Sequence metadata
|
||||
# ------ [0] metadata
|
||||
# -------- Sequence metadata
|
||||
# ---------- OID
|
||||
# ------------ [0] metadata
|
||||
# -------------- Sequence metadata
|
||||
# ---------------- version
|
||||
# ---------------- digestAlgorithms
|
||||
# ---------------- signedData
|
||||
# ---------------- certificates
|
||||
type KRB_PA_PK_AS_Rep = record {
|
||||
string_meta : ASN1EncodingMeta;
|
||||
elem_0_meta1: ASN1EncodingMeta;
|
||||
seq_meta1 : ASN1EncodingMeta;
|
||||
elem_0_meta2: ASN1EncodingMeta;
|
||||
seq_meta2 : ASN1EncodingMeta;
|
||||
oid : ASN1Encoding;
|
||||
elem_0_meta3: ASN1EncodingMeta;
|
||||
seq_meta3 : ASN1EncodingMeta;
|
||||
version : ASN1Encoding;
|
||||
digest_algs : ASN1Encoding;
|
||||
signed_data : ASN1Encoding;
|
||||
cert_meta : ASN1EncodingMeta;
|
||||
cert : bytestring &length=cert_meta.length;
|
||||
# Ignore everything else
|
||||
: bytestring &restofdata &transient;
|
||||
};
|
||||
|
||||
type KRB_REQ_Body = record {
|
||||
seq_meta : ASN1EncodingMeta;
|
||||
args : KRB_REQ_Arg[];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue