add a file analyzer to parse ocsp request and response

add two events: ocsp_request and ocsp_response
This commit is contained in:
Liang Zhu 2015-06-15 11:05:04 -07:00
parent 668f3e38ad
commit e9baddfd6b
15 changed files with 833 additions and 1 deletions

View file

@ -0,0 +1 @@
Support for ocsp file analysis framework.

View file

@ -0,0 +1 @@
@load ./main

View file

@ -0,0 +1,11 @@
@load base/frameworks/files
@load base/utils/paths
module FileOCSP;
export {
## add one more argument to indicate is ocsp response or request
redef record Files::AnalyzerArgs += {
ocsp_type: string &optional;
};
}

View file

@ -2927,6 +2927,50 @@ export {
}; };
} }
module OCSP;
export {
type OneReq: record {
hashAlgorithm: string &log;
issuerNameHash: string &log;
issuerKeyHash: string &log;
serialNumber: string &log;
#RequestExtensions: xxx
};
type Request: record {
version: count &log &optional;
requestorName: string &log &optional;
requestList: vector of OneReq;
#requestExtensions: xxx
};
type SingleResp: record {
hashAlgorithm: string &log;
issuerNameHash: string &log;
issuerKeyHash: string &log;
serialNumber: string &log;
certStatus: string &log;
thisUpdate: string &log;
nextUpdate: string &log &optional;
#Extensions: xxx
};
type Response: record {
responseStatus: string &log;
responseType: string &log;
version: count &log;
responderID: string &log;
producedAt: string &log;
responses: vector of SingleResp;
#responseExtensions:xxx
signatureAlgorithm: string &log;
signature: string; #&log;
};
}
module GLOBAL;
type ocsp_req_vec: vector of OCSP::OneReq;
type ocsp_resp_vec: vector of OCSP::SingleResp;
module SOCKS; module SOCKS;
export { export {
## This record is for a SOCKS client or server to provide either a ## This record is for a SOCKS client or server to provide either a

View file

@ -65,6 +65,7 @@
@load base/files/extract @load base/files/extract
@load base/files/unified2 @load base/files/unified2
@load base/files/x509 @load base/files/x509
@load base/files/ocsp
@load base/misc/find-checksum-offloading @load base/misc/find-checksum-offloading
@load base/misc/find-filtered-trace @load base/misc/find-filtered-trace

View file

@ -115,6 +115,8 @@ SERIAL_VAL(CARDINALITY_VAL, 22)
SERIAL_VAL(X509_VAL, 23) SERIAL_VAL(X509_VAL, 23)
SERIAL_VAL(COMM_STORE_HANDLE_VAL, 24) SERIAL_VAL(COMM_STORE_HANDLE_VAL, 24)
SERIAL_VAL(COMM_DATA_VAL, 25) SERIAL_VAL(COMM_DATA_VAL, 25)
SERIAL_VAL(OCSP_REQ_VAL, 26)
SERIAL_VAL(OCSP_RESP_VAL, 27)
#define SERIAL_EXPR(name, val) SERIAL_CONST(name, val, EXPR) #define SERIAL_EXPR(name, val) SERIAL_CONST(name, val, EXPR)
SERIAL_EXPR(EXPR, 1) SERIAL_EXPR(EXPR, 1)

View file

@ -627,6 +627,8 @@ extern OpaqueType* cardinality_type;
extern OpaqueType* topk_type; extern OpaqueType* topk_type;
extern OpaqueType* bloomfilter_type; extern OpaqueType* bloomfilter_type;
extern OpaqueType* x509_opaque_type; extern OpaqueType* x509_opaque_type;
extern OpaqueType* ocsp_req_opaque_type;
extern OpaqueType* ocsp_resp_opaque_type;
// Returns the Bro basic (non-parameterized) type with the given type. // Returns the Bro basic (non-parameterized) type with the given type.
// The reference count of the type is not increased. // The reference count of the type is not increased.

View file

@ -4,3 +4,4 @@ add_subdirectory(hash)
add_subdirectory(pe) add_subdirectory(pe)
add_subdirectory(unified2) add_subdirectory(unified2)
add_subdirectory(x509) add_subdirectory(x509)
add_subdirectory(ocsp)

View file

@ -0,0 +1,10 @@
include(BroPlugin)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR})
bro_plugin_begin(Bro OCSP)
bro_plugin_cc(OCSP.cc Plugin.cc)
bro_plugin_bif(events.bif types.bif)
bro_plugin_end()

View file

@ -0,0 +1,637 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include <string>
#include "OCSP.h"
#include "Event.h"
#include "events.bif.h"
#include "types.bif.h"
#include "file_analysis/Manager.h"
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/asn1.h>
#include <openssl/opensslconf.h>
using namespace file_analysis;
IMPLEMENT_SERIAL(OCSP_REQVal, SER_OCSP_REQ_VAL);
IMPLEMENT_SERIAL(OCSP_RESPVal, SER_OCSP_RESP_VAL);
#define OCSP_STRING_BUF_SIZE 2048
//this function is copied from src/file_analysis/analyzer/extract/Extract.cc
static Val* get_extract_field_val(RecordVal* args, const char* name)
{
Val* rval = args->Lookup(name);
if ( ! rval )
reporter->Error("File extraction analyzer missing arg field: %s", name);
return rval;
}
//convert different ANS1 type to c string
static int ANS1_to_cstr(char *buf, int buf_len, void *data, int type)
{
if (data == NULL || buf == NULL || buf_len <=0)
return -1;
int new_len = -1;
BIO *bio = BIO_new(BIO_s_mem());
memset(buf, 0, buf_len);
if (type == V_ASN1_OCTET_STRING)
{
if (i2a_ASN1_STRING(bio, (ASN1_STRING *)data, V_ASN1_OCTET_STRING) <= 0)
goto err;
}
else if (type == V_ASN1_BIT_STRING)
{
if (i2a_ASN1_STRING(bio, (ASN1_STRING *)data, V_ASN1_BIT_STRING) <= 0)
goto err;
}
else if (type == V_ASN1_INTEGER)
{
if (i2a_ASN1_INTEGER(bio, (ASN1_INTEGER *)data) <= 0)
goto err;
}
else if (type == V_ASN1_OBJECT)
{
if (i2a_ASN1_OBJECT(bio, (ASN1_OBJECT *)data) <= 0)
goto err;
}
else if (type == V_ASN1_GENERALIZEDTIME)
{
// TODO: convert ASN1_GENERALIZEDTIME to epoch time?
// new API: ASN1_TIME_diff() requires openssl 1.0.2
// epoch time might be better for post processing
// NOTE: this is for human readable time format
//if (!ASN1_GENERALIZEDTIME_print(bio, (ASN1_GENERALIZEDTIME *)data))
// goto err;
// NOTE: this is printing the raw string which is also understandable
// since this is smaller, let's keep ASN1_GENERALIZEDTIME as this for now?
ASN1_GENERALIZEDTIME *tmp = (ASN1_GENERALIZEDTIME *)data;
BIO_write(bio, tmp->data, tmp->length);
}
else
goto err;
new_len = BIO_read(bio, buf, buf_len);
err:
BIO_free_all(bio);
return new_len;
}
//ANS1 OCTET string to c string
static int ASN1_OCTET_STRING_to_cstr(char *buf, int len, void *data)
{
return ANS1_to_cstr(buf, len, data, V_ASN1_OCTET_STRING);
}
//ANS1 BIT string to c string
static int ASN1_BIT_STRING_to_cstr(char *buf, int len, void *data)
{
return ANS1_to_cstr(buf, len, data, V_ASN1_BIT_STRING);
}
//ANS1 integer to c string
static int ASN1_INTEGER_to_cstr(char *buf, int len, void *data)
{
return ANS1_to_cstr(buf, len, data, V_ASN1_INTEGER);
}
//ANS1 object to c string
static int ASN1_OBJECT_to_cstr(char *buf, int len, void *data)
{
return ANS1_to_cstr(buf, len, data, V_ASN1_OBJECT);
}
//ASN1_GENERALIZEDTIME to c string
static int ASN1_GENERALIZEDTIME_to_cstr(char *buf, int len, void *data)
{
return ANS1_to_cstr(buf, len, data, V_ASN1_GENERALIZEDTIME);
}
//CENERAL XXX to c string
static int GENERAL_NAME_to_cstr(char *buf, int buf_len, void *data)
{
if (data == NULL || buf == NULL || buf_len <= 0)
return -1;
int new_len = -1;
BIO *bio = BIO_new(BIO_s_mem());
memset(buf, 0, buf_len);
if (GENERAL_NAME_print(bio, (GENERAL_NAME *)data) <= 0)
goto err;
new_len = BIO_read(bio, buf, buf_len);
err:
BIO_free_all(bio);
return new_len;
}
//OCSP respond id to c string
static int OCSP_RESPID_to_cstr(char *buf, int buf_len, OCSP_RESPID *resp_id)
{
if (resp_id == NULL || buf == NULL || buf_len <= 0)
return -1;
int new_len = -1;
BIO *bio = BIO_new(BIO_s_mem());
memset(buf, 0, buf_len);
if (resp_id->type == V_OCSP_RESPID_NAME)
{
if (X509_NAME_print_ex(bio, resp_id->value.byName, 0, XN_FLAG_ONELINE) <=0)
goto err;
}
else if (resp_id->type == V_OCSP_RESPID_KEY)
{
if (i2a_ASN1_STRING(bio, resp_id->value.byKey, V_ASN1_OCTET_STRING) <= 0)
goto err;
}
else
goto err;
new_len = BIO_read(bio, buf, buf_len);
err:
BIO_free_all(bio);
return new_len;
}
//print out a cert id for debug
static void ocsp_print_cert_id(OCSP_CERTID *cid)
{
if (cid == NULL)
return;
char buf[OCSP_STRING_BUF_SIZE];
int len = sizeof(buf);
memset(buf, 0, len);
int new_len = -1;
//print hashAlgorithm
new_len = ASN1_OBJECT_to_cstr(buf, len, (void *)(cid->hashAlgorithm->algorithm));
StringVal hashAlgorithm = StringVal(new_len, buf);
printf("[%d]hashAlgorithm: %s\n", new_len, hashAlgorithm.CheckString());
//print issuerNameHash
new_len = ASN1_OCTET_STRING_to_cstr(buf, len, (void *)(cid->issuerNameHash));
StringVal issuerNameHash = StringVal(new_len, buf);
printf("[%d]issuerNameHash: %s\n", new_len, issuerNameHash.CheckString());
//print issuerKeyHash
new_len = ASN1_OCTET_STRING_to_cstr(buf, len, (void *)(cid->issuerKeyHash));
StringVal issuerKeyHash = StringVal(new_len, buf);
printf("[%d]issuerKeyHash: %s\n", new_len, issuerKeyHash.CheckString());
//print serialNumber
new_len = ASN1_INTEGER_to_cstr(buf, len, (void *)(cid->issuerKeyHash));
StringVal serialNumber = StringVal(new_len, buf);
printf("[%d]serialNumber: %s\n", new_len, serialNumber.CheckString());
}
//fill in cert id
static void ocsp_fill_cert_id(OCSP_CERTID *cert_id, RecordVal *d)
{
if (d == NULL || cert_id == NULL)
return;
char buf[OCSP_STRING_BUF_SIZE];
int buf_len = sizeof(buf);
memset(buf, 0, buf_len);
//hashAlgorithm
int len = -1;
len = ASN1_OBJECT_to_cstr(buf, buf_len, (void *)(cert_id->hashAlgorithm->algorithm));
if (len > 0)
d->Assign(0, new StringVal(len, buf));
//issuerNameHash
len = -1;
len = ASN1_OCTET_STRING_to_cstr(buf, buf_len, (void *)(cert_id->issuerNameHash));
if (len > 0)
d->Assign(1, new StringVal(len, buf));
//issuerKeyHash
len = -1;
len = ASN1_OCTET_STRING_to_cstr(buf, buf_len, (void *)(cert_id->issuerKeyHash));
if (len > 0)
d->Assign(2, new StringVal(len, buf));
//serialNumber
len = -1;
len = ASN1_INTEGER_to_cstr(buf, buf_len, (void *)(cert_id->issuerKeyHash));
if (len > 0)
d->Assign(3, new StringVal(len, buf));
}
file_analysis::Analyzer* OCSP::Instantiate(RecordVal* args, File* file)
{
Val* ocsp_type = get_extract_field_val(args, "ocsp_type");
if (! ocsp_type )
return 0;
return new OCSP(args, file, ocsp_type->AsString()->CheckString());
}
file_analysis::OCSP::OCSP(RecordVal* args, file_analysis::File* file, const string& arg_ocsp_type)
: file_analysis::Analyzer(file_mgr->GetComponentTag("OCSP"), args, file)
{
ocsp_type = arg_ocsp_type;
ocsp_data.clear();
}
bool file_analysis::OCSP::DeliverStream(const u_char* data, uint64 len)
{
ocsp_data.append(reinterpret_cast<const char*>(data), len);
return true;
}
bool file_analysis::OCSP::Undelivered(uint64 offset, uint64 len)
{
return false;
}
// parse OCSP request or response and send data to bro scriptland
bool file_analysis::OCSP::EndOfFile()
{
OCSP_REQUEST *req = NULL;
OCSP_RESPONSE *resp = NULL;
const unsigned char* ocsp_char = reinterpret_cast<const unsigned char*>(ocsp_data.data());
if (ocsp_type == "request")
{
req = d2i_OCSP_REQUEST(NULL, &ocsp_char, ocsp_data.size());
if (!req)
{
reporter->Weird(fmt("OPENSSL Could not parse OCSP request (fuid %s)", GetFile()->GetID().c_str()));
goto ocsp_cleanup;
}
//parse request into record
OCSP_REQVal* req_val = new OCSP_REQVal(req);
RecordVal* req_record = ParseRequest(req_val);
if (!req_record)
{
reporter->Weird(fmt("Internal fail to parse OCSP request (fuid %s)", GetFile()->GetID().c_str()));
Unref(req_val);
goto ocsp_cleanup;
}
// and send the record on to scriptland
val_list* vl = new val_list();
vl->append(GetFile()->GetVal()->Ref());
vl->append(req_val->Ref());
vl->append(req_record->Ref());
mgr.QueueEvent(ocsp_request, vl);
Unref(req_val);
Unref(req_record);
}
else if (ocsp_type == "response")
{
resp = d2i_OCSP_RESPONSE(NULL, &ocsp_char, ocsp_data.size());
if (!resp)
{
reporter->Weird(fmt("OPENSSL Could not parse OCSP response (fuid %s)", GetFile()->GetID().c_str()));
goto ocsp_cleanup;
}
//parse request into record
OCSP_RESPVal* resp_val = new OCSP_RESPVal(resp);
RecordVal* resp_record = ParseResponse(resp_val);
if (!resp_record)
{
reporter->Weird(fmt("Internal fail to parse OCSP response (fuid %s)", GetFile()->GetID().c_str()));
Unref(resp_val);
goto ocsp_cleanup;
}
// and send the record on to scriptland
val_list* vl = new val_list();
vl->append(GetFile()->GetVal()->Ref());
vl->append(resp_val->Ref());
vl->append(resp_record->Ref());
mgr.QueueEvent(ocsp_response, vl);
Unref(resp_val);
Unref(resp_record);
}
else
reporter->Weird(fmt("the given argument of ocsp_type (%s) is not recognized", ocsp_type.c_str()));
ocsp_cleanup:
//if (resp)
// OCSP_RESPONSE_free(resp);
//if (req)
// OCSP_REQUEST_free(req);
return false;
}
// parse OCSP request and trigger event
RecordVal *file_analysis::OCSP::ParseRequest(OCSP_REQVal *req_val)
{
if (req_val == NULL)
return NULL;
OCSP_REQUEST *req = NULL;
OCSP_ONEREQ *one_req = NULL;
OCSP_CERTID *cert_id = NULL;
OCSP_REQINFO *inf = NULL;
//OCSP_SIGNATURE *sig = NULL;
RecordVal* ocsp_req_record = NULL;
VectorVal* all_req_bro = NULL;
int req_count = -1, i = -1, len = -1;
long version = -1;
req = req_val->GetReq();
if (req == NULL)
return NULL;
char buf[OCSP_STRING_BUF_SIZE];
int buf_len = sizeof(buf);
memset(buf, 0, buf_len);
inf = req->tbsRequest;
//sig = req->optionalSignature;
if (inf == NULL)
return NULL;
ocsp_req_record = new RecordVal(BifType::Record::OCSP::Request);
if (!ocsp_req_record)
{
reporter->Error("Cannot create OCSP request structure: Internal memory error");
return NULL;
}
//version
version = ASN1_INTEGER_get(inf->version);
if (version != -1)
ocsp_req_record->Assign(0, new Val((uint64)version, TYPE_COUNT));
//requestorName
if (inf->requestorName != NULL)
{
len = -1;
len = GENERAL_NAME_to_cstr(buf, buf_len, (void *)(inf->requestorName));
if (len > 1)
ocsp_req_record->Assign(1, new StringVal(len, buf));
}
//deal with details of the request
req_count = OCSP_request_onereq_count(req);
if (req_count <= 0)
goto clean_up;
for (i=0; i<req_count; i++)
{
one_req = OCSP_request_onereq_get0(req, i);
cert_id = OCSP_onereq_get0_id(one_req);
if (all_req_bro == NULL)
all_req_bro = new VectorVal(internal_type("ocsp_req_vec")->AsVectorType());
RecordVal *one_req_bro = new RecordVal(BifType::Record::OCSP::OneReq);
ocsp_fill_cert_id(cert_id, one_req_bro);
all_req_bro->Assign(all_req_bro->Size(), one_req_bro);
}
if (all_req_bro != NULL)
ocsp_req_record->Assign(2, all_req_bro);
clean_up:
return ocsp_req_record;
}
// parse OCSP response and trigger event
RecordVal *file_analysis::OCSP::ParseResponse(OCSP_RESPVal *resp_val)
{
if (resp_val == NULL)
return NULL;
OCSP_RESPONSE *resp = NULL;
OCSP_RESPBYTES *resp_bytes = NULL;
OCSP_CERTID *cert_id = NULL;
OCSP_BASICRESP *basic_resp = NULL;
OCSP_RESPDATA *resp_data = NULL;
OCSP_RESPID *resp_id = NULL;
OCSP_SINGLERESP *single_resp = NULL;
//OCSP_CERTSTATUS *cst = NULL;
//OCSP_REVOKEDINFO *rev = NULL;
RecordVal *ocsp_resp_record = NULL;
VectorVal *all_resp_bro = NULL;
int resp_count = -1, status = -1, i = -1, len = -1;
long version = -1;
resp = resp_val->GetResp();
if (resp == NULL)
return NULL;
char buf[OCSP_STRING_BUF_SIZE];
int buf_len = sizeof(buf);
memset(buf, 0, buf_len);
ocsp_resp_record = new RecordVal(BifType::Record::OCSP::Response);
if (!ocsp_resp_record)
{
reporter->Error("Cannot create OCSP response structure: Internal memory error");
return NULL;
}
//responseStatus
status = OCSP_response_status(resp);
const char *status_str = OCSP_response_status_str(status);
ocsp_resp_record->Assign(0, new StringVal(strlen(status_str), status_str));
//responseType
resp_bytes = resp->responseBytes;
if (!resp_bytes)
goto clean_up;
len = -1;
len = ASN1_OBJECT_to_cstr(buf, buf_len, (void *)(resp_bytes->responseType));
if (len > 0)
ocsp_resp_record->Assign(1, new StringVal(len, buf));
//get the basic response
basic_resp = OCSP_response_get1_basic(resp);
if (!basic_resp)
goto clean_up;
resp_data = basic_resp->tbsResponseData;
if (!resp_data)
goto clean_up;
//version
version = ASN1_INTEGER_get(resp_data->version);
if (version != -1)
ocsp_resp_record->Assign(2, new Val((uint64)version, TYPE_COUNT));
//responderID
resp_id = resp_data->responderId;
len = -1;
len = OCSP_RESPID_to_cstr(buf, buf_len, resp_id);
if (len > 0)
ocsp_resp_record->Assign(3, new StringVal(len, buf));
//producedAt
len = -1;
len = ASN1_GENERALIZEDTIME_to_cstr(buf, buf_len, (void *)(resp_data->producedAt));
if (len > 0)
ocsp_resp_record->Assign(4, new StringVal(len, buf));
//responses
resp_count = sk_OCSP_SINGLERESP_num(resp_data->responses);
if (resp_count <= 0)
goto clean_up;
for (i=0; i<resp_count; i++)
{
single_resp = sk_OCSP_SINGLERESP_value(resp_data->responses, i);
if (!single_resp)
continue;
if (all_resp_bro == NULL)
all_resp_bro = new VectorVal(internal_type("ocsp_resp_vec")->AsVectorType());
RecordVal *single_resp_bro = new RecordVal(BifType::Record::OCSP::SingleResp);
//cert id
cert_id = single_resp->certId;
ocsp_fill_cert_id(cert_id, single_resp_bro);
//certStatus
const char *cert_status_str = OCSP_cert_status_str(single_resp->certStatus->type);
single_resp_bro->Assign(4, new StringVal(strlen(cert_status_str), cert_status_str));
//thisUpdate
len = -1;
len = ASN1_GENERALIZEDTIME_to_cstr(buf, buf_len, (void *)(single_resp->thisUpdate));
if (len > 0)
single_resp_bro->Assign(5, new StringVal(len, buf));
//nextUpdate
len = -1;
len = ASN1_GENERALIZEDTIME_to_cstr(buf, buf_len, (void *)(single_resp->nextUpdate));
if (len > 0)
single_resp_bro->Assign(6, new StringVal(len, buf));
all_resp_bro->Assign(all_resp_bro->Size(), single_resp_bro);
}
if (all_resp_bro != NULL)
ocsp_resp_record->Assign(5, all_resp_bro);
//signatureAlgorithm
if (basic_resp->signatureAlgorithm)
{
len = -1;
len = ASN1_OBJECT_to_cstr(buf, buf_len, (void *)(basic_resp->signatureAlgorithm->algorithm));
if (len > 0)
ocsp_resp_record->Assign(6, new StringVal(len, buf));
}
//signature
if (basic_resp->signature)
{
len = -1;
len = ASN1_BIT_STRING_to_cstr(buf, buf_len, (void *)(basic_resp->signature));
if (len > 0)
ocsp_resp_record->Assign(7, new StringVal(len, buf));
}
clean_up:
return ocsp_resp_record;
}
//OCSP_REQVal
OCSP_REQVal::OCSP_REQVal(OCSP_REQUEST* arg_ocsp_req) : OpaqueVal(ocsp_req_opaque_type)
{
ocsp_req = arg_ocsp_req;
}
OCSP_REQVal::OCSP_REQVal() : OpaqueVal(ocsp_req_opaque_type)
{
ocsp_req = NULL;
}
OCSP_REQVal::~OCSP_REQVal()
{
if (ocsp_req)
OCSP_REQUEST_free(ocsp_req);
}
OCSP_REQUEST* OCSP_REQVal::GetReq() const
{
return ocsp_req;
}
bool OCSP_REQVal::DoSerialize(SerialInfo* info) const
{
DO_SERIALIZE(SER_OCSP_REQ_VAL, OpaqueVal);
unsigned char *buf = NULL;
int length = i2d_OCSP_REQUEST(ocsp_req, &buf);
if ( length < 0 )
return false;
bool res = SERIALIZE_STR(reinterpret_cast<const char*>(buf), length);
OPENSSL_free(buf);
return res;
}
bool OCSP_REQVal::DoUnserialize(UnserialInfo* info)
{
DO_UNSERIALIZE(OpaqueVal)
int length;
unsigned char *ocsp_req_buf, *opensslbuf;
if ( ! UNSERIALIZE_STR(reinterpret_cast<char **>(&ocsp_req_buf), &length) )
return false;
opensslbuf = ocsp_req_buf; // OpenSSL likes to shift pointers around. really.
ocsp_req = d2i_OCSP_REQUEST(NULL, const_cast<const unsigned char**>(&opensslbuf), length);
delete[] ocsp_req_buf;
if ( !ocsp_req )
return false;
return true;
}
//OCSP_RESPVal
OCSP_RESPVal::OCSP_RESPVal(OCSP_RESPONSE* arg_ocsp_resp) : OpaqueVal(ocsp_resp_opaque_type)
{
ocsp_resp = arg_ocsp_resp;
}
OCSP_RESPVal::OCSP_RESPVal() : OpaqueVal(ocsp_resp_opaque_type)
{
ocsp_resp = NULL;
}
OCSP_RESPVal::~OCSP_RESPVal()
{
if (ocsp_resp)
OCSP_RESPONSE_free(ocsp_resp);
}
OCSP_RESPONSE* OCSP_RESPVal::GetResp() const
{
return ocsp_resp;
}
bool OCSP_RESPVal::DoSerialize(SerialInfo* info) const
{
DO_SERIALIZE(SER_OCSP_RESP_VAL, OpaqueVal);
unsigned char *buf = NULL;
int length = i2d_OCSP_RESPONSE(ocsp_resp, &buf);
if ( length < 0 )
return false;
bool res = SERIALIZE_STR(reinterpret_cast<const char*>(buf), length);
OPENSSL_free(buf);
return res;
}
bool OCSP_RESPVal::DoUnserialize(UnserialInfo* info)
{
DO_UNSERIALIZE(OpaqueVal)
int length;
unsigned char *ocsp_resp_buf, *opensslbuf;
if ( ! UNSERIALIZE_STR(reinterpret_cast<char **>(&ocsp_resp_buf), &length) )
return false;
opensslbuf = ocsp_resp_buf; // OpenSSL likes to shift pointers around. really.
ocsp_resp = d2i_OCSP_RESPONSE(NULL, const_cast<const unsigned char**>(&opensslbuf), length);
delete[] ocsp_resp_buf;
if ( !ocsp_resp )
return false;
return true;
}

View file

@ -0,0 +1,66 @@
// See the file "COPYING" in the main distribution directory for copyright.
#ifndef FILE_ANALYSIS_OCSP_H
#define FILE_ANALYSIS_OCSP_H
#include <string>
#include "Val.h"
#include "../File.h"
#include "Analyzer.h"
#include <openssl/ocsp.h>
#include <openssl/x509.h>
#include <openssl/asn1.h>
namespace file_analysis {
class OCSP_REQVal;
class OCSP_RESPVal;
class OCSP : public file_analysis::Analyzer {
public:
virtual bool DeliverStream(const u_char* data, uint64 len);
virtual bool Undelivered(uint64 offset, uint64 len);
virtual bool EndOfFile();
static RecordVal *ParseResponse(OCSP_RESPVal *);
static RecordVal *ParseRequest(OCSP_REQVal *);
static file_analysis::Analyzer* Instantiate(RecordVal* args, File* file);
protected:
OCSP(RecordVal* args, File* file, const string& ocsp_type);
private:
std::string ocsp_data;
std::string ocsp_type;
};
class OCSP_REQVal: public OpaqueVal {
public:
explicit OCSP_REQVal(OCSP_REQUEST *);
~OCSP_REQVal();
OCSP_REQUEST *GetReq() const;
protected:
OCSP_REQVal();
private:
OCSP_REQUEST *ocsp_req;
DECLARE_SERIAL(OCSP_REQVal);
};
class OCSP_RESPVal: public OpaqueVal {
public:
explicit OCSP_RESPVal(OCSP_RESPONSE *);
~OCSP_RESPVal();
OCSP_RESPONSE *GetResp() const;
protected:
OCSP_RESPVal();
private:
OCSP_RESPONSE *ocsp_resp;
DECLARE_SERIAL(OCSP_RESPVal);
};
}
#endif

View file

@ -0,0 +1,25 @@
// See the file in the main distribution directory for copyright.
#include "plugin/Plugin.h"
#include "OCSP.h"
namespace plugin {
namespace Bro_OCSP {
class Plugin : public plugin::Plugin {
public:
plugin::Configuration Configure()
{
AddComponent(new ::file_analysis::Component("OCSP", ::file_analysis::OCSP::Instantiate));
plugin::Configuration config;
config.name = "Bro::OCSP";
config.description = "OCSP analyzer";
return config;
}
} plugin;
}
}

View file

@ -0,0 +1,23 @@
## Generated for encountered OCSP request
##
##
## f: The file.
##
## req_ref: An opaque pointer to the underlying OpenSSL data structure of the
## OCSP request
##
## req: The parsed OCSP request information.
##
event ocsp_request%(f: fa_file, req_ref: opaque of ocsp_req, req: OCSP::Request%);
## Generated for encountered OCSP response
##
##
## f: The file.
##
## req_ref: An opaque pointer to the underlying OpenSSL data structure of the
## OCSP response
##
## req: The parsed OCSP response information.
##
event ocsp_response%(f: fa_file, resp_ref: opaque of ocsp_resp, resp: OCSP::Response%);

View file

@ -0,0 +1,4 @@
type OCSP::Request: record;
type OCSP::Response: record;
type OCSP::OneReq: record;
type OCSP::SingleResp: record;

View file

@ -131,6 +131,8 @@ OpaqueType* cardinality_type = 0;
OpaqueType* topk_type = 0; OpaqueType* topk_type = 0;
OpaqueType* bloomfilter_type = 0; OpaqueType* bloomfilter_type = 0;
OpaqueType* x509_opaque_type = 0; OpaqueType* x509_opaque_type = 0;
OpaqueType* ocsp_req_opaque_type = 0;
OpaqueType* ocsp_resp_opaque_type = 0;
// Keep copy of command line // Keep copy of command line
int bro_argc; int bro_argc;
@ -873,7 +875,9 @@ int main(int argc, char** argv)
topk_type = new OpaqueType("topk"); topk_type = new OpaqueType("topk");
bloomfilter_type = new OpaqueType("bloomfilter"); bloomfilter_type = new OpaqueType("bloomfilter");
x509_opaque_type = new OpaqueType("x509"); x509_opaque_type = new OpaqueType("x509");
ocsp_req_opaque_type = new OpaqueType("ocsp_req");
ocsp_resp_opaque_type = new OpaqueType("ocsp_resp");
// The leak-checker tends to produce some false // The leak-checker tends to produce some false
// positives (memory which had already been // positives (memory which had already been
// allocated before we start the checking is // allocated before we start the checking is