diff --git a/scripts/policy/protocols/ssl/ocsp-stapling.bro b/scripts/policy/protocols/ssl/ocsp-stapling.bro new file mode 100644 index 0000000000..0a0c92da1c --- /dev/null +++ b/scripts/policy/protocols/ssl/ocsp-stapling.bro @@ -0,0 +1,113 @@ +#! Log ocsp stapling information + +module OCSP_STAPLING; + +export { + redef enum Log::ID += { LOG }; + type Info: record { + ## timestamp + ts: time &log; + + ## connection uid + cid: conn_id &log; + + ## connection uid + cuid: string &log; + + ## size of this response + size: count &log; + + ## responseStatus + responseStatus: string &log; + + ## responseType + responseType: string &log; + + ## version + version: count &log; + + ## responderID + responderID: string &log; + + ## producedAt + producedAt: string &log; + + ## NOTE: the following are specific to one cert id + ## the above are for one message which may contain + ## several responses + + ## index + idx: count &log &optional; + + ## cert id + cert_id: OCSP::CertId &log &optional; + + ## certStatus (this is the response to look at) + certStatus: string &log &optional; + + ## thisUpdate + thisUpdate: string &log &optional; + + ## nextUpdate + nextUpdate: string &log &optional; + }; +} + +event ssl_stapled_ocsp(c: connection, is_orig: bool, response: string) + { + local resp: OCSP::Response = ocsp_parse_response(response); + + # TOCHECK: is this right? + local resp_size: count =|response|; + + if (resp?$responses) + { + local num: count = 0; + for (x in resp$responses) + { + num += 1; + local single_resp: OCSP::SingleResp = resp$responses[x]; + local cert_id: OCSP::CertId = [$hashAlgorithm = single_resp$hashAlgorithm, + $issuerNameHash = single_resp$issuerNameHash, + $issuerKeyHash = single_resp$issuerKeyHash, + $serialNumber = single_resp$serialNumber]; + + local resp_rec: Info = [$ts = network_time(), + $cid = c$id, + $cuid = c$uid, + $size = resp_size, + $responseStatus = resp$responseStatus, + $responseType = resp$responseType, + $version = resp$version, + $responderID = resp$responderID, + $producedAt = resp$producedAt, + $idx = num, + $cert_id = cert_id, + $certStatus = single_resp$certStatus, + $thisUpdate = single_resp$thisUpdate]; + + if (single_resp?$nextUpdate) + resp_rec$nextUpdate = single_resp$nextUpdate; + Log::write(LOG, resp_rec); + } + } + else + { + # no response content? this is weird but log it anyway + local resp_rec_empty: Info = [$ts = network_time(), + $cid = c$id, + $cuid = c$uid, + $size = resp_size, + $responseStatus = resp$responseStatus, + $responseType = resp$responseType, + $version = resp$version, + $responderID = resp$responderID, + $producedAt = resp$producedAt]; + Log::write(LOG, resp_rec_empty); + } + } + +event bro_init() + { + Log::create_stream(LOG, [$columns=Info, $path="ocsp-stapling"]); + } diff --git a/src/file_analysis/analyzer/ocsp/CMakeLists.txt b/src/file_analysis/analyzer/ocsp/CMakeLists.txt index d1cff9d157..12c54c1c84 100644 --- a/src/file_analysis/analyzer/ocsp/CMakeLists.txt +++ b/src/file_analysis/analyzer/ocsp/CMakeLists.txt @@ -6,5 +6,5 @@ include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} bro_plugin_begin(Bro OCSP) bro_plugin_cc(OCSP.cc Plugin.cc) -bro_plugin_bif(events.bif types.bif) +bro_plugin_bif(events.bif types.bif functions.bif) bro_plugin_end() diff --git a/src/file_analysis/analyzer/ocsp/functions.bif b/src/file_analysis/analyzer/ocsp/functions.bif new file mode 100644 index 0000000000..19d9ac1cb5 --- /dev/null +++ b/src/file_analysis/analyzer/ocsp/functions.bif @@ -0,0 +1,36 @@ +%%{ +#include "file_analysis/analyzer/ocsp/OCSP.h" +#include "types.bif.h" +%%} + +## Parses a OCSP response into an OCSP::Response structure. +## +## ocsp_reply: OCSP data. +## +## Returns: A OCSP::Response structure. +## +## .. bro:see:: ssl_stapled_ocsp +function ocsp_parse_response%(ocsp_reply: string%): OCSP::Response + %{ + const unsigned char* start = ocsp_reply->Bytes(); + OCSP_RESPONSE *resp = NULL; + file_analysis::OCSP_RESPVal* resp_val = NULL; + RecordVal* resp_record = NULL; + resp = d2i_OCSP_RESPONSE(NULL, &start, ocsp_reply->Len()); + if ( ! resp ) + { + reporter->Weird("OPENSSL Could not parse OCSP response"); + return NULL; + } + resp_val = new file_analysis::OCSP_RESPVal(resp); + resp_record = file_analysis::OCSP::ParseResponse(resp_val); + if (!resp_record) + { + reporter->Weird("Internal fail to parse OCSP response"); + Unref(resp_val); + return NULL; + } + Unref(resp_val); + //Unref(resp_record); + return resp_record; + %}