mirror of
https://github.com/zeek/zeek.git
synced 2025-10-04 23:58:20 +00:00
add a file analyzer to parse ocsp request and response
add two events: ocsp_request and ocsp_response
This commit is contained in:
parent
668f3e38ad
commit
e9baddfd6b
15 changed files with 833 additions and 1 deletions
|
@ -4,3 +4,4 @@ add_subdirectory(hash)
|
|||
add_subdirectory(pe)
|
||||
add_subdirectory(unified2)
|
||||
add_subdirectory(x509)
|
||||
add_subdirectory(ocsp)
|
10
src/file_analysis/analyzer/ocsp/CMakeLists.txt
Normal file
10
src/file_analysis/analyzer/ocsp/CMakeLists.txt
Normal 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()
|
637
src/file_analysis/analyzer/ocsp/OCSP.cc
Normal file
637
src/file_analysis/analyzer/ocsp/OCSP.cc
Normal 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;
|
||||
}
|
66
src/file_analysis/analyzer/ocsp/OCSP.h
Normal file
66
src/file_analysis/analyzer/ocsp/OCSP.h
Normal 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
|
25
src/file_analysis/analyzer/ocsp/Plugin.cc
Normal file
25
src/file_analysis/analyzer/ocsp/Plugin.cc
Normal 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;
|
||||
|
||||
}
|
||||
}
|
23
src/file_analysis/analyzer/ocsp/events.bif
Normal file
23
src/file_analysis/analyzer/ocsp/events.bif
Normal 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%);
|
4
src/file_analysis/analyzer/ocsp/types.bif
Normal file
4
src/file_analysis/analyzer/ocsp/types.bif
Normal file
|
@ -0,0 +1,4 @@
|
|||
type OCSP::Request: record;
|
||||
type OCSP::Response: record;
|
||||
type OCSP::OneReq: record;
|
||||
type OCSP::SingleResp: record;
|
Loading…
Add table
Add a link
Reference in a new issue