Change x509 log - now certificates are only logged once per hour.

Add parsing of several more types to SAN extension.

Make error messages of x509 file analyzer more useful.

Fix file ID generation.

You apparently have to be very careful which EndOfFile function of
the file analysis framework you call... otherwhise it might try
to close another file id. This took me quite a while to find.

addresses BIT-953, BIT-760, BIT-1150
This commit is contained in:
Bernhard Amann 2014-03-13 00:05:48 -07:00
parent 7eb6b5133e
commit 0d50b8b04f
10 changed files with 242 additions and 55 deletions

View file

@ -108,7 +108,7 @@ public:
* cached and passed back in to a subsequent function call in order
* to avoid costly file handle lookups (which have to go through
* the \c get_file_handle script-layer event). An empty string
* indicates the associate file is not going to be analyzed further.
* indicates the associated file is not going to be analyzed further.
*/
std::string DataIn(const u_char* data, uint64 len, analyzer::Tag tag,
Connection* conn, bool is_orig,

View file

@ -45,7 +45,7 @@ bool file_analysis::X509::EndOfFile()
::X509* ssl_cert = d2i_X509(NULL, &cert_char, cert_data.size());
if ( !ssl_cert )
{
reporter->Error("Could not parse X509 certificate");
reporter->Error("Could not parse X509 certificate. fuid %s", GetFile()->GetID().c_str());
return false;
}
@ -222,7 +222,7 @@ void file_analysis::X509::ParseBasicConstraints(X509_EXTENSION* ex)
BASIC_CONSTRAINTS *constr = (BASIC_CONSTRAINTS *) X509V3_EXT_d2i(ex);
if ( !constr )
{
reporter->Error("Certificate with invalid BasicConstraint");
reporter->Error("Certificate with invalid BasicConstraint. fuid %s", GetFile()->GetID().c_str());
}
else
{
@ -246,41 +246,96 @@ void file_analysis::X509::ParseSAN(X509_EXTENSION* ext)
GENERAL_NAMES *altname = (GENERAL_NAMES*)X509V3_EXT_d2i(ext);
if ( !altname )
{
reporter->Error("could not parse subject alternative names");
reporter->Error("Could not parse subject alternative names. fuid %s", GetFile()->GetID().c_str());
return;
}
VectorVal* names = new VectorVal(internal_type("string_vec")->AsVectorType());
VectorVal* names = 0;
VectorVal* emails = 0;
VectorVal* uris = 0;
VectorVal* ips = 0;
unsigned int otherfields = 0;
int j = 0;
for ( int i = 0; i < sk_GENERAL_NAME_num(altname); i++ )
{
GENERAL_NAME *gen = sk_GENERAL_NAME_value(altname, i);
assert(gen);
if ( gen->type == GEN_DNS )
if ( gen->type == GEN_DNS || gen->type == GEN_URI || gen->type == GEN_EMAIL )
{
if (ASN1_STRING_type(gen->d.ia5) != V_ASN1_IA5STRING)
{
reporter->Error("DNS-field does not contain an IA5String");
reporter->Error("DNS-field does not contain an IA5String. fuid %s", GetFile()->GetID().c_str());
continue;
}
const char* name = (const char*) ASN1_STRING_data(gen->d.ia5);
StringVal* bs = new StringVal(name);
names->Assign(j, bs);
j++;
switch ( gen->type )
{
case GEN_DNS:
if ( names == 0 )
names = new VectorVal(internal_type("string_vec")->AsVectorType());
names->Assign(names->Size(), bs);
break;
case GEN_URI:
if ( uris == 0 )
uris = new VectorVal(internal_type("string_vec")->AsVectorType());
uris->Assign(uris->Size(), bs);
break;
case GEN_EMAIL:
if ( emails == 0 )
emails = new VectorVal(internal_type("string_vec")->AsVectorType());
emails->Assign(emails->Size(), bs);
break;
}
}
else if ( gen->type == GEN_IPADD )
{
if ( ips == 0 )
ips = new VectorVal(internal_type("addr_vec")->AsVectorType());
uint32* addr = (uint32*) gen->d.ip->data;
if(gen->d.ip->length == 4 )
{
ips->Assign(ips->Size(), new AddrVal(*addr));
}
else if ( gen->d.ip->length == 16 )
{
ips->Assign(ips->Size(), new AddrVal(addr));
}
else
{
reporter->Error("Weird IP address length %d in subject alternative name. fuid %s", gen->d.ip->length, GetFile()->GetID().c_str());
continue;
}
}
else
{
// we should perhaps sometime parse out ip-addresses
reporter->Error("Subject alternative name contained non-dns fields");
//reporter->Error("Subject alternative name contained unsupported fields. fuid %s", GetFile()->GetID().c_str());
// This happens quite often - just mark it
otherfields = 1;
continue;
}
}
RecordVal* sanExt = new RecordVal(BifType::Record::X509::SubjectAlternativeName);
if ( names != 0 )
sanExt->Assign(0, names);
if ( uris != 0 )
sanExt->Assign(1, uris);
if ( emails != 0 )
sanExt->Assign(2, emails);
if ( ips != 0 )
sanExt->Assign(3, ips);
sanExt->Assign(4, new Val(otherfields, TYPE_BOOL));
val_list* vl = new val_list();
vl->append(GetFile()->GetVal()->Ref());
vl->append(names);
vl->append(sanExt);
mgr.QueueEvent(x509_ext_subject_alternative_name, vl);
}

View file

@ -1,4 +1,57 @@
## Generated for encountered X509 certificates, e.g., in the clear SSL/TLS
## connection handshake.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/X.509>`__ for more information
## about the X.509 format.
##
## f: The file.
##
## cert_ref: An opaque pointer to the underlying OpenSSL data structure of the
## certificate.
##
## cert: The parsed certificate information.
##
## .. bro:see:: x509_extension x509_ext_basic_constraints
## x509_ext_subject_alternative_name x509_parse x509_verify
## x509_get_certificate_string
event x509_certificate%(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate%);
## Generated for X509 extensions seen in a certificate.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/X.509>`__ for more information
## about the X.509 format.
##
## f: The file.
##
## ext: The parsed extension.
##
## .. bro:see:: x509_certificate x509_ext_basic_constraints
## x509_ext_subject_alternative_name x509_parse x509_verify
## x509_get_certificate_string
event x509_extension%(f: fa_file, ext: X509::Extension%);
## Generated for the X509 basic constraints extension seen in a certificate.
## This extension can be used to identify the subject of a certificate as a CA.
##
## f: The file.
##
## ext: The parsed basic constraints extension.
##
## .. bro:see:: x509_certificate x509_extension
## x509_ext_subject_alternative_name x509_parse x509_verify
## x509_get_certificate_string
event x509_ext_basic_constraints%(f: fa_file, ext: X509::BasicConstraints%);
event x509_ext_subject_alternative_name%(f: fa_file, names: string_vec%);
## Generated for the X509 subject alternative name extension seen in a certificate.
## This extension can be used to allow additional entities to be bound to the subject
## of the certificate. Usually it is used to specify one or multiple DNS names for
## which a certificate is valid.
##
## f: The file.
##
## ext: The parsed subject alternative name extension.
##
## .. bro:see:: x509_certificate x509_extension x509_ext_basic_constraints
## x509_parse x509_verify
## x509_get_certificate_string
event x509_ext_subject_alternative_name%(f: fa_file, ext: X509::SubjectAlternativeName%);

View file

@ -42,7 +42,9 @@ RecordVal* x509_error_record(uint64_t num, const char* reason)
##
## Returns: A X509::Certificate structure
##
## .. bro:see:: x509_verify
## .. bro:see:: x509_certificate x509_extension x509_ext_basic_constraints
## x509_ext_subject_alternative_name x509_verify
## x509_get_certificate_string
function x509_parse%(cert: opaque of x509%): X509::Certificate
%{
assert(cert);
@ -60,7 +62,9 @@ function x509_parse%(cert: opaque of x509%): X509::Certificate
## (false).
##
## Returns: X509 certificate as a string
##
## .. bro:see:: x509_certificate x509_extension x509_ext_basic_constraints
## x509_ext_subject_alternative_name x509_parse x509_verify
function x509_get_certificate_string%(cert: opaque of x509, pem: bool &default=F%): string
%{
assert(cert);
@ -101,7 +105,9 @@ function x509_get_certificate_string%(cert: opaque of x509, pem: bool &default=F
## Returns: A record of type X509::Result containing the result code of the verify
## operation. In case of success also returns the full certificate chain.
##
## .. bro:see:: x509_parse
## .. bro:see:: x509_certificate x509_extension x509_ext_basic_constraints
## x509_ext_subject_alternative_name x509_parse
## x509_get_certificate_string
function x509_verify%(certs: x509_opaque_vector, root_certs: table_string_of_string%): X509::Result
%{
X509_STORE* ctx = 0;

View file

@ -1,5 +1,5 @@
type X509::Certificate: record;
type X509::Extension: record;
type X509::BasicConstraints: record;
type X509::SubjectAlternativeName: record;
type X509::Result: record;