Howto

Every year, at least once a year, I make an honest effort to implement
Bro and to start taking advantage of its advanced capabilities. Each
year, I spend a few hours on it and give up. I look through every doc
I can find on the Bro web site and in the tarball, but the lack of
sufficient examples and documentation always stifles any progress. I
want this year to be different. The purpose of this email is to find
out from you guys how to do the following (ideally in example form):

How do I write a policy to detect when an SSL connection has a
certificate which was created less than 30 days ago (not_valid_before

30 days ago)?

How do I send arbitrary connection data to an external program and
receive information back from it (and I need something more detailed
than "use broccoli")?

Thanks,

Martin

Every year, at least once a year, I make an honest effort to implement
Bro and to start taking advantage of its advanced capabilities. Each
year, I spend a few hours on it and give up.

Unfortunately Bro has never been at a sufficient point to spend a few hours and start getting great results, it typically takes a lot more time and effort. We're working hard to change that though.

I want this year to be different.

Great to hear Martin!

How do I write a policy to detect when an SSL connection has a
certificate which was created less than 30 days ago (not_valid_before 30 days ago)?

These will only work in the git master and we'll likely have some sort of notice for this situation for the release, but it's pretty easy and there are a couple of ways of doing it.

If you want to do it through the new logging framework...

@load protocols/ssl
event SSL::log_ssl(rec: SSL::Info)
  {
  if ( rec$not_valid_before > network_time() - 60*60*24*30 )
    {
    print fmt("%s is using a certificate that was created %d days ago",
      rec$id$resp_h, (network_time()-rec$not_valid_before) / (60*60*24));
    }
  }

That code above doesn't output to the logging framework or the notice framework, but I wanted to pare it down to the bare minimum to demonstrate how easy that is. If you want to use the actual internal SSL events, you can do this...

@load protocols/ssl
event x509_certificate(c: connection, cert: X509, is_server: bool, chain_idx: count, chain_len: count, der_cert: string)
  {
  # The entire certificate chain is presented to us here but we only want chain_idx==0 because that's the actual host certificate.
  if ( chain_idx != 0 )
    return;

  if ( cert$not_valid_before > network_time() - 60*60*24*30 )
    {
    print fmt("%s is using a certificate that was created %d days ago",
      c$id$resp_h, (network_time()-cert$not_valid_before) / (60*60*24));
    }
  }

Please send along more concrete examples of tasks you'd like to complete. Those are the kinds of questions I really like. :slight_smile:

How do I send arbitrary connection data to an external program and
receive information back from it (and I need something more detailed
than "use broccoli")?

Heh, the reason you've always gotten that answer is that that's a bit more complicated that we all wish it was. If you could give me an example of what you are aiming to do here I may be able to give a good answer of either how to do it or make sure that it's possible soon.

We've begun defining a companion input framework to go along with the logging framework but it's still very early and we haven't begun writing any code for it yet (IOW, definitely not in the next release).

  .Seth

@load protocols/ssl
event SSL::log_ssl(rec: SSL::Info)
{
if ( rec$not_valid_before > network_time() - 60*60*24*30 )
{
print fmt("%s is using a certificate that was created %d days ago",
rec$id$resp_h, (network_time()-rec$not_valid_before) / (60*60*24));
}
}

Awesome, this is good stuff! Now I have a concrete goal. If I can
get just this working, it will have been worth my time.

@load protocols/ssl
event x509_certificate(c: connection, cert: X509, is_server: bool, chain_idx: count, chain_len: count, der_cert: string)
{
# The entire certificate chain is presented to us here but we only want chain_idx==0 because that's the actual host certificate.
if ( chain_idx != 0 )
return;

   if \( cert$not\_valid\_before > network\_time\(\) \- 60\*60\*24\*30 \)
           \{
           print fmt\("%s is using a certificate that was created %d days ago",
                   c$id$resp\_h, \(network\_time\(\)\-cert$not\_valid\_before\) / \(60\*60\*24\)\);
           \}
   \}

So when would one want to use this version? If you need access to the
entire cert chain for your calculations?

Please send along more concrete examples of tasks you'd like to complete. Those are the kinds of questions I really like. :slight_smile:

Ha, how much time do you have!

We've begun defining a companion input framework to go along with the logging framework but it's still very early and we haven't begun writing any code for it yet (IOW, definitely not in the next release).

Please, please do it this way:
Create a generic external IO system that uses an HTTP protocol. REST
is preferred, but the simpler the better. That way you can get out of
the binary protocol business and get back to work on Bro's core
competencies, and anyone who wants to interact with Bro can just make
sure they have a sensible web API.

  if ( rec$not_valid_before > network_time() - 60*60*24*30 )

Note, this will need to be:

  if ( rec$not_valid_before > network_time() - 60*60*24*30 sec )

Bro won't allow mixing integers with time values.

    Vern

Damn, I knew I should have tested that first. Thanks.

  .Seth

So when would one want to use this version? If you need access to the
entire cert chain for your calculations?

That's up to you. :slight_smile: I have a whole list of things you may want to do (and some of which will be done out of the box).

1. You may want to see the signing chain for a certificate, including the root signer. This event will give you the subject, the actual certificate itself, etc. Here's the cert structure...
  type X509: record { version: count; serial: string; subject: string; issuer: string; not_valid_before: time; not_valid_after: time; };

2. You need the full certificate chain to do certificate validation (that's already built into the script).

3. You may want extract the certificates in the chain. The entire certificate chain is given to you as DER and you can print it to a file with the &raw_output attribute.

Ha, how much time do you have!

That's the only way we can make sure that we are solving real world problems. :slight_smile:

Please, please do it this way:
Create a generic external IO system that uses an HTTP protocol. REST
is preferred, but the simpler the better.

Thanks for the comments. I think it's certainly possible that someone could already implement something like this with broccoli and that's probably how it should be done anyway. It would be like an API daemon. :slight_smile:

Feel free to file a feature request ticket, I think creating an API daemon would be possible and could work quite well.
  http://tracker.bro-ids.org/
  
  .Seth