mirror of
https://github.com/zeek/zeek.git
synced 2025-10-09 01:58:20 +00:00
Reformat Zeek in Spicy style
This largely copies over Spicy's `.clang-format` configuration file. The one place where we deviate is header include order since Zeek depends on headers being included in a certain order.
This commit is contained in:
parent
7b8e7ed72c
commit
f5a76c1aed
786 changed files with 131714 additions and 153609 deletions
|
@ -10,57 +10,49 @@
|
|||
#include "zeek/file_analysis/Manager.h"
|
||||
#include "zeek/util.h"
|
||||
|
||||
namespace zeek::file_analysis::detail
|
||||
{
|
||||
namespace zeek::file_analysis::detail {
|
||||
|
||||
DataEvent::DataEvent(RecordValPtr args, file_analysis::File* file, EventHandlerPtr ce,
|
||||
EventHandlerPtr se)
|
||||
: file_analysis::Analyzer(file_mgr->GetComponentTag("DATA_EVENT"), std::move(args), file),
|
||||
chunk_event(ce), stream_event(se)
|
||||
{
|
||||
}
|
||||
DataEvent::DataEvent(RecordValPtr args, file_analysis::File* file, EventHandlerPtr ce, EventHandlerPtr se)
|
||||
: file_analysis::Analyzer(file_mgr->GetComponentTag("DATA_EVENT"), std::move(args), file),
|
||||
chunk_event(ce),
|
||||
stream_event(se) {}
|
||||
|
||||
file_analysis::Analyzer* DataEvent::Instantiate(RecordValPtr args, file_analysis::File* file)
|
||||
{
|
||||
const auto& chunk_val = args->GetField("chunk_event");
|
||||
const auto& stream_val = args->GetField("stream_event");
|
||||
file_analysis::Analyzer* DataEvent::Instantiate(RecordValPtr args, file_analysis::File* file) {
|
||||
const auto& chunk_val = args->GetField("chunk_event");
|
||||
const auto& stream_val = args->GetField("stream_event");
|
||||
|
||||
if ( ! chunk_val && ! stream_val )
|
||||
return nullptr;
|
||||
if ( ! chunk_val && ! stream_val )
|
||||
return nullptr;
|
||||
|
||||
EventHandlerPtr chunk;
|
||||
EventHandlerPtr stream;
|
||||
EventHandlerPtr chunk;
|
||||
EventHandlerPtr stream;
|
||||
|
||||
if ( chunk_val )
|
||||
chunk = event_registry->Lookup(chunk_val->AsFunc()->Name());
|
||||
if ( chunk_val )
|
||||
chunk = event_registry->Lookup(chunk_val->AsFunc()->Name());
|
||||
|
||||
if ( stream_val )
|
||||
stream = event_registry->Lookup(stream_val->AsFunc()->Name());
|
||||
if ( stream_val )
|
||||
stream = event_registry->Lookup(stream_val->AsFunc()->Name());
|
||||
|
||||
return new DataEvent(std::move(args), file, chunk, stream);
|
||||
}
|
||||
return new DataEvent(std::move(args), file, chunk, stream);
|
||||
}
|
||||
|
||||
bool DataEvent::DeliverChunk(const u_char* data, uint64_t len, uint64_t offset)
|
||||
{
|
||||
if ( ! chunk_event )
|
||||
return true;
|
||||
bool DataEvent::DeliverChunk(const u_char* data, uint64_t len, uint64_t offset) {
|
||||
if ( ! chunk_event )
|
||||
return true;
|
||||
|
||||
event_mgr.Enqueue(chunk_event, GetFile()->ToVal(),
|
||||
make_intrusive<StringVal>(new String(data, len, false)),
|
||||
val_mgr->Count(offset));
|
||||
event_mgr.Enqueue(chunk_event, GetFile()->ToVal(), make_intrusive<StringVal>(new String(data, len, false)),
|
||||
val_mgr->Count(offset));
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DataEvent::DeliverStream(const u_char* data, uint64_t len)
|
||||
{
|
||||
if ( ! stream_event )
|
||||
return true;
|
||||
bool DataEvent::DeliverStream(const u_char* data, uint64_t len) {
|
||||
if ( ! stream_event )
|
||||
return true;
|
||||
|
||||
event_mgr.Enqueue(stream_event, GetFile()->ToVal(),
|
||||
make_intrusive<StringVal>(new String(data, len, false)));
|
||||
event_mgr.Enqueue(stream_event, GetFile()->ToVal(), make_intrusive<StringVal>(new String(data, len, false)));
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace zeek::file_analysis::detail
|
||||
} // namespace zeek::file_analysis::detail
|
||||
|
|
|
@ -9,58 +9,56 @@
|
|||
#include "zeek/file_analysis/Analyzer.h"
|
||||
#include "zeek/file_analysis/File.h"
|
||||
|
||||
namespace zeek::file_analysis::detail
|
||||
{
|
||||
namespace zeek::file_analysis::detail {
|
||||
|
||||
/**
|
||||
* An analyzer to send file data to script-layer via events.
|
||||
*/
|
||||
class DataEvent : public file_analysis::Analyzer
|
||||
{
|
||||
class DataEvent : public file_analysis::Analyzer {
|
||||
public:
|
||||
/**
|
||||
* Generates the event, if any, specified by the "chunk_event" field of this
|
||||
* analyzer's \c AnalyzerArgs. This is for non-sequential file data input.
|
||||
* @param data pointer to start of file data chunk.
|
||||
* @param len number of bytes in the data chunk.
|
||||
* @param offset number of bytes from start of file at which chunk occurs.
|
||||
* @return always true
|
||||
*/
|
||||
bool DeliverChunk(const u_char* data, uint64_t len, uint64_t offset) override;
|
||||
/**
|
||||
* Generates the event, if any, specified by the "chunk_event" field of this
|
||||
* analyzer's \c AnalyzerArgs. This is for non-sequential file data input.
|
||||
* @param data pointer to start of file data chunk.
|
||||
* @param len number of bytes in the data chunk.
|
||||
* @param offset number of bytes from start of file at which chunk occurs.
|
||||
* @return always true
|
||||
*/
|
||||
bool DeliverChunk(const u_char* data, uint64_t len, uint64_t offset) override;
|
||||
|
||||
/**
|
||||
* Generates the event, if any, specified by the "stream_event" field of
|
||||
* this analyzer's \c AnalyzerArgs. This is for sequential file data input.
|
||||
* @param data pointer to start of file data chunk.
|
||||
* @param len number of bytes in the data chunk.
|
||||
* @return always true
|
||||
*/
|
||||
bool DeliverStream(const u_char* data, uint64_t len) override;
|
||||
/**
|
||||
* Generates the event, if any, specified by the "stream_event" field of
|
||||
* this analyzer's \c AnalyzerArgs. This is for sequential file data input.
|
||||
* @param data pointer to start of file data chunk.
|
||||
* @param len number of bytes in the data chunk.
|
||||
* @return always true
|
||||
*/
|
||||
bool DeliverStream(const u_char* data, uint64_t len) override;
|
||||
|
||||
/**
|
||||
* Create a new instance of a DataEvent analyzer.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @return the new DataEvent analyzer instance or a null pointer if
|
||||
* no "chunk_event" or "stream_event" field was specified in \a args.
|
||||
*/
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file);
|
||||
/**
|
||||
* Create a new instance of a DataEvent analyzer.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @return the new DataEvent analyzer instance or a null pointer if
|
||||
* no "chunk_event" or "stream_event" field was specified in \a args.
|
||||
*/
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @param ce pointer to event handler which will be called to receive
|
||||
* non-sequential file data.
|
||||
* @param se pointer to event handler which will be called to receive
|
||||
* sequential file data.
|
||||
*/
|
||||
DataEvent(RecordValPtr args, file_analysis::File* file, EventHandlerPtr ce, EventHandlerPtr se);
|
||||
/**
|
||||
* Constructor.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @param ce pointer to event handler which will be called to receive
|
||||
* non-sequential file data.
|
||||
* @param se pointer to event handler which will be called to receive
|
||||
* sequential file data.
|
||||
*/
|
||||
DataEvent(RecordValPtr args, file_analysis::File* file, EventHandlerPtr ce, EventHandlerPtr se);
|
||||
|
||||
private:
|
||||
EventHandlerPtr chunk_event;
|
||||
EventHandlerPtr stream_event;
|
||||
};
|
||||
EventHandlerPtr chunk_event;
|
||||
EventHandlerPtr stream_event;
|
||||
};
|
||||
|
||||
} // namespace zeek::file_analysis::detail
|
||||
} // namespace zeek::file_analysis::detail
|
||||
|
|
|
@ -5,22 +5,19 @@
|
|||
#include "zeek/file_analysis/Component.h"
|
||||
#include "zeek/file_analysis/analyzer/data_event/DataEvent.h"
|
||||
|
||||
namespace zeek::plugin::detail::Zeek_FileDataEvent
|
||||
{
|
||||
namespace zeek::plugin::detail::Zeek_FileDataEvent {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::file_analysis::Component(
|
||||
"DATA_EVENT", zeek::file_analysis::detail::DataEvent::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(
|
||||
new zeek::file_analysis::Component("DATA_EVENT", zeek::file_analysis::detail::DataEvent::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::FileDataEvent";
|
||||
config.description = "Delivers file content";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::FileDataEvent";
|
||||
config.description = "Delivers file content";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
|
||||
} // namespace zeek::plugin::detail::Zeek_FileDataEvent
|
||||
} // namespace zeek::plugin::detail::Zeek_FileDataEvent
|
||||
|
|
|
@ -8,67 +8,55 @@
|
|||
#include "zeek/file_analysis/Manager.h"
|
||||
#include "zeek/util.h"
|
||||
|
||||
namespace zeek::file_analysis::detail
|
||||
{
|
||||
namespace zeek::file_analysis::detail {
|
||||
|
||||
Entropy::Entropy(RecordValPtr args, file_analysis::File* file)
|
||||
: file_analysis::Analyzer(file_mgr->GetComponentTag("ENTROPY"), std::move(args), file)
|
||||
{
|
||||
entropy = new EntropyVal;
|
||||
fed = false;
|
||||
}
|
||||
: file_analysis::Analyzer(file_mgr->GetComponentTag("ENTROPY"), std::move(args), file) {
|
||||
entropy = new EntropyVal;
|
||||
fed = false;
|
||||
}
|
||||
|
||||
Entropy::~Entropy()
|
||||
{
|
||||
Unref(entropy);
|
||||
}
|
||||
Entropy::~Entropy() { Unref(entropy); }
|
||||
|
||||
file_analysis::Analyzer* Entropy::Instantiate(RecordValPtr args, file_analysis::File* file)
|
||||
{
|
||||
return new Entropy(std::move(args), file);
|
||||
}
|
||||
file_analysis::Analyzer* Entropy::Instantiate(RecordValPtr args, file_analysis::File* file) {
|
||||
return new Entropy(std::move(args), file);
|
||||
}
|
||||
|
||||
bool Entropy::DeliverStream(const u_char* data, uint64_t len)
|
||||
{
|
||||
if ( ! fed )
|
||||
fed = len > 0;
|
||||
bool Entropy::DeliverStream(const u_char* data, uint64_t len) {
|
||||
if ( ! fed )
|
||||
fed = len > 0;
|
||||
|
||||
entropy->Feed(data, len);
|
||||
return true;
|
||||
}
|
||||
entropy->Feed(data, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Entropy::EndOfFile()
|
||||
{
|
||||
Finalize();
|
||||
return false;
|
||||
}
|
||||
bool Entropy::EndOfFile() {
|
||||
Finalize();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Entropy::Undelivered(uint64_t offset, uint64_t len)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool Entropy::Undelivered(uint64_t offset, uint64_t len) { return false; }
|
||||
|
||||
void Entropy::Finalize()
|
||||
{
|
||||
if ( ! fed )
|
||||
return;
|
||||
void Entropy::Finalize() {
|
||||
if ( ! fed )
|
||||
return;
|
||||
|
||||
if ( ! file_entropy )
|
||||
return;
|
||||
if ( ! file_entropy )
|
||||
return;
|
||||
|
||||
double montepi, scc, ent, mean, chisq;
|
||||
montepi = scc = ent = mean = chisq = 0.0;
|
||||
entropy->Get(&ent, &chisq, &mean, &montepi, &scc);
|
||||
double montepi, scc, ent, mean, chisq;
|
||||
montepi = scc = ent = mean = chisq = 0.0;
|
||||
entropy->Get(&ent, &chisq, &mean, &montepi, &scc);
|
||||
|
||||
static auto entropy_test_result = id::find_type<RecordType>("entropy_test_result");
|
||||
auto ent_result = make_intrusive<RecordVal>(entropy_test_result);
|
||||
ent_result->Assign(0, ent);
|
||||
ent_result->Assign(1, chisq);
|
||||
ent_result->Assign(2, mean);
|
||||
ent_result->Assign(3, montepi);
|
||||
ent_result->Assign(4, scc);
|
||||
static auto entropy_test_result = id::find_type<RecordType>("entropy_test_result");
|
||||
auto ent_result = make_intrusive<RecordVal>(entropy_test_result);
|
||||
ent_result->Assign(0, ent);
|
||||
ent_result->Assign(1, chisq);
|
||||
ent_result->Assign(2, mean);
|
||||
ent_result->Assign(3, montepi);
|
||||
ent_result->Assign(4, scc);
|
||||
|
||||
event_mgr.Enqueue(file_entropy, GetFile()->ToVal(), std::move(ent_result));
|
||||
}
|
||||
event_mgr.Enqueue(file_entropy, GetFile()->ToVal(), std::move(ent_result));
|
||||
}
|
||||
|
||||
} // namespace zeek::file_analysis::detail
|
||||
} // namespace zeek::file_analysis::detail
|
||||
|
|
|
@ -10,71 +10,69 @@
|
|||
#include "zeek/file_analysis/File.h"
|
||||
#include "zeek/file_analysis/analyzer/entropy/events.bif.h"
|
||||
|
||||
namespace zeek::file_analysis::detail
|
||||
{
|
||||
namespace zeek::file_analysis::detail {
|
||||
|
||||
/**
|
||||
* An analyzer to produce entropy of file contents.
|
||||
*/
|
||||
class Entropy : public file_analysis::Analyzer
|
||||
{
|
||||
class Entropy : public file_analysis::Analyzer {
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~Entropy() override;
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~Entropy() override;
|
||||
|
||||
/**
|
||||
* Create a new instance of an Entropy analyzer.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @return the new Entropy analyzer instance or a null pointer if the
|
||||
* the "extraction_file" field of \a args wasn't set.
|
||||
*/
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file);
|
||||
/**
|
||||
* Create a new instance of an Entropy analyzer.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @return the new Entropy analyzer instance or a null pointer if the
|
||||
* the "extraction_file" field of \a args wasn't set.
|
||||
*/
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file);
|
||||
|
||||
/**
|
||||
* Calculate entropy of next chunk of file contents.
|
||||
* @param data pointer to start of a chunk of a file data.
|
||||
* @param len number of bytes in the data chunk.
|
||||
* @return false if the digest is in an invalid state, else true.
|
||||
*/
|
||||
bool DeliverStream(const u_char* data, uint64_t len) override;
|
||||
/**
|
||||
* Calculate entropy of next chunk of file contents.
|
||||
* @param data pointer to start of a chunk of a file data.
|
||||
* @param len number of bytes in the data chunk.
|
||||
* @return false if the digest is in an invalid state, else true.
|
||||
*/
|
||||
bool DeliverStream(const u_char* data, uint64_t len) override;
|
||||
|
||||
/**
|
||||
* Finalizes the calculation and raises a "file_entropy_test" event.
|
||||
* @return always false so analyze will be detached from file.
|
||||
*/
|
||||
bool EndOfFile() override;
|
||||
/**
|
||||
* Finalizes the calculation and raises a "file_entropy_test" event.
|
||||
* @return always false so analyze will be detached from file.
|
||||
*/
|
||||
bool EndOfFile() override;
|
||||
|
||||
/**
|
||||
* Missing data can't be handled, so just indicate the this analyzer should
|
||||
* be removed from receiving further data. The entropy will not be finalized.
|
||||
* @param offset byte offset in file at which missing chunk starts.
|
||||
* @param len number of missing bytes.
|
||||
* @return always false so analyzer will detach from file.
|
||||
*/
|
||||
bool Undelivered(uint64_t offset, uint64_t len) override;
|
||||
/**
|
||||
* Missing data can't be handled, so just indicate the this analyzer should
|
||||
* be removed from receiving further data. The entropy will not be finalized.
|
||||
* @param offset byte offset in file at which missing chunk starts.
|
||||
* @param len number of missing bytes.
|
||||
* @return always false so analyzer will detach from file.
|
||||
*/
|
||||
bool Undelivered(uint64_t offset, uint64_t len) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @param hv specific hash calculator object.
|
||||
* @param kind human readable name of the hash algorithm to use.
|
||||
*/
|
||||
Entropy(RecordValPtr args, file_analysis::File* file);
|
||||
/**
|
||||
* Constructor.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @param hv specific hash calculator object.
|
||||
* @param kind human readable name of the hash algorithm to use.
|
||||
*/
|
||||
Entropy(RecordValPtr args, file_analysis::File* file);
|
||||
|
||||
/**
|
||||
* If some file contents have been seen, finalizes the entropy of them and
|
||||
* raises the "file_entropy" event with the results.
|
||||
*/
|
||||
void Finalize();
|
||||
/**
|
||||
* If some file contents have been seen, finalizes the entropy of them and
|
||||
* raises the "file_entropy" event with the results.
|
||||
*/
|
||||
void Finalize();
|
||||
|
||||
private:
|
||||
EntropyVal* entropy;
|
||||
bool fed;
|
||||
};
|
||||
EntropyVal* entropy;
|
||||
bool fed;
|
||||
};
|
||||
|
||||
} // namespace zeek::file_analysis::detail
|
||||
} // namespace zeek::file_analysis::detail
|
||||
|
|
|
@ -5,22 +5,18 @@
|
|||
#include "zeek/file_analysis/Component.h"
|
||||
#include "zeek/file_analysis/analyzer/entropy/Entropy.h"
|
||||
|
||||
namespace zeek::plugin::detail::Zeek_FileEntropy
|
||||
{
|
||||
namespace zeek::plugin::detail::Zeek_FileEntropy {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::file_analysis::Component(
|
||||
"ENTROPY", zeek::file_analysis::detail::Entropy::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(new zeek::file_analysis::Component("ENTROPY", zeek::file_analysis::detail::Entropy::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::FileEntropy";
|
||||
config.description = "Entropy test file content";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::FileEntropy";
|
||||
config.description = "Entropy test file content";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
|
||||
} // namespace zeek::plugin::detail::Zeek_FileEntropy
|
||||
} // namespace zeek::plugin::detail::Zeek_FileEntropy
|
||||
|
|
|
@ -9,67 +9,59 @@
|
|||
#include "zeek/file_analysis/Manager.h"
|
||||
#include "zeek/util.h"
|
||||
|
||||
namespace zeek::file_analysis::detail
|
||||
{
|
||||
namespace zeek::file_analysis::detail {
|
||||
|
||||
Extract::Extract(RecordValPtr args, file_analysis::File* file, const std::string& arg_filename,
|
||||
uint64_t arg_limit, bool arg_limit_includes_missing)
|
||||
: file_analysis::Analyzer(file_mgr->GetComponentTag("EXTRACT"), std::move(args), file),
|
||||
filename(arg_filename), limit(arg_limit), written(0),
|
||||
limit_includes_missing(arg_limit_includes_missing)
|
||||
{
|
||||
char buf[128];
|
||||
file_stream = fopen(filename.data(), "wb");
|
||||
Extract::Extract(RecordValPtr args, file_analysis::File* file, const std::string& arg_filename, uint64_t arg_limit,
|
||||
bool arg_limit_includes_missing)
|
||||
: file_analysis::Analyzer(file_mgr->GetComponentTag("EXTRACT"), std::move(args), file),
|
||||
filename(arg_filename),
|
||||
limit(arg_limit),
|
||||
written(0),
|
||||
limit_includes_missing(arg_limit_includes_missing) {
|
||||
char buf[128];
|
||||
file_stream = fopen(filename.data(), "wb");
|
||||
|
||||
if ( file_stream )
|
||||
{
|
||||
// Try to ensure full buffering.
|
||||
if ( util::detail::setvbuf(file_stream, nullptr, _IOFBF, BUFSIZ) )
|
||||
{
|
||||
util::zeek_strerror_r(errno, buf, sizeof(buf));
|
||||
reporter->Warning("cannot set buffering mode for %s: %s", filename.data(), buf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
util::zeek_strerror_r(errno, buf, sizeof(buf));
|
||||
reporter->Error("cannot open %s: %s", filename.c_str(), buf);
|
||||
}
|
||||
}
|
||||
if ( file_stream ) {
|
||||
// Try to ensure full buffering.
|
||||
if ( util::detail::setvbuf(file_stream, nullptr, _IOFBF, BUFSIZ) ) {
|
||||
util::zeek_strerror_r(errno, buf, sizeof(buf));
|
||||
reporter->Warning("cannot set buffering mode for %s: %s", filename.data(), buf);
|
||||
}
|
||||
}
|
||||
else {
|
||||
util::zeek_strerror_r(errno, buf, sizeof(buf));
|
||||
reporter->Error("cannot open %s: %s", filename.c_str(), buf);
|
||||
}
|
||||
}
|
||||
|
||||
Extract::~Extract()
|
||||
{
|
||||
if ( file_stream && fclose(file_stream) )
|
||||
{
|
||||
char buf[128];
|
||||
util::zeek_strerror_r(errno, buf, sizeof(buf));
|
||||
reporter->Error("cannot close %s: %s", filename.data(), buf);
|
||||
}
|
||||
}
|
||||
Extract::~Extract() {
|
||||
if ( file_stream && fclose(file_stream) ) {
|
||||
char buf[128];
|
||||
util::zeek_strerror_r(errno, buf, sizeof(buf));
|
||||
reporter->Error("cannot close %s: %s", filename.data(), buf);
|
||||
}
|
||||
}
|
||||
|
||||
static ValPtr get_extract_field_val(const RecordValPtr& args, const char* name)
|
||||
{
|
||||
const auto& rval = args->GetField(name);
|
||||
static ValPtr get_extract_field_val(const RecordValPtr& args, const char* name) {
|
||||
const auto& rval = args->GetField(name);
|
||||
|
||||
if ( ! rval )
|
||||
reporter->Error("File extraction analyzer missing arg field: %s", name);
|
||||
if ( ! rval )
|
||||
reporter->Error("File extraction analyzer missing arg field: %s", name);
|
||||
|
||||
return rval;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
file_analysis::Analyzer* Extract::Instantiate(RecordValPtr args, file_analysis::File* file)
|
||||
{
|
||||
const auto& fname = get_extract_field_val(args, "extract_filename");
|
||||
const auto& limit = get_extract_field_val(args, "extract_limit");
|
||||
const auto& extract_limit_includes_missing = get_extract_field_val(
|
||||
args, "extract_limit_includes_missing");
|
||||
file_analysis::Analyzer* Extract::Instantiate(RecordValPtr args, file_analysis::File* file) {
|
||||
const auto& fname = get_extract_field_val(args, "extract_filename");
|
||||
const auto& limit = get_extract_field_val(args, "extract_limit");
|
||||
const auto& extract_limit_includes_missing = get_extract_field_val(args, "extract_limit_includes_missing");
|
||||
|
||||
if ( ! fname || ! limit || ! extract_limit_includes_missing )
|
||||
return nullptr;
|
||||
if ( ! fname || ! limit || ! extract_limit_includes_missing )
|
||||
return nullptr;
|
||||
|
||||
return new Extract(std::move(args), file, fname->AsString()->CheckString(), limit->AsCount(),
|
||||
extract_limit_includes_missing->AsBool());
|
||||
}
|
||||
return new Extract(std::move(args), file, fname->AsString()->CheckString(), limit->AsCount(),
|
||||
extract_limit_includes_missing->AsBool());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are exceeding the write limit with this write.
|
||||
|
@ -79,118 +71,102 @@ file_analysis::Analyzer* Extract::Instantiate(RecordValPtr args, file_analysis::
|
|||
* @param n number of bytes to write to keep within limit
|
||||
* @returns true if limit exceeded
|
||||
*/
|
||||
static bool check_limit_exceeded(uint64_t lim, uint64_t written, uint64_t len, uint64_t* n)
|
||||
{
|
||||
if ( lim == 0 )
|
||||
{
|
||||
*n = len;
|
||||
return false;
|
||||
}
|
||||
static bool check_limit_exceeded(uint64_t lim, uint64_t written, uint64_t len, uint64_t* n) {
|
||||
if ( lim == 0 ) {
|
||||
*n = len;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( written >= lim )
|
||||
{
|
||||
*n = 0;
|
||||
return true;
|
||||
}
|
||||
else if ( written + len > lim )
|
||||
{
|
||||
*n = lim - written;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
*n = len;
|
||||
}
|
||||
if ( written >= lim ) {
|
||||
*n = 0;
|
||||
return true;
|
||||
}
|
||||
else if ( written + len > lim ) {
|
||||
*n = lim - written;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
*n = len;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Extract::DeliverStream(const u_char* data, uint64_t len)
|
||||
{
|
||||
if ( ! file_stream )
|
||||
return false;
|
||||
bool Extract::DeliverStream(const u_char* data, uint64_t len) {
|
||||
if ( ! file_stream )
|
||||
return false;
|
||||
|
||||
uint64_t towrite = 0;
|
||||
bool limit_exceeded = check_limit_exceeded(limit, written, len, &towrite);
|
||||
uint64_t towrite = 0;
|
||||
bool limit_exceeded = check_limit_exceeded(limit, written, len, &towrite);
|
||||
|
||||
if ( limit_exceeded && file_extraction_limit )
|
||||
{
|
||||
file_analysis::File* f = GetFile();
|
||||
f->FileEvent(file_extraction_limit,
|
||||
{f->ToVal(), GetArgs(), val_mgr->Count(limit), val_mgr->Count(len)});
|
||||
if ( limit_exceeded && file_extraction_limit ) {
|
||||
file_analysis::File* f = GetFile();
|
||||
f->FileEvent(file_extraction_limit, {f->ToVal(), GetArgs(), val_mgr->Count(limit), val_mgr->Count(len)});
|
||||
|
||||
// Limit may have been modified by a BIF, re-check it.
|
||||
limit_exceeded = check_limit_exceeded(limit, written, len, &towrite);
|
||||
}
|
||||
// Limit may have been modified by a BIF, re-check it.
|
||||
limit_exceeded = check_limit_exceeded(limit, written, len, &towrite);
|
||||
}
|
||||
|
||||
char buf[128];
|
||||
char buf[128];
|
||||
|
||||
if ( towrite > 0 )
|
||||
{
|
||||
if ( fwrite(data, towrite, 1, file_stream) != 1 )
|
||||
{
|
||||
util::zeek_strerror_r(errno, buf, sizeof(buf));
|
||||
reporter->Error("failed to write to extracted file %s: %s", filename.data(), buf);
|
||||
fclose(file_stream);
|
||||
file_stream = nullptr;
|
||||
return false;
|
||||
}
|
||||
if ( towrite > 0 ) {
|
||||
if ( fwrite(data, towrite, 1, file_stream) != 1 ) {
|
||||
util::zeek_strerror_r(errno, buf, sizeof(buf));
|
||||
reporter->Error("failed to write to extracted file %s: %s", filename.data(), buf);
|
||||
fclose(file_stream);
|
||||
file_stream = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
written += towrite;
|
||||
}
|
||||
written += towrite;
|
||||
}
|
||||
|
||||
// Assume we may not try to write anything more for a while due to reaching
|
||||
// the extraction limit and the file analysis File still proceeding to
|
||||
// do other analysis without destructing/closing this one until the very end,
|
||||
// so flush anything currently buffered.
|
||||
if ( limit_exceeded && fflush(file_stream) )
|
||||
{
|
||||
util::zeek_strerror_r(errno, buf, sizeof(buf));
|
||||
reporter->Warning("cannot fflush extracted file %s: %s", filename.data(), buf);
|
||||
}
|
||||
// Assume we may not try to write anything more for a while due to reaching
|
||||
// the extraction limit and the file analysis File still proceeding to
|
||||
// do other analysis without destructing/closing this one until the very end,
|
||||
// so flush anything currently buffered.
|
||||
if ( limit_exceeded && fflush(file_stream) ) {
|
||||
util::zeek_strerror_r(errno, buf, sizeof(buf));
|
||||
reporter->Warning("cannot fflush extracted file %s: %s", filename.data(), buf);
|
||||
}
|
||||
|
||||
return (! limit_exceeded);
|
||||
}
|
||||
return (! limit_exceeded);
|
||||
}
|
||||
|
||||
bool Extract::Undelivered(uint64_t offset, uint64_t len)
|
||||
{
|
||||
if ( ! file_stream )
|
||||
return false;
|
||||
bool Extract::Undelivered(uint64_t offset, uint64_t len) {
|
||||
if ( ! file_stream )
|
||||
return false;
|
||||
|
||||
if ( limit_includes_missing )
|
||||
{
|
||||
uint64_t towrite = 0;
|
||||
bool limit_exceeded = check_limit_exceeded(limit, written, len, &towrite);
|
||||
// if the limit is exceeded, we have to raise the event. This gives scripts the opportunity
|
||||
// to raise the limit.
|
||||
if ( limit_exceeded && file_extraction_limit )
|
||||
{
|
||||
file_analysis::File* f = GetFile();
|
||||
f->FileEvent(file_extraction_limit,
|
||||
{f->ToVal(), GetArgs(), val_mgr->Count(limit), val_mgr->Count(len)});
|
||||
// we have to check again if the limit is still exceedee
|
||||
limit_exceeded = check_limit_exceeded(limit, written, len, &towrite);
|
||||
}
|
||||
if ( limit_includes_missing ) {
|
||||
uint64_t towrite = 0;
|
||||
bool limit_exceeded = check_limit_exceeded(limit, written, len, &towrite);
|
||||
// if the limit is exceeded, we have to raise the event. This gives scripts the opportunity
|
||||
// to raise the limit.
|
||||
if ( limit_exceeded && file_extraction_limit ) {
|
||||
file_analysis::File* f = GetFile();
|
||||
f->FileEvent(file_extraction_limit, {f->ToVal(), GetArgs(), val_mgr->Count(limit), val_mgr->Count(len)});
|
||||
// we have to check again if the limit is still exceedee
|
||||
limit_exceeded = check_limit_exceeded(limit, written, len, &towrite);
|
||||
}
|
||||
|
||||
// if the limit is exceeded, abort and don't do anything - no reason to seek.
|
||||
if ( limit_exceeded )
|
||||
return false;
|
||||
// if the limit is exceeded, abort and don't do anything - no reason to seek.
|
||||
if ( limit_exceeded )
|
||||
return false;
|
||||
|
||||
// if we don't skip holes, count this hole against the write limit
|
||||
written += len;
|
||||
}
|
||||
// if we don't skip holes, count this hole against the write limit
|
||||
written += len;
|
||||
}
|
||||
|
||||
if ( fseek(file_stream, len + offset, SEEK_SET) != 0 )
|
||||
{
|
||||
char buf[128];
|
||||
util::zeek_strerror_r(errno, buf, sizeof(buf));
|
||||
reporter->Error("failed to seek in extracted file %s: %s", filename.data(), buf);
|
||||
fclose(file_stream);
|
||||
file_stream = nullptr;
|
||||
return false;
|
||||
}
|
||||
if ( fseek(file_stream, len + offset, SEEK_SET) != 0 ) {
|
||||
char buf[128];
|
||||
util::zeek_strerror_r(errno, buf, sizeof(buf));
|
||||
reporter->Error("failed to seek in extracted file %s: %s", filename.data(), buf);
|
||||
fclose(file_stream);
|
||||
file_stream = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace zeek::file_analysis::detail
|
||||
} // namespace zeek::file_analysis::detail
|
||||
|
|
|
@ -10,72 +10,70 @@
|
|||
#include "zeek/file_analysis/File.h"
|
||||
#include "zeek/file_analysis/analyzer/extract/events.bif.h"
|
||||
|
||||
namespace zeek::file_analysis::detail
|
||||
{
|
||||
namespace zeek::file_analysis::detail {
|
||||
|
||||
/**
|
||||
* An analyzer to extract content of files to local disk.
|
||||
*/
|
||||
class Extract : public file_analysis::Analyzer
|
||||
{
|
||||
class Extract : public file_analysis::Analyzer {
|
||||
public:
|
||||
/**
|
||||
* Destructor. Will close the file that was used for data extraction.
|
||||
*/
|
||||
~Extract() override;
|
||||
/**
|
||||
* Destructor. Will close the file that was used for data extraction.
|
||||
*/
|
||||
~Extract() override;
|
||||
|
||||
/**
|
||||
* Write a chunk of file data to the local extraction file.
|
||||
* @param data pointer to a chunk of file data.
|
||||
* @param len number of bytes in the data chunk.
|
||||
* @return false if there was no extraction file open and the data couldn't
|
||||
* be written, else true.
|
||||
*/
|
||||
bool DeliverStream(const u_char* data, uint64_t len) override;
|
||||
/**
|
||||
* Write a chunk of file data to the local extraction file.
|
||||
* @param data pointer to a chunk of file data.
|
||||
* @param len number of bytes in the data chunk.
|
||||
* @return false if there was no extraction file open and the data couldn't
|
||||
* be written, else true.
|
||||
*/
|
||||
bool DeliverStream(const u_char* data, uint64_t len) override;
|
||||
|
||||
/**
|
||||
* Report undelivered bytes.
|
||||
* @param offset distance into the file where the gap occurred.
|
||||
* @param len number of bytes undelivered.
|
||||
* @return true
|
||||
*/
|
||||
bool Undelivered(uint64_t offset, uint64_t len) override;
|
||||
/**
|
||||
* Report undelivered bytes.
|
||||
* @param offset distance into the file where the gap occurred.
|
||||
* @param len number of bytes undelivered.
|
||||
* @return true
|
||||
*/
|
||||
bool Undelivered(uint64_t offset, uint64_t len) override;
|
||||
|
||||
/**
|
||||
* Create a new instance of an Extract analyzer.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @return the new Extract analyzer instance or a null pointer if the
|
||||
* the "extraction_file" field of \a args wasn't set.
|
||||
*/
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file);
|
||||
/**
|
||||
* Create a new instance of an Extract analyzer.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @return the new Extract analyzer instance or a null pointer if the
|
||||
* the "extraction_file" field of \a args wasn't set.
|
||||
*/
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file);
|
||||
|
||||
/**
|
||||
* Sets the maximum allowed extracted file size. A value of zero means
|
||||
* "no limit".
|
||||
* @param bytes number of bytes allowed to be extracted
|
||||
*/
|
||||
void SetLimit(uint64_t bytes) { limit = bytes; }
|
||||
/**
|
||||
* Sets the maximum allowed extracted file size. A value of zero means
|
||||
* "no limit".
|
||||
* @param bytes number of bytes allowed to be extracted
|
||||
*/
|
||||
void SetLimit(uint64_t bytes) { limit = bytes; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @param arg_filename a file system path which specifies the local file
|
||||
* to which the contents of the file will be extracted/written.
|
||||
* @param arg_limit the maximum allowed file size.
|
||||
* @param arg_limit_includes_missing missing bytes count towards limit if true.
|
||||
*/
|
||||
Extract(RecordValPtr args, file_analysis::File* file, const std::string& arg_filename,
|
||||
uint64_t arg_limit, bool arg_limit_includes_missing);
|
||||
/**
|
||||
* Constructor.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @param arg_filename a file system path which specifies the local file
|
||||
* to which the contents of the file will be extracted/written.
|
||||
* @param arg_limit the maximum allowed file size.
|
||||
* @param arg_limit_includes_missing missing bytes count towards limit if true.
|
||||
*/
|
||||
Extract(RecordValPtr args, file_analysis::File* file, const std::string& arg_filename, uint64_t arg_limit,
|
||||
bool arg_limit_includes_missing);
|
||||
|
||||
private:
|
||||
std::string filename;
|
||||
FILE* file_stream;
|
||||
uint64_t limit; // the file extraction limit
|
||||
uint64_t written; // how many bytes we have written so far
|
||||
bool limit_includes_missing; // do count missing bytes against limit if true
|
||||
};
|
||||
std::string filename;
|
||||
FILE* file_stream;
|
||||
uint64_t limit; // the file extraction limit
|
||||
uint64_t written; // how many bytes we have written so far
|
||||
bool limit_includes_missing; // do count missing bytes against limit if true
|
||||
};
|
||||
|
||||
} // namespace zeek::file_analysis::detail
|
||||
} // namespace zeek::file_analysis::detail
|
||||
|
|
|
@ -5,22 +5,18 @@
|
|||
#include "zeek/file_analysis/Component.h"
|
||||
#include "zeek/file_analysis/analyzer/extract/Extract.h"
|
||||
|
||||
namespace zeek::plugin::detail::Zeek_FileExtract
|
||||
{
|
||||
namespace zeek::plugin::detail::Zeek_FileExtract {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::file_analysis::Component(
|
||||
"EXTRACT", zeek::file_analysis::detail::Extract::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(new zeek::file_analysis::Component("EXTRACT", zeek::file_analysis::detail::Extract::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::FileExtract";
|
||||
config.description = "Extract file content";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::FileExtract";
|
||||
config.description = "Extract file content";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
|
||||
} // namespace zeek::plugin::detail::Zeek_FileExtract
|
||||
} // namespace zeek::plugin::detail::Zeek_FileExtract
|
||||
|
|
|
@ -8,58 +8,49 @@
|
|||
#include "zeek/file_analysis/Manager.h"
|
||||
#include "zeek/util.h"
|
||||
|
||||
namespace zeek::file_analysis::detail
|
||||
{
|
||||
namespace zeek::file_analysis::detail {
|
||||
|
||||
StringValPtr MD5::kind_val = make_intrusive<StringVal>("md5");
|
||||
StringValPtr SHA1::kind_val = make_intrusive<StringVal>("sha1");
|
||||
StringValPtr SHA256::kind_val = make_intrusive<StringVal>("sha256");
|
||||
|
||||
Hash::Hash(RecordValPtr args, file_analysis::File* file, HashVal* hv, StringValPtr arg_kind)
|
||||
: file_analysis::Analyzer(file_mgr->GetComponentTag(util::to_upper(arg_kind->ToStdString())),
|
||||
std::move(args), file),
|
||||
hash(hv), fed(false), kind(std::move(arg_kind))
|
||||
{
|
||||
hash->Init();
|
||||
}
|
||||
: file_analysis::Analyzer(file_mgr->GetComponentTag(util::to_upper(arg_kind->ToStdString())), std::move(args),
|
||||
file),
|
||||
hash(hv),
|
||||
fed(false),
|
||||
kind(std::move(arg_kind)) {
|
||||
hash->Init();
|
||||
}
|
||||
|
||||
Hash::~Hash()
|
||||
{
|
||||
Unref(hash);
|
||||
}
|
||||
Hash::~Hash() { Unref(hash); }
|
||||
|
||||
bool Hash::DeliverStream(const u_char* data, uint64_t len)
|
||||
{
|
||||
if ( ! hash->IsValid() )
|
||||
return false;
|
||||
bool Hash::DeliverStream(const u_char* data, uint64_t len) {
|
||||
if ( ! hash->IsValid() )
|
||||
return false;
|
||||
|
||||
if ( ! fed )
|
||||
fed = len > 0;
|
||||
if ( ! fed )
|
||||
fed = len > 0;
|
||||
|
||||
hash->Feed(data, len);
|
||||
return true;
|
||||
}
|
||||
hash->Feed(data, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Hash::EndOfFile()
|
||||
{
|
||||
Finalize();
|
||||
return false;
|
||||
}
|
||||
bool Hash::EndOfFile() {
|
||||
Finalize();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Hash::Undelivered(uint64_t offset, uint64_t len)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool Hash::Undelivered(uint64_t offset, uint64_t len) { return false; }
|
||||
|
||||
void Hash::Finalize()
|
||||
{
|
||||
if ( ! hash->IsValid() || ! fed )
|
||||
return;
|
||||
void Hash::Finalize() {
|
||||
if ( ! hash->IsValid() || ! fed )
|
||||
return;
|
||||
|
||||
if ( ! file_hash )
|
||||
return;
|
||||
if ( ! file_hash )
|
||||
return;
|
||||
|
||||
event_mgr.Enqueue(file_hash, GetFile()->ToVal(), kind, hash->Get());
|
||||
}
|
||||
event_mgr.Enqueue(file_hash, GetFile()->ToVal(), kind, hash->Get());
|
||||
}
|
||||
|
||||
} // namespace zeek::file_analysis::detail
|
||||
} // namespace zeek::file_analysis::detail
|
||||
|
|
|
@ -10,159 +10,143 @@
|
|||
#include "zeek/file_analysis/File.h"
|
||||
#include "zeek/file_analysis/analyzer/hash/events.bif.h"
|
||||
|
||||
namespace zeek::file_analysis::detail
|
||||
{
|
||||
namespace zeek::file_analysis::detail {
|
||||
|
||||
/**
|
||||
* An analyzer to produce a hash of file contents.
|
||||
*/
|
||||
class Hash : public file_analysis::Analyzer
|
||||
{
|
||||
class Hash : public file_analysis::Analyzer {
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~Hash() override;
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~Hash() override;
|
||||
|
||||
/**
|
||||
* Incrementally hash next chunk of file contents.
|
||||
* @param data pointer to start of a chunk of a file data.
|
||||
* @param len number of bytes in the data chunk.
|
||||
* @return false if the digest is in an invalid state, else true.
|
||||
*/
|
||||
bool DeliverStream(const u_char* data, uint64_t len) override;
|
||||
/**
|
||||
* Incrementally hash next chunk of file contents.
|
||||
* @param data pointer to start of a chunk of a file data.
|
||||
* @param len number of bytes in the data chunk.
|
||||
* @return false if the digest is in an invalid state, else true.
|
||||
*/
|
||||
bool DeliverStream(const u_char* data, uint64_t len) override;
|
||||
|
||||
/**
|
||||
* Finalizes the hash and raises a "file_hash" event.
|
||||
* @return always false so analyze will be detached from file.
|
||||
*/
|
||||
bool EndOfFile() override;
|
||||
/**
|
||||
* Finalizes the hash and raises a "file_hash" event.
|
||||
* @return always false so analyze will be detached from file.
|
||||
*/
|
||||
bool EndOfFile() override;
|
||||
|
||||
/**
|
||||
* Missing data can't be handled, so just indicate the this analyzer should
|
||||
* be removed from receiving further data. The hash will not be finalized.
|
||||
* @param offset byte offset in file at which missing chunk starts.
|
||||
* @param len number of missing bytes.
|
||||
* @return always false so analyzer will detach from file.
|
||||
*/
|
||||
bool Undelivered(uint64_t offset, uint64_t len) override;
|
||||
/**
|
||||
* Missing data can't be handled, so just indicate the this analyzer should
|
||||
* be removed from receiving further data. The hash will not be finalized.
|
||||
* @param offset byte offset in file at which missing chunk starts.
|
||||
* @param len number of missing bytes.
|
||||
* @return always false so analyzer will detach from file.
|
||||
*/
|
||||
bool Undelivered(uint64_t offset, uint64_t len) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @param hv specific hash calculator object.
|
||||
* @param kind human readable name of the hash algorithm to use.
|
||||
*/
|
||||
Hash(RecordValPtr args, file_analysis::File* file, HashVal* hv, StringValPtr kind);
|
||||
/**
|
||||
* Constructor.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @param hv specific hash calculator object.
|
||||
* @param kind human readable name of the hash algorithm to use.
|
||||
*/
|
||||
Hash(RecordValPtr args, file_analysis::File* file, HashVal* hv, StringValPtr kind);
|
||||
|
||||
/**
|
||||
* If some file contents have been seen, finalizes the hash of them and
|
||||
* raises the "file_hash" event with the results.
|
||||
*/
|
||||
void Finalize();
|
||||
/**
|
||||
* If some file contents have been seen, finalizes the hash of them and
|
||||
* raises the "file_hash" event with the results.
|
||||
*/
|
||||
void Finalize();
|
||||
|
||||
private:
|
||||
HashVal* hash;
|
||||
bool fed;
|
||||
StringValPtr kind;
|
||||
};
|
||||
HashVal* hash;
|
||||
bool fed;
|
||||
StringValPtr kind;
|
||||
};
|
||||
|
||||
/**
|
||||
* An analyzer to produce an MD5 hash of file contents.
|
||||
*/
|
||||
class MD5 final : public Hash
|
||||
{
|
||||
class MD5 final : public Hash {
|
||||
public:
|
||||
/**
|
||||
* Create a new instance of the MD5 hashing file analyzer.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @return the new MD5 analyzer instance or a null pointer if there's no
|
||||
* handler for the "file_hash" event.
|
||||
*/
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file)
|
||||
{
|
||||
return file_hash ? new MD5(std::move(args), file) : nullptr;
|
||||
}
|
||||
/**
|
||||
* Create a new instance of the MD5 hashing file analyzer.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @return the new MD5 analyzer instance or a null pointer if there's no
|
||||
* handler for the "file_hash" event.
|
||||
*/
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file) {
|
||||
return file_hash ? new MD5(std::move(args), file) : nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
*/
|
||||
MD5(RecordValPtr args, file_analysis::File* file)
|
||||
: Hash(std::move(args), file, new MD5Val(), MD5::kind_val)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Constructor.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
*/
|
||||
MD5(RecordValPtr args, file_analysis::File* file) : Hash(std::move(args), file, new MD5Val(), MD5::kind_val) {}
|
||||
|
||||
static StringValPtr kind_val;
|
||||
};
|
||||
static StringValPtr kind_val;
|
||||
};
|
||||
|
||||
/**
|
||||
* An analyzer to produce a SHA1 hash of file contents.
|
||||
*/
|
||||
class SHA1 final : public Hash
|
||||
{
|
||||
class SHA1 final : public Hash {
|
||||
public:
|
||||
/**
|
||||
* Create a new instance of the SHA1 hashing file analyzer.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @return the new MD5 analyzer instance or a null pointer if there's no
|
||||
* handler for the "file_hash" event.
|
||||
*/
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file)
|
||||
{
|
||||
return file_hash ? new SHA1(std::move(args), file) : nullptr;
|
||||
}
|
||||
/**
|
||||
* Create a new instance of the SHA1 hashing file analyzer.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @return the new MD5 analyzer instance or a null pointer if there's no
|
||||
* handler for the "file_hash" event.
|
||||
*/
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file) {
|
||||
return file_hash ? new SHA1(std::move(args), file) : nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
*/
|
||||
SHA1(RecordValPtr args, file_analysis::File* file)
|
||||
: Hash(std::move(args), file, new SHA1Val(), SHA1::kind_val)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Constructor.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
*/
|
||||
SHA1(RecordValPtr args, file_analysis::File* file) : Hash(std::move(args), file, new SHA1Val(), SHA1::kind_val) {}
|
||||
|
||||
static StringValPtr kind_val;
|
||||
};
|
||||
static StringValPtr kind_val;
|
||||
};
|
||||
|
||||
/**
|
||||
* An analyzer to produce a SHA256 hash of file contents.
|
||||
*/
|
||||
class SHA256 final : public Hash
|
||||
{
|
||||
class SHA256 final : public Hash {
|
||||
public:
|
||||
/**
|
||||
* Create a new instance of the SHA256 hashing file analyzer.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @return the new MD5 analyzer instance or a null pointer if there's no
|
||||
* handler for the "file_hash" event.
|
||||
*/
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file)
|
||||
{
|
||||
return file_hash ? new SHA256(std::move(args), file) : nullptr;
|
||||
}
|
||||
/**
|
||||
* Create a new instance of the SHA256 hashing file analyzer.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
* @return the new MD5 analyzer instance or a null pointer if there's no
|
||||
* handler for the "file_hash" event.
|
||||
*/
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file) {
|
||||
return file_hash ? new SHA256(std::move(args), file) : nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
*/
|
||||
SHA256(RecordValPtr args, file_analysis::File* file)
|
||||
: Hash(std::move(args), file, new SHA256Val(), SHA256::kind_val)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Constructor.
|
||||
* @param args the \c AnalyzerArgs value which represents the analyzer.
|
||||
* @param file the file to which the analyzer will be attached.
|
||||
*/
|
||||
SHA256(RecordValPtr args, file_analysis::File* file)
|
||||
: Hash(std::move(args), file, new SHA256Val(), SHA256::kind_val) {}
|
||||
|
||||
static StringValPtr kind_val;
|
||||
};
|
||||
static StringValPtr kind_val;
|
||||
};
|
||||
|
||||
} // namespace zeek::file_analysis
|
||||
} // namespace zeek::file_analysis::detail
|
||||
|
|
|
@ -5,26 +5,20 @@
|
|||
#include "zeek/file_analysis/Component.h"
|
||||
#include "zeek/file_analysis/analyzer/hash/Hash.h"
|
||||
|
||||
namespace zeek::plugin::detail::Zeek_FileHash
|
||||
{
|
||||
namespace zeek::plugin::detail::Zeek_FileHash {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::file_analysis::Component(
|
||||
"MD5", zeek::file_analysis::detail::MD5::Instantiate));
|
||||
AddComponent(new zeek::file_analysis::Component(
|
||||
"SHA1", zeek::file_analysis::detail::SHA1::Instantiate));
|
||||
AddComponent(new zeek::file_analysis::Component(
|
||||
"SHA256", zeek::file_analysis::detail::SHA256::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(new zeek::file_analysis::Component("MD5", zeek::file_analysis::detail::MD5::Instantiate));
|
||||
AddComponent(new zeek::file_analysis::Component("SHA1", zeek::file_analysis::detail::SHA1::Instantiate));
|
||||
AddComponent(new zeek::file_analysis::Component("SHA256", zeek::file_analysis::detail::SHA256::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::FileHash";
|
||||
config.description = "Hash file content";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::FileHash";
|
||||
config.description = "Hash file content";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
|
||||
} // namespace zeek::plugin::detail::Zeek_FileHash
|
||||
} // namespace zeek::plugin::detail::Zeek_FileHash
|
||||
|
|
|
@ -2,44 +2,34 @@
|
|||
|
||||
#include "zeek/file_analysis/Manager.h"
|
||||
|
||||
namespace zeek::file_analysis::detail
|
||||
{
|
||||
namespace zeek::file_analysis::detail {
|
||||
|
||||
PE::PE(RecordValPtr args, file_analysis::File* file)
|
||||
: file_analysis::Analyzer(file_mgr->GetComponentTag("PE"), std::move(args), file)
|
||||
{
|
||||
conn = new binpac::PE::MockConnection(this);
|
||||
interp = new binpac::PE::File(conn);
|
||||
done = false;
|
||||
}
|
||||
: file_analysis::Analyzer(file_mgr->GetComponentTag("PE"), std::move(args), file) {
|
||||
conn = new binpac::PE::MockConnection(this);
|
||||
interp = new binpac::PE::File(conn);
|
||||
done = false;
|
||||
}
|
||||
|
||||
PE::~PE()
|
||||
{
|
||||
delete interp;
|
||||
delete conn;
|
||||
}
|
||||
PE::~PE() {
|
||||
delete interp;
|
||||
delete conn;
|
||||
}
|
||||
|
||||
bool PE::DeliverStream(const u_char* data, uint64_t len)
|
||||
{
|
||||
if ( conn->is_done() )
|
||||
return false;
|
||||
bool PE::DeliverStream(const u_char* data, uint64_t len) {
|
||||
if ( conn->is_done() )
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
interp->NewData(data, data + len);
|
||||
}
|
||||
catch ( const binpac::Exception& e )
|
||||
{
|
||||
AnalyzerViolation(util::fmt("Binpac exception: %s", e.c_msg()));
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
interp->NewData(data, data + len);
|
||||
} catch ( const binpac::Exception& e ) {
|
||||
AnalyzerViolation(util::fmt("Binpac exception: %s", e.c_msg()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! conn->is_done();
|
||||
}
|
||||
return ! conn->is_done();
|
||||
}
|
||||
|
||||
bool PE::EndOfFile()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool PE::EndOfFile() { return false; }
|
||||
|
||||
} // namespace zeek::file_analysis::detail
|
||||
} // namespace zeek::file_analysis::detail
|
||||
|
|
|
@ -7,31 +7,28 @@
|
|||
|
||||
#include "file_analysis/analyzer/pe/pe_pac.h"
|
||||
|
||||
namespace zeek::file_analysis::detail
|
||||
{
|
||||
namespace zeek::file_analysis::detail {
|
||||
|
||||
/**
|
||||
* Analyze Portable Executable files
|
||||
*/
|
||||
class PE : public file_analysis::Analyzer
|
||||
{
|
||||
class PE : public file_analysis::Analyzer {
|
||||
public:
|
||||
~PE();
|
||||
~PE();
|
||||
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file)
|
||||
{
|
||||
return new PE(std::move(args), file);
|
||||
}
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file) {
|
||||
return new PE(std::move(args), file);
|
||||
}
|
||||
|
||||
virtual bool DeliverStream(const u_char* data, uint64_t len);
|
||||
virtual bool DeliverStream(const u_char* data, uint64_t len);
|
||||
|
||||
virtual bool EndOfFile();
|
||||
virtual bool EndOfFile();
|
||||
|
||||
protected:
|
||||
PE(RecordValPtr args, file_analysis::File* file);
|
||||
binpac::PE::File* interp;
|
||||
binpac::PE::MockConnection* conn;
|
||||
bool done;
|
||||
};
|
||||
PE(RecordValPtr args, file_analysis::File* file);
|
||||
binpac::PE::File* interp;
|
||||
binpac::PE::MockConnection* conn;
|
||||
bool done;
|
||||
};
|
||||
|
||||
} // namespace zeek::file_analysis::detail
|
||||
} // namespace zeek::file_analysis::detail
|
||||
|
|
|
@ -5,22 +5,18 @@
|
|||
#include "zeek/file_analysis/Component.h"
|
||||
#include "zeek/file_analysis/analyzer/pe/PE.h"
|
||||
|
||||
namespace zeek::plugin::detail::Zeek_PE
|
||||
{
|
||||
namespace zeek::plugin::detail::Zeek_PE {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(
|
||||
new zeek::file_analysis::Component("PE", zeek::file_analysis::detail::PE::Instantiate));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(new zeek::file_analysis::Component("PE", zeek::file_analysis::detail::PE::Instantiate));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::PE";
|
||||
config.description = "Portable Executable analyzer";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::PE";
|
||||
config.description = "Portable Executable analyzer";
|
||||
return config;
|
||||
}
|
||||
} plugin;
|
||||
|
||||
} // namespace zeek::plugin::detail::Zeek_PE
|
||||
} // namespace zeek::plugin::detail::Zeek_PE
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,36 +7,32 @@
|
|||
|
||||
#include "zeek/file_analysis/analyzer/x509/X509Common.h"
|
||||
|
||||
namespace zeek::file_analysis
|
||||
{
|
||||
namespace zeek::file_analysis {
|
||||
|
||||
class File;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace detail {
|
||||
|
||||
class OCSP : public file_analysis::detail::X509Common
|
||||
{
|
||||
class OCSP : public file_analysis::detail::X509Common {
|
||||
public:
|
||||
bool DeliverStream(const u_char* data, uint64_t len) override;
|
||||
bool Undelivered(uint64_t offset, uint64_t len) override;
|
||||
bool EndOfFile() override;
|
||||
bool DeliverStream(const u_char* data, uint64_t len) override;
|
||||
bool Undelivered(uint64_t offset, uint64_t len) override;
|
||||
bool EndOfFile() override;
|
||||
|
||||
static file_analysis::Analyzer* InstantiateRequest(RecordValPtr args,
|
||||
file_analysis::File* file);
|
||||
static file_analysis::Analyzer* InstantiateReply(RecordValPtr args, file_analysis::File* file);
|
||||
static file_analysis::Analyzer* InstantiateRequest(RecordValPtr args, file_analysis::File* file);
|
||||
static file_analysis::Analyzer* InstantiateReply(RecordValPtr args, file_analysis::File* file);
|
||||
|
||||
protected:
|
||||
OCSP(RecordValPtr args, file_analysis::File* file, bool request);
|
||||
OCSP(RecordValPtr args, file_analysis::File* file, bool request);
|
||||
|
||||
private:
|
||||
void ParseResponse(OCSP_RESPONSE*);
|
||||
void ParseRequest(OCSP_REQUEST*);
|
||||
void ParseExtensionsSpecific(X509_EXTENSION* ex, bool, ASN1_OBJECT*, const char*) override;
|
||||
void ParseResponse(OCSP_RESPONSE*);
|
||||
void ParseRequest(OCSP_REQUEST*);
|
||||
void ParseExtensionsSpecific(X509_EXTENSION* ex, bool, ASN1_OBJECT*, const char*) override;
|
||||
|
||||
std::string ocsp_data;
|
||||
bool request = false; // true if ocsp request, false if reply
|
||||
};
|
||||
std::string ocsp_data;
|
||||
bool request = false; // true if ocsp request, false if reply
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace zeek::file_analysis
|
||||
} // namespace detail
|
||||
} // namespace zeek::file_analysis
|
||||
|
|
|
@ -6,32 +6,27 @@
|
|||
#include "zeek/file_analysis/analyzer/x509/OCSP.h"
|
||||
#include "zeek/file_analysis/analyzer/x509/X509.h"
|
||||
|
||||
namespace zeek::plugin::detail::Zeek_X509
|
||||
{
|
||||
namespace zeek::plugin::detail::Zeek_X509 {
|
||||
|
||||
class Plugin : public zeek::plugin::Plugin
|
||||
{
|
||||
class Plugin : public zeek::plugin::Plugin {
|
||||
public:
|
||||
zeek::plugin::Configuration Configure() override
|
||||
{
|
||||
AddComponent(new zeek::file_analysis::Component(
|
||||
"X509", zeek::file_analysis::detail::X509::Instantiate));
|
||||
AddComponent(new zeek::file_analysis::Component(
|
||||
"OCSP_REQUEST", zeek::file_analysis::detail::OCSP::InstantiateRequest));
|
||||
AddComponent(new zeek::file_analysis::Component(
|
||||
"OCSP_REPLY", zeek::file_analysis::detail::OCSP::InstantiateReply));
|
||||
zeek::plugin::Configuration Configure() override {
|
||||
AddComponent(new zeek::file_analysis::Component("X509", zeek::file_analysis::detail::X509::Instantiate));
|
||||
AddComponent(
|
||||
new zeek::file_analysis::Component("OCSP_REQUEST", zeek::file_analysis::detail::OCSP::InstantiateRequest));
|
||||
AddComponent(
|
||||
new zeek::file_analysis::Component("OCSP_REPLY", zeek::file_analysis::detail::OCSP::InstantiateReply));
|
||||
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::X509";
|
||||
config.description = "X509 and OCSP analyzer";
|
||||
return config;
|
||||
}
|
||||
zeek::plugin::Configuration config;
|
||||
config.name = "Zeek::X509";
|
||||
config.description = "X509 and OCSP analyzer";
|
||||
return config;
|
||||
}
|
||||
|
||||
void Done() override
|
||||
{
|
||||
zeek::plugin::Plugin::Done();
|
||||
zeek::file_analysis::detail::X509::FreeRootStore();
|
||||
}
|
||||
} plugin;
|
||||
void Done() override {
|
||||
zeek::plugin::Plugin::Done();
|
||||
zeek::file_analysis::detail::X509::FreeRootStore();
|
||||
}
|
||||
} plugin;
|
||||
|
||||
} // namespace zeek::plugin::detail::Zeek_X509
|
||||
} // namespace zeek::plugin::detail::Zeek_X509
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -30,122 +30,113 @@
|
|||
|
||||
#define OCSP_SINGLERESP_get0_id(s) (s)->certId
|
||||
|
||||
static X509* X509_OBJECT_get0_X509(const X509_OBJECT* a)
|
||||
{
|
||||
if ( a == nullptr || a->type != X509_LU_X509 )
|
||||
return nullptr;
|
||||
return a->data.x509;
|
||||
}
|
||||
static X509* X509_OBJECT_get0_X509(const X509_OBJECT* a) {
|
||||
if ( a == nullptr || a->type != X509_LU_X509 )
|
||||
return nullptr;
|
||||
return a->data.x509;
|
||||
}
|
||||
|
||||
static void DSA_get0_pqg(const DSA* d, const BIGNUM** p, const BIGNUM** q, const BIGNUM** g)
|
||||
{
|
||||
if ( p != nullptr )
|
||||
*p = d->p;
|
||||
if ( q != nullptr )
|
||||
*q = d->q;
|
||||
if ( g != nullptr )
|
||||
*g = d->g;
|
||||
}
|
||||
static void DSA_get0_pqg(const DSA* d, const BIGNUM** p, const BIGNUM** q, const BIGNUM** g) {
|
||||
if ( p != nullptr )
|
||||
*p = d->p;
|
||||
if ( q != nullptr )
|
||||
*q = d->q;
|
||||
if ( g != nullptr )
|
||||
*g = d->g;
|
||||
}
|
||||
|
||||
static void RSA_get0_key(const RSA* r, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d)
|
||||
{
|
||||
if ( n != nullptr )
|
||||
*n = r->n;
|
||||
if ( e != nullptr )
|
||||
*e = r->e;
|
||||
if ( d != nullptr )
|
||||
*d = r->d;
|
||||
}
|
||||
static void RSA_get0_key(const RSA* r, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d) {
|
||||
if ( n != nullptr )
|
||||
*n = r->n;
|
||||
if ( e != nullptr )
|
||||
*e = r->e;
|
||||
if ( d != nullptr )
|
||||
*d = r->d;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
namespace zeek::file_analysis::detail
|
||||
{
|
||||
namespace zeek::file_analysis::detail {
|
||||
|
||||
class X509Val;
|
||||
|
||||
class X509 : public file_analysis::detail::X509Common
|
||||
{
|
||||
class X509 : public file_analysis::detail::X509Common {
|
||||
public:
|
||||
bool DeliverStream(const u_char* data, uint64_t len) override;
|
||||
bool Undelivered(uint64_t offset, uint64_t len) override;
|
||||
bool EndOfFile() override;
|
||||
bool DeliverStream(const u_char* data, uint64_t len) override;
|
||||
bool Undelivered(uint64_t offset, uint64_t len) override;
|
||||
bool EndOfFile() override;
|
||||
|
||||
/**
|
||||
* Converts an X509 certificate into a \c X509::Certificate record
|
||||
* value. This is a static function that can be called from external,
|
||||
* it doesn't depend on the state of any particular file analyzer.
|
||||
*
|
||||
* @param cert_val The certificate to converts.
|
||||
*
|
||||
* @param f A file associated with the certificate, if any
|
||||
* (primarily for error reporting).
|
||||
*
|
||||
* @param Returns the new record value and passes ownership to
|
||||
* caller.
|
||||
*/
|
||||
static RecordValPtr ParseCertificate(X509Val* cert_val, file_analysis::File* file = nullptr);
|
||||
/**
|
||||
* Converts an X509 certificate into a \c X509::Certificate record
|
||||
* value. This is a static function that can be called from external,
|
||||
* it doesn't depend on the state of any particular file analyzer.
|
||||
*
|
||||
* @param cert_val The certificate to converts.
|
||||
*
|
||||
* @param f A file associated with the certificate, if any
|
||||
* (primarily for error reporting).
|
||||
*
|
||||
* @param Returns the new record value and passes ownership to
|
||||
* caller.
|
||||
*/
|
||||
static RecordValPtr ParseCertificate(X509Val* cert_val, file_analysis::File* file = nullptr);
|
||||
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file)
|
||||
{
|
||||
return new X509(std::move(args), file);
|
||||
}
|
||||
static file_analysis::Analyzer* Instantiate(RecordValPtr args, file_analysis::File* file) {
|
||||
return new X509(std::move(args), file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves OpenSSL's representation of an X509 certificate store
|
||||
* associated with a script-layer certificate root table variable/value.
|
||||
* The underlying X509 store will be created if it has not been already,
|
||||
* else the previously allocated one for the same table will be returned.
|
||||
*
|
||||
* @param root_certs The script-layer certificate root table value.
|
||||
*
|
||||
* @return OpenSSL's X509 store associated with the table value.
|
||||
*/
|
||||
static X509_STORE* GetRootStore(TableVal* root_certs);
|
||||
/**
|
||||
* Retrieves OpenSSL's representation of an X509 certificate store
|
||||
* associated with a script-layer certificate root table variable/value.
|
||||
* The underlying X509 store will be created if it has not been already,
|
||||
* else the previously allocated one for the same table will be returned.
|
||||
*
|
||||
* @param root_certs The script-layer certificate root table value.
|
||||
*
|
||||
* @return OpenSSL's X509 store associated with the table value.
|
||||
*/
|
||||
static X509_STORE* GetRootStore(TableVal* root_certs);
|
||||
|
||||
/**
|
||||
* Frees memory obtained from OpenSSL that is associated with the global
|
||||
* X509 certificate store used by the Zeek scripting-layer. This primarily
|
||||
* exists so leak checkers like LeakSanitizer don't count the
|
||||
* globally-allocated mapping as a leak. Would be easy to suppress/ignore
|
||||
* it, but that could accidentally silence cases where some new code
|
||||
* mistakenly overwrites a table element without freeing it.
|
||||
*/
|
||||
static void FreeRootStore();
|
||||
/**
|
||||
* Frees memory obtained from OpenSSL that is associated with the global
|
||||
* X509 certificate store used by the Zeek scripting-layer. This primarily
|
||||
* exists so leak checkers like LeakSanitizer don't count the
|
||||
* globally-allocated mapping as a leak. Would be easy to suppress/ignore
|
||||
* it, but that could accidentally silence cases where some new code
|
||||
* mistakenly overwrites a table element without freeing it.
|
||||
*/
|
||||
static void FreeRootStore();
|
||||
|
||||
/**
|
||||
* Sets the table[string] that used as the certificate cache inside of Zeek.
|
||||
*/
|
||||
static void SetCertificateCache(TableValPtr cache) { certificate_cache = std::move(cache); }
|
||||
/**
|
||||
* Sets the table[string] that used as the certificate cache inside of Zeek.
|
||||
*/
|
||||
static void SetCertificateCache(TableValPtr cache) { certificate_cache = std::move(cache); }
|
||||
|
||||
/**
|
||||
* Sets the callback when a certificate cache hit is encountered
|
||||
*/
|
||||
static void SetCertificateCacheHitCallback(FuncPtr func)
|
||||
{
|
||||
cache_hit_callback = std::move(func);
|
||||
}
|
||||
/**
|
||||
* Sets the callback when a certificate cache hit is encountered
|
||||
*/
|
||||
static void SetCertificateCacheHitCallback(FuncPtr func) { cache_hit_callback = std::move(func); }
|
||||
|
||||
protected:
|
||||
X509(RecordValPtr args, file_analysis::File* file);
|
||||
X509(RecordValPtr args, file_analysis::File* file);
|
||||
|
||||
private:
|
||||
void ParseBasicConstraints(X509_EXTENSION* ex);
|
||||
void ParseSAN(X509_EXTENSION* ex);
|
||||
void ParseExtensionsSpecific(X509_EXTENSION* ex, bool, ASN1_OBJECT*, const char*) override;
|
||||
void ParseBasicConstraints(X509_EXTENSION* ex);
|
||||
void ParseSAN(X509_EXTENSION* ex);
|
||||
void ParseExtensionsSpecific(X509_EXTENSION* ex, bool, ASN1_OBJECT*, const char*) override;
|
||||
|
||||
std::string cert_data;
|
||||
std::string cert_data;
|
||||
|
||||
// Helpers for ParseCertificate.
|
||||
static StringValPtr KeyCurve(EVP_PKEY* key);
|
||||
static unsigned int KeyLength(EVP_PKEY* key);
|
||||
/** X509 stores associated with global script-layer values */
|
||||
inline static std::map<Val*, X509_STORE*> x509_stores = std::map<Val*, X509_STORE*>();
|
||||
inline static TableValPtr certificate_cache = nullptr;
|
||||
inline static FuncPtr cache_hit_callback = nullptr;
|
||||
};
|
||||
// Helpers for ParseCertificate.
|
||||
static StringValPtr KeyCurve(EVP_PKEY* key);
|
||||
static unsigned int KeyLength(EVP_PKEY* key);
|
||||
/** X509 stores associated with global script-layer values */
|
||||
inline static std::map<Val*, X509_STORE*> x509_stores = std::map<Val*, X509_STORE*>();
|
||||
inline static TableValPtr certificate_cache = nullptr;
|
||||
inline static FuncPtr cache_hit_callback = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class wraps an OpenSSL X509 data structure.
|
||||
|
@ -154,49 +145,48 @@ private:
|
|||
* script-land. Otherwise, we cannot verify certificates from Zeek
|
||||
* scriptland
|
||||
*/
|
||||
class X509Val : public OpaqueVal
|
||||
{
|
||||
class X509Val : public OpaqueVal {
|
||||
public:
|
||||
/**
|
||||
* Construct an X509Val.
|
||||
*
|
||||
* @param certificate specifies the wrapped OpenSSL certificate
|
||||
*
|
||||
* @return A newly initialized X509Val.
|
||||
*/
|
||||
explicit X509Val(::X509* certificate);
|
||||
/**
|
||||
* Construct an X509Val.
|
||||
*
|
||||
* @param certificate specifies the wrapped OpenSSL certificate
|
||||
*
|
||||
* @return A newly initialized X509Val.
|
||||
*/
|
||||
explicit X509Val(::X509* certificate);
|
||||
|
||||
/**
|
||||
* Clone an X509Val
|
||||
*
|
||||
* @param state certifies the state of the clone operation (duplicate tracking)
|
||||
*
|
||||
* @return A cloned X509Val.
|
||||
*/
|
||||
ValPtr DoClone(CloneState* state) override;
|
||||
/**
|
||||
* Clone an X509Val
|
||||
*
|
||||
* @param state certifies the state of the clone operation (duplicate tracking)
|
||||
*
|
||||
* @return A cloned X509Val.
|
||||
*/
|
||||
ValPtr DoClone(CloneState* state) override;
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~X509Val() override;
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~X509Val() override;
|
||||
|
||||
/**
|
||||
* Get the wrapped X509 certificate. Please take care, that the
|
||||
* internal OpenSSL reference counting stays the same.
|
||||
*
|
||||
* @return The wrapped OpenSSL X509 certificate.
|
||||
*/
|
||||
::X509* GetCertificate() const;
|
||||
/**
|
||||
* Get the wrapped X509 certificate. Please take care, that the
|
||||
* internal OpenSSL reference counting stays the same.
|
||||
*
|
||||
* @return The wrapped OpenSSL X509 certificate.
|
||||
*/
|
||||
::X509* GetCertificate() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Construct an empty X509Val. Only used for deserialization
|
||||
*/
|
||||
X509Val();
|
||||
/**
|
||||
* Construct an empty X509Val. Only used for deserialization
|
||||
*/
|
||||
X509Val();
|
||||
|
||||
DECLARE_OPAQUE_VALUE(X509Val)
|
||||
DECLARE_OPAQUE_VALUE(X509Val)
|
||||
private:
|
||||
::X509* certificate; // the wrapped certificate
|
||||
};
|
||||
::X509* certificate; // the wrapped certificate
|
||||
};
|
||||
|
||||
} // namespace zeek::file_analysis::detail
|
||||
} // namespace zeek::file_analysis::detail
|
||||
|
|
|
@ -14,334 +14,295 @@
|
|||
#include "zeek/file_analysis/analyzer/x509/types.bif.h"
|
||||
#include "zeek/file_analysis/analyzer/x509/x509-extension_pac.h"
|
||||
|
||||
namespace zeek::file_analysis::detail
|
||||
{
|
||||
namespace zeek::file_analysis::detail {
|
||||
|
||||
X509Common::X509Common(const zeek::Tag& arg_tag, RecordValPtr arg_args,
|
||||
file_analysis::File* arg_file)
|
||||
: file_analysis::Analyzer(arg_tag, std::move(arg_args), arg_file)
|
||||
{
|
||||
}
|
||||
X509Common::X509Common(const zeek::Tag& arg_tag, RecordValPtr arg_args, file_analysis::File* arg_file)
|
||||
: file_analysis::Analyzer(arg_tag, std::move(arg_args), arg_file) {}
|
||||
|
||||
static void EmitWeird(const char* name, file_analysis::File* file, const char* addl = "")
|
||||
{
|
||||
if ( file )
|
||||
reporter->Weird(file, name, addl);
|
||||
else
|
||||
reporter->Weird(name);
|
||||
}
|
||||
static void EmitWeird(const char* name, file_analysis::File* file, const char* addl = "") {
|
||||
if ( file )
|
||||
reporter->Weird(file, name, addl);
|
||||
else
|
||||
reporter->Weird(name);
|
||||
}
|
||||
|
||||
double X509Common::GetTimeFromAsn1(const ASN1_TIME* atime, file_analysis::File* f,
|
||||
Reporter* reporter)
|
||||
{
|
||||
time_t lResult = 0;
|
||||
double X509Common::GetTimeFromAsn1(const ASN1_TIME* atime, file_analysis::File* f, Reporter* reporter) {
|
||||
time_t lResult = 0;
|
||||
|
||||
char lBuffer[26];
|
||||
char* pBuffer = lBuffer;
|
||||
char lBuffer[26];
|
||||
char* pBuffer = lBuffer;
|
||||
|
||||
const char* pString = (const char*)atime->data;
|
||||
unsigned int remaining = atime->length;
|
||||
const char* pString = (const char*)atime->data;
|
||||
unsigned int remaining = atime->length;
|
||||
|
||||
if ( atime->type == V_ASN1_UTCTIME )
|
||||
{
|
||||
if ( remaining < 11 || remaining > 17 )
|
||||
{
|
||||
EmitWeird("x509_utc_length", f);
|
||||
return 0;
|
||||
}
|
||||
if ( atime->type == V_ASN1_UTCTIME ) {
|
||||
if ( remaining < 11 || remaining > 17 ) {
|
||||
EmitWeird("x509_utc_length", f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( pString[remaining - 1] != 'Z' )
|
||||
{
|
||||
// not valid according to RFC 2459 4.1.2.5.1
|
||||
EmitWeird("x509_utc_format", f);
|
||||
return 0;
|
||||
}
|
||||
if ( pString[remaining - 1] != 'Z' ) {
|
||||
// not valid according to RFC 2459 4.1.2.5.1
|
||||
EmitWeird("x509_utc_format", f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// year is first two digits in YY format. Buffer expects YYYY format.
|
||||
if ( pString[0] < '5' ) // RFC 2459 4.1.2.5.1
|
||||
{
|
||||
*(pBuffer++) = '2';
|
||||
*(pBuffer++) = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
*(pBuffer++) = '1';
|
||||
*(pBuffer++) = '9';
|
||||
}
|
||||
// year is first two digits in YY format. Buffer expects YYYY format.
|
||||
if ( pString[0] < '5' ) // RFC 2459 4.1.2.5.1
|
||||
{
|
||||
*(pBuffer++) = '2';
|
||||
*(pBuffer++) = '0';
|
||||
}
|
||||
else {
|
||||
*(pBuffer++) = '1';
|
||||
*(pBuffer++) = '9';
|
||||
}
|
||||
|
||||
memcpy(pBuffer, pString, 10);
|
||||
pBuffer += 10;
|
||||
pString += 10;
|
||||
remaining -= 10;
|
||||
}
|
||||
else if ( atime->type == V_ASN1_GENERALIZEDTIME )
|
||||
{
|
||||
// generalized time. We apparently ignore the YYYYMMDDHH case
|
||||
// for now and assume we always have minutes and seconds.
|
||||
// This should be ok because it is specified as a requirement in RFC 2459 4.1.2.5.2
|
||||
memcpy(pBuffer, pString, 10);
|
||||
pBuffer += 10;
|
||||
pString += 10;
|
||||
remaining -= 10;
|
||||
}
|
||||
else if ( atime->type == V_ASN1_GENERALIZEDTIME ) {
|
||||
// generalized time. We apparently ignore the YYYYMMDDHH case
|
||||
// for now and assume we always have minutes and seconds.
|
||||
// This should be ok because it is specified as a requirement in RFC 2459 4.1.2.5.2
|
||||
|
||||
if ( remaining < 12 || remaining > 23 )
|
||||
{
|
||||
EmitWeird("x509_gen_time_length", f);
|
||||
return 0;
|
||||
}
|
||||
if ( remaining < 12 || remaining > 23 ) {
|
||||
EmitWeird("x509_gen_time_length", f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(pBuffer, pString, 12);
|
||||
pBuffer += 12;
|
||||
pString += 12;
|
||||
remaining -= 12;
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitWeird("x509_invalid_time_type", f);
|
||||
return 0;
|
||||
}
|
||||
memcpy(pBuffer, pString, 12);
|
||||
pBuffer += 12;
|
||||
pString += 12;
|
||||
remaining -= 12;
|
||||
}
|
||||
else {
|
||||
EmitWeird("x509_invalid_time_type", f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( (remaining == 0) || (*pString == 'Z') || (*pString == '-') || (*pString == '+') )
|
||||
{
|
||||
*(pBuffer++) = '0';
|
||||
*(pBuffer++) = '0';
|
||||
}
|
||||
if ( (remaining == 0) || (*pString == 'Z') || (*pString == '-') || (*pString == '+') ) {
|
||||
*(pBuffer++) = '0';
|
||||
*(pBuffer++) = '0';
|
||||
}
|
||||
|
||||
else if ( remaining >= 2 )
|
||||
{
|
||||
*(pBuffer++) = *(pString++);
|
||||
*(pBuffer++) = *(pString++);
|
||||
else if ( remaining >= 2 ) {
|
||||
*(pBuffer++) = *(pString++);
|
||||
*(pBuffer++) = *(pString++);
|
||||
|
||||
remaining -= 2;
|
||||
remaining -= 2;
|
||||
|
||||
// Skip any fractional seconds...
|
||||
if ( (remaining > 0) && (*pString == '.') )
|
||||
{
|
||||
pString++;
|
||||
remaining--;
|
||||
// Skip any fractional seconds...
|
||||
if ( (remaining > 0) && (*pString == '.') ) {
|
||||
pString++;
|
||||
remaining--;
|
||||
|
||||
while ( (remaining > 0) && (*pString >= '0') && (*pString <= '9') )
|
||||
{
|
||||
pString++;
|
||||
remaining--;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ( (remaining > 0) && (*pString >= '0') && (*pString <= '9') ) {
|
||||
pString++;
|
||||
remaining--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
EmitWeird("x509_time_add_char", f);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
EmitWeird("x509_time_add_char", f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*(pBuffer++) = 'Z';
|
||||
*(pBuffer++) = '\0';
|
||||
*(pBuffer++) = 'Z';
|
||||
*(pBuffer++) = '\0';
|
||||
|
||||
time_t lSecondsFromUTC;
|
||||
time_t lSecondsFromUTC;
|
||||
|
||||
if ( remaining == 0 || *pString == 'Z' )
|
||||
lSecondsFromUTC = 0;
|
||||
else
|
||||
{
|
||||
if ( remaining < 5 )
|
||||
{
|
||||
EmitWeird("x509_time_offset_underflow", f);
|
||||
return 0;
|
||||
}
|
||||
if ( remaining == 0 || *pString == 'Z' )
|
||||
lSecondsFromUTC = 0;
|
||||
else {
|
||||
if ( remaining < 5 ) {
|
||||
EmitWeird("x509_time_offset_underflow", f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( (*pString != '+') && (*pString != '-') )
|
||||
{
|
||||
EmitWeird("x509_time_offset_type", f);
|
||||
return 0;
|
||||
}
|
||||
if ( (*pString != '+') && (*pString != '-') ) {
|
||||
EmitWeird("x509_time_offset_type", f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lSecondsFromUTC = ((pString[1] - '0') * 10 + (pString[2] - '0')) * 60;
|
||||
lSecondsFromUTC += (pString[3] - '0') * 10 + (pString[4] - '0');
|
||||
lSecondsFromUTC = ((pString[1] - '0') * 10 + (pString[2] - '0')) * 60;
|
||||
lSecondsFromUTC += (pString[3] - '0') * 10 + (pString[4] - '0');
|
||||
|
||||
if ( *pString == '-' )
|
||||
lSecondsFromUTC = -lSecondsFromUTC;
|
||||
}
|
||||
if ( *pString == '-' )
|
||||
lSecondsFromUTC = -lSecondsFromUTC;
|
||||
}
|
||||
|
||||
tm lTime;
|
||||
lTime.tm_sec = ((lBuffer[12] - '0') * 10) + (lBuffer[13] - '0');
|
||||
lTime.tm_min = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0');
|
||||
lTime.tm_hour = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0');
|
||||
lTime.tm_mday = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0');
|
||||
lTime.tm_mon = (((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0')) - 1;
|
||||
lTime.tm_year = (lBuffer[0] - '0') * 1000 + (lBuffer[1] - '0') * 100 +
|
||||
((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0');
|
||||
tm lTime;
|
||||
lTime.tm_sec = ((lBuffer[12] - '0') * 10) + (lBuffer[13] - '0');
|
||||
lTime.tm_min = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0');
|
||||
lTime.tm_hour = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0');
|
||||
lTime.tm_mday = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0');
|
||||
lTime.tm_mon = (((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0')) - 1;
|
||||
lTime.tm_year =
|
||||
(lBuffer[0] - '0') * 1000 + (lBuffer[1] - '0') * 100 + ((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0');
|
||||
|
||||
if ( lTime.tm_year > 1900 )
|
||||
lTime.tm_year -= 1900;
|
||||
if ( lTime.tm_year > 1900 )
|
||||
lTime.tm_year -= 1900;
|
||||
|
||||
lTime.tm_wday = 0;
|
||||
lTime.tm_yday = 0;
|
||||
lTime.tm_isdst = 0; // No DST adjustment requested
|
||||
lTime.tm_wday = 0;
|
||||
lTime.tm_yday = 0;
|
||||
lTime.tm_isdst = 0; // No DST adjustment requested
|
||||
|
||||
lResult = mktime(&lTime);
|
||||
lResult = mktime(&lTime);
|
||||
|
||||
if ( lResult )
|
||||
{
|
||||
if ( lTime.tm_isdst != 0 )
|
||||
lResult -= 3600; // mktime may adjust for DST (OS dependent)
|
||||
if ( lResult ) {
|
||||
if ( lTime.tm_isdst != 0 )
|
||||
lResult -= 3600; // mktime may adjust for DST (OS dependent)
|
||||
|
||||
lResult += lSecondsFromUTC;
|
||||
}
|
||||
lResult += lSecondsFromUTC;
|
||||
}
|
||||
|
||||
else
|
||||
lResult = 0;
|
||||
else
|
||||
lResult = 0;
|
||||
|
||||
return lResult;
|
||||
}
|
||||
return lResult;
|
||||
}
|
||||
|
||||
void X509Common::ParseSignedCertificateTimestamps(X509_EXTENSION* ext)
|
||||
{
|
||||
// Ok, signed certificate timestamps are a bit of an odd case out; we don't
|
||||
// want to use the (basically nonexistent) OpenSSL functionality to parse them.
|
||||
// Instead we have our own, self-written binpac parser to parse just them,
|
||||
// which we will initialize here and tear down immediately again.
|
||||
void X509Common::ParseSignedCertificateTimestamps(X509_EXTENSION* ext) {
|
||||
// Ok, signed certificate timestamps are a bit of an odd case out; we don't
|
||||
// want to use the (basically nonexistent) OpenSSL functionality to parse them.
|
||||
// Instead we have our own, self-written binpac parser to parse just them,
|
||||
// which we will initialize here and tear down immediately again.
|
||||
|
||||
ASN1_OCTET_STRING* ext_val = X509_EXTENSION_get_data(ext);
|
||||
// the octet string of the extension contains the octet string which in turn
|
||||
// contains the SCT. Obviously.
|
||||
ASN1_OCTET_STRING* ext_val = X509_EXTENSION_get_data(ext);
|
||||
// the octet string of the extension contains the octet string which in turn
|
||||
// contains the SCT. Obviously.
|
||||
|
||||
unsigned char* ext_val_copy = (unsigned char*)OPENSSL_malloc(ext_val->length);
|
||||
unsigned char* ext_val_second_pointer = ext_val_copy;
|
||||
memcpy(ext_val_copy, ext_val->data, ext_val->length);
|
||||
unsigned char* ext_val_copy = (unsigned char*)OPENSSL_malloc(ext_val->length);
|
||||
unsigned char* ext_val_second_pointer = ext_val_copy;
|
||||
memcpy(ext_val_copy, ext_val->data, ext_val->length);
|
||||
|
||||
ASN1_OCTET_STRING* inner = d2i_ASN1_OCTET_STRING(NULL, (const unsigned char**)&ext_val_copy,
|
||||
ext_val->length);
|
||||
if ( ! inner )
|
||||
{
|
||||
OPENSSL_free(ext_val_second_pointer);
|
||||
reporter->Error(
|
||||
"X509::ParseSignedCertificateTimestamps could not parse inner octet string");
|
||||
return;
|
||||
}
|
||||
ASN1_OCTET_STRING* inner = d2i_ASN1_OCTET_STRING(NULL, (const unsigned char**)&ext_val_copy, ext_val->length);
|
||||
if ( ! inner ) {
|
||||
OPENSSL_free(ext_val_second_pointer);
|
||||
reporter->Error("X509::ParseSignedCertificateTimestamps could not parse inner octet string");
|
||||
return;
|
||||
}
|
||||
|
||||
binpac::X509Extension::MockConnection* conn = new binpac::X509Extension::MockConnection(this);
|
||||
binpac::X509Extension::SignedCertTimestampExt* interp =
|
||||
new binpac::X509Extension::SignedCertTimestampExt(conn);
|
||||
binpac::X509Extension::MockConnection* conn = new binpac::X509Extension::MockConnection(this);
|
||||
binpac::X509Extension::SignedCertTimestampExt* interp = new binpac::X509Extension::SignedCertTimestampExt(conn);
|
||||
|
||||
try
|
||||
{
|
||||
interp->NewData(inner->data, inner->data + inner->length);
|
||||
}
|
||||
catch ( const binpac::Exception& e )
|
||||
{
|
||||
// throw a warning or sth
|
||||
reporter->Error("X509::ParseSignedCertificateTimestamps could not parse SCT");
|
||||
}
|
||||
try {
|
||||
interp->NewData(inner->data, inner->data + inner->length);
|
||||
} catch ( const binpac::Exception& e ) {
|
||||
// throw a warning or sth
|
||||
reporter->Error("X509::ParseSignedCertificateTimestamps could not parse SCT");
|
||||
}
|
||||
|
||||
ASN1_OCTET_STRING_free(inner);
|
||||
OPENSSL_free(ext_val_second_pointer);
|
||||
ASN1_OCTET_STRING_free(inner);
|
||||
OPENSSL_free(ext_val_second_pointer);
|
||||
|
||||
interp->FlowEOF();
|
||||
interp->FlowEOF();
|
||||
|
||||
delete interp;
|
||||
delete conn;
|
||||
}
|
||||
delete interp;
|
||||
delete conn;
|
||||
}
|
||||
|
||||
void X509Common::ParseExtension(X509_EXTENSION* ex, const EventHandlerPtr& h, bool global)
|
||||
{
|
||||
char name[256];
|
||||
char oid[256];
|
||||
void X509Common::ParseExtension(X509_EXTENSION* ex, const EventHandlerPtr& h, bool global) {
|
||||
char name[256];
|
||||
char oid[256];
|
||||
|
||||
ASN1_OBJECT* ext_asn = X509_EXTENSION_get_object(ex);
|
||||
const char* short_name = OBJ_nid2sn(OBJ_obj2nid(ext_asn));
|
||||
ASN1_OBJECT* ext_asn = X509_EXTENSION_get_object(ex);
|
||||
const char* short_name = OBJ_nid2sn(OBJ_obj2nid(ext_asn));
|
||||
|
||||
OBJ_obj2txt(name, 255, ext_asn, 0);
|
||||
OBJ_obj2txt(oid, 255, ext_asn, 1);
|
||||
OBJ_obj2txt(name, 255, ext_asn, 0);
|
||||
OBJ_obj2txt(oid, 255, ext_asn, 1);
|
||||
|
||||
int critical = 0;
|
||||
if ( X509_EXTENSION_get_critical(ex) != 0 )
|
||||
critical = 1;
|
||||
int critical = 0;
|
||||
if ( X509_EXTENSION_get_critical(ex) != 0 )
|
||||
critical = 1;
|
||||
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
if ( ! X509V3_EXT_print(bio, ex, 0, 0) )
|
||||
{
|
||||
unsigned char* buf = nullptr;
|
||||
int len = i2d_ASN1_OCTET_STRING(X509_EXTENSION_get_data(ex), &buf);
|
||||
if ( len >= 0 )
|
||||
{
|
||||
BIO_write(bio, buf, len);
|
||||
OPENSSL_free(buf);
|
||||
}
|
||||
}
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
if ( ! X509V3_EXT_print(bio, ex, 0, 0) ) {
|
||||
unsigned char* buf = nullptr;
|
||||
int len = i2d_ASN1_OCTET_STRING(X509_EXTENSION_get_data(ex), &buf);
|
||||
if ( len >= 0 ) {
|
||||
BIO_write(bio, buf, len);
|
||||
OPENSSL_free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
auto ext_val = GetExtensionFromBIO(bio, GetFile());
|
||||
auto ext_val = GetExtensionFromBIO(bio, GetFile());
|
||||
|
||||
if ( ! h )
|
||||
{
|
||||
// let individual analyzers parse more.
|
||||
ParseExtensionsSpecific(ex, global, ext_asn, oid);
|
||||
return;
|
||||
}
|
||||
if ( ! h ) {
|
||||
// let individual analyzers parse more.
|
||||
ParseExtensionsSpecific(ex, global, ext_asn, oid);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! ext_val )
|
||||
ext_val = make_intrusive<StringVal>(0, "");
|
||||
if ( ! ext_val )
|
||||
ext_val = make_intrusive<StringVal>(0, "");
|
||||
|
||||
auto pX509Ext = make_intrusive<RecordVal>(BifType::Record::X509::Extension);
|
||||
pX509Ext->Assign(0, name);
|
||||
auto pX509Ext = make_intrusive<RecordVal>(BifType::Record::X509::Extension);
|
||||
pX509Ext->Assign(0, name);
|
||||
|
||||
if ( short_name && strlen(short_name) > 0 )
|
||||
pX509Ext->Assign(1, short_name);
|
||||
if ( short_name && strlen(short_name) > 0 )
|
||||
pX509Ext->Assign(1, short_name);
|
||||
|
||||
pX509Ext->Assign(2, oid);
|
||||
pX509Ext->Assign(3, critical);
|
||||
pX509Ext->Assign(4, ext_val);
|
||||
pX509Ext->Assign(2, oid);
|
||||
pX509Ext->Assign(3, critical);
|
||||
pX509Ext->Assign(4, ext_val);
|
||||
|
||||
// send off generic extension event
|
||||
//
|
||||
// and then look if we have a specialized event for the extension we just
|
||||
// parsed. And if we have it, we send the specialized event on top of the
|
||||
// generic event that we just had. I know, that is... kind of not nice,
|
||||
// but I am not sure if there is a better way to do it...
|
||||
// send off generic extension event
|
||||
//
|
||||
// and then look if we have a specialized event for the extension we just
|
||||
// parsed. And if we have it, we send the specialized event on top of the
|
||||
// generic event that we just had. I know, that is... kind of not nice,
|
||||
// but I am not sure if there is a better way to do it...
|
||||
|
||||
if ( h == ocsp_extension )
|
||||
event_mgr.Enqueue(h, GetFile()->ToVal(), std::move(pX509Ext), val_mgr->Bool(global));
|
||||
else
|
||||
event_mgr.Enqueue(h, GetFile()->ToVal(), std::move(pX509Ext));
|
||||
if ( h == ocsp_extension )
|
||||
event_mgr.Enqueue(h, GetFile()->ToVal(), std::move(pX509Ext), val_mgr->Bool(global));
|
||||
else
|
||||
event_mgr.Enqueue(h, GetFile()->ToVal(), std::move(pX509Ext));
|
||||
|
||||
// let individual analyzers parse more.
|
||||
ParseExtensionsSpecific(ex, global, ext_asn, oid);
|
||||
}
|
||||
// let individual analyzers parse more.
|
||||
ParseExtensionsSpecific(ex, global, ext_asn, oid);
|
||||
}
|
||||
|
||||
StringValPtr X509Common::GetExtensionFromBIO(BIO* bio, file_analysis::File* f)
|
||||
{
|
||||
BIO_flush(bio);
|
||||
ERR_clear_error();
|
||||
int length = BIO_pending(bio);
|
||||
StringValPtr X509Common::GetExtensionFromBIO(BIO* bio, file_analysis::File* f) {
|
||||
BIO_flush(bio);
|
||||
ERR_clear_error();
|
||||
int length = BIO_pending(bio);
|
||||
|
||||
if ( ERR_peek_error() != 0 )
|
||||
{
|
||||
char tmp[120];
|
||||
ERR_error_string_n(ERR_get_error(), tmp, sizeof(tmp));
|
||||
EmitWeird("x509_get_ext_from_bio", f, tmp);
|
||||
BIO_free_all(bio);
|
||||
return nullptr;
|
||||
}
|
||||
if ( ERR_peek_error() != 0 ) {
|
||||
char tmp[120];
|
||||
ERR_error_string_n(ERR_get_error(), tmp, sizeof(tmp));
|
||||
EmitWeird("x509_get_ext_from_bio", f, tmp);
|
||||
BIO_free_all(bio);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ( length == 0 )
|
||||
{
|
||||
BIO_free_all(bio);
|
||||
return val_mgr->EmptyString();
|
||||
}
|
||||
if ( length == 0 ) {
|
||||
BIO_free_all(bio);
|
||||
return val_mgr->EmptyString();
|
||||
}
|
||||
|
||||
char* buffer = (char*)malloc(length);
|
||||
char* buffer = (char*)malloc(length);
|
||||
|
||||
if ( ! buffer )
|
||||
{
|
||||
// Just emit an error here and try to continue instead of aborting
|
||||
// because it's unclear the length value is very reliable.
|
||||
reporter->Error("X509::GetExtensionFromBIO malloc(%d) failed", length);
|
||||
BIO_free_all(bio);
|
||||
return nullptr;
|
||||
}
|
||||
if ( ! buffer ) {
|
||||
// Just emit an error here and try to continue instead of aborting
|
||||
// because it's unclear the length value is very reliable.
|
||||
reporter->Error("X509::GetExtensionFromBIO malloc(%d) failed", length);
|
||||
BIO_free_all(bio);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BIO_read(bio, (void*)buffer, length);
|
||||
auto ext_val = make_intrusive<StringVal>(length, buffer);
|
||||
BIO_read(bio, (void*)buffer, length);
|
||||
auto ext_val = make_intrusive<StringVal>(length, buffer);
|
||||
|
||||
free(buffer);
|
||||
BIO_free_all(bio);
|
||||
free(buffer);
|
||||
BIO_free_all(bio);
|
||||
|
||||
return ext_val;
|
||||
}
|
||||
return ext_val;
|
||||
}
|
||||
|
||||
} // namespace zeek::file_analysis::detail
|
||||
} // namespace zeek::file_analysis::detail
|
||||
|
|
|
@ -10,52 +10,48 @@
|
|||
|
||||
#include "zeek/file_analysis/Analyzer.h"
|
||||
|
||||
namespace zeek
|
||||
{
|
||||
namespace zeek {
|
||||
|
||||
class EventHandlerPtr;
|
||||
class Reporter;
|
||||
class StringVal;
|
||||
template <class T> class IntrusivePtr;
|
||||
template<class T>
|
||||
class IntrusivePtr;
|
||||
using StringValPtr = IntrusivePtr<StringVal>;
|
||||
|
||||
namespace file_analysis
|
||||
{
|
||||
namespace file_analysis {
|
||||
|
||||
class File;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace detail {
|
||||
|
||||
class X509Common : public file_analysis::Analyzer
|
||||
{
|
||||
class X509Common : public file_analysis::Analyzer {
|
||||
public:
|
||||
~X509Common() override{};
|
||||
~X509Common() override{};
|
||||
|
||||
/**
|
||||
* Retrieve an X509 extension value from an OpenSSL BIO to which it was
|
||||
* written.
|
||||
*
|
||||
* @param bio the OpenSSL BIO to read. It will be freed by the function,
|
||||
* including when an error occurs.
|
||||
*
|
||||
* @param f an associated file, if any (used for error reporting).
|
||||
*
|
||||
* @return The X509 extension value.
|
||||
*/
|
||||
static StringValPtr GetExtensionFromBIO(BIO* bio, file_analysis::File* f = nullptr);
|
||||
/**
|
||||
* Retrieve an X509 extension value from an OpenSSL BIO to which it was
|
||||
* written.
|
||||
*
|
||||
* @param bio the OpenSSL BIO to read. It will be freed by the function,
|
||||
* including when an error occurs.
|
||||
*
|
||||
* @param f an associated file, if any (used for error reporting).
|
||||
*
|
||||
* @return The X509 extension value.
|
||||
*/
|
||||
static StringValPtr GetExtensionFromBIO(BIO* bio, file_analysis::File* f = nullptr);
|
||||
|
||||
static double GetTimeFromAsn1(const ASN1_TIME* atime, file_analysis::File* f,
|
||||
Reporter* reporter);
|
||||
static double GetTimeFromAsn1(const ASN1_TIME* atime, file_analysis::File* f, Reporter* reporter);
|
||||
|
||||
protected:
|
||||
X509Common(const zeek::Tag& arg_tag, RecordValPtr arg_args, file_analysis::File* arg_file);
|
||||
X509Common(const zeek::Tag& arg_tag, RecordValPtr arg_args, file_analysis::File* arg_file);
|
||||
|
||||
void ParseExtension(X509_EXTENSION* ex, const EventHandlerPtr& h, bool global);
|
||||
void ParseSignedCertificateTimestamps(X509_EXTENSION* ext);
|
||||
virtual void ParseExtensionsSpecific(X509_EXTENSION* ex, bool, ASN1_OBJECT*, const char*) = 0;
|
||||
};
|
||||
void ParseExtension(X509_EXTENSION* ex, const EventHandlerPtr& h, bool global);
|
||||
void ParseSignedCertificateTimestamps(X509_EXTENSION* ext);
|
||||
virtual void ParseExtensionsSpecific(X509_EXTENSION* ex, bool, ASN1_OBJECT*, const char*) = 0;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace file_analysis
|
||||
} // namespace zeek
|
||||
} // namespace detail
|
||||
} // namespace file_analysis
|
||||
} // namespace zeek
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue