diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6867b9639c..69559d6258 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -358,6 +358,7 @@ set(bro_SRCS NetVar.cc NetbiosSSN.cc Obj.cc + OpaqueVal.cc OSFinger.cc PacketFilter.cc PacketSort.cc diff --git a/src/OpaqueVal.cc b/src/OpaqueVal.cc new file mode 100644 index 0000000000..478a2f502d --- /dev/null +++ b/src/OpaqueVal.cc @@ -0,0 +1,200 @@ +#include "OpaqueVal.h" +#include "Reporter.h" +#include "Serializer.h" + +bool HashVal::IsValid() const + { + return valid; + } + +bool HashVal::Init() + { + assert(! "missing implementation of Init()"); + return false; + } + +StringVal* HashVal::Get() + { + if ( ! valid ) + return new StringVal(""); + + StringVal* result = Finish(); + valid = false; + return result; + } + +bool HashVal::Feed(const void* data, size_t size) + { + if ( valid ) + return Update(data, size); + + reporter->InternalError("invalidated opaque handle"); + return false; + } + +bool HashVal::Update(const void*, size_t) + { + assert(! "missing implementation of Update()"); + return false; + } + +StringVal* HashVal::Finish() + { + assert(! "missing implementation of Finish()"); + return new StringVal(""); + } + +HashVal::HashVal(OpaqueType* t) : OpaqueVal(t), valid(true) { } + +IMPLEMENT_SERIAL(HashVal, SER_HASH_VAL); + +bool HashVal::DoSerialize(SerialInfo* info) const + { + return SERIALIZE(valid); + } + +bool HashVal::DoUnserialize(UnserialInfo* info) + { + return UNSERIALIZE(&valid); + } + + +void MD5Val::digest(val_list& vlist, u_char result[MD5_DIGEST_LENGTH]) + { + MD5_CTX h; + + md5_init(&h); + loop_over_list(vlist, i) + { + Val* v = vlist[i]; + if ( v->Type()->Tag() == TYPE_STRING ) + { + const BroString* str = v->AsString(); + md5_update(&h, str->Bytes(), str->Len()); + } + else + { + ODesc d(DESC_BINARY); + v->Describe(&d); + md5_update(&h, (const u_char *) d.Bytes(), d.Len()); + } + } + md5_final(&h, result); + } + +void MD5Val::hmac(val_list& vlist, + u_char key[MD5_DIGEST_LENGTH], + u_char result[MD5_DIGEST_LENGTH]) + { + digest(vlist, result); + for ( int i = 0; i < MD5_DIGEST_LENGTH; ++i ) + result[i] ^= key[i]; + MD5(result, MD5_DIGEST_LENGTH, result); + } + +bool MD5Val::Init() + { + md5_init(&ctx); + return true; + } + +bool MD5Val::Update(const void* data, size_t size) + { + assert(IsValid()); + md5_update(&ctx, data, size); + return true; + } + +StringVal* MD5Val::Finish() + { + assert(IsValid()); + u_char digest[MD5_DIGEST_LENGTH]; + md5_final(&ctx, digest); + return new StringVal(md5_digest_print(digest)); + } + +IMPLEMENT_SERIAL(MD5Val, SER_MD5_VAL); + +bool MD5Val::DoSerialize(SerialInfo* info) const + { + // TODO: Implement serialization of MD5 state. + return false; + } + +bool MD5Val::DoUnserialize(UnserialInfo* info) + { + // TODO: Implement deserialization of MD5 state. + return false; + } + + +bool SHA1Val::Init() + { + sha1_init(&ctx); + return true; + } + +bool SHA1Val::Update(const void* data, size_t size) + { + assert(IsValid()); + sha1_update(&ctx, data, size); + return true; + } + +StringVal* SHA1Val::Finish() + { + assert(IsValid()); + u_char digest[SHA_DIGEST_LENGTH]; + sha1_final(&ctx, digest); + return new StringVal(sha1_digest_print(digest)); + } + +IMPLEMENT_SERIAL(SHA1Val, SER_SHA1_VAL); + +bool SHA1Val::DoSerialize(SerialInfo* info) const + { + // TODO: Implement serialization of SHA1 state. + return false; + } + +bool SHA1Val::DoUnserialize(UnserialInfo* info) + { + // TODO: Implement deserialization of SHA1 state. + return false; + } + + +bool SHA256Val::Init() + { + sha256_init(&ctx); + return true; + } + +bool SHA256Val::Update(const void* data, size_t size) + { + assert(IsValid()); + sha256_update(&ctx, data, size); + return true; + } + +StringVal* SHA256Val::Finish() + { + assert(IsValid()); + u_char digest[SHA256_DIGEST_LENGTH]; + sha256_final(&ctx, digest); + return new StringVal(sha256_digest_print(digest)); + } + +IMPLEMENT_SERIAL(SHA256Val, SER_SHA256_VAL); + +bool SHA256Val::DoSerialize(SerialInfo* info) const + { + // TODO: Implement serialization of SHA256 state. + return false; + } + +bool SHA256Val::DoUnserialize(UnserialInfo* info) + { + // TODO: Implement deserialization of SHA256 state. + return false; + } diff --git a/src/OpaqueVal.h b/src/OpaqueVal.h new file mode 100644 index 0000000000..6b86b96999 --- /dev/null +++ b/src/OpaqueVal.h @@ -0,0 +1,84 @@ +#ifndef OPAQUEVAL_H +#define OPAQUEVAL_H + +#include "Val.h" +#include "digest.h" + +class HashVal : public OpaqueVal { +public: + virtual bool IsValid() const; + virtual bool Init(); + virtual bool Feed(const void* data, size_t size); + virtual StringVal* Get(); + +protected: + HashVal() { }; + HashVal(OpaqueType* t); + virtual bool Update(const void* data, size_t size); + virtual StringVal* Finish(); + + DECLARE_SERIAL(HashVal); + +private: + // This flag exists because Get() can only be called once. + bool valid; +}; + +class MD5Val : public HashVal { +public: + static void digest(val_list& vlist, u_char result[MD5_DIGEST_LENGTH]); + + static void hmac(val_list& vlist, + u_char key[MD5_DIGEST_LENGTH], + u_char result[MD5_DIGEST_LENGTH]); + + MD5Val() : HashVal(new OpaqueType("md5")) { } + +protected: + friend class Val; + + virtual bool Init() /* override */; + virtual bool Update(const void* data, size_t size) /* override */; + virtual StringVal* Finish() /* override */; + + DECLARE_SERIAL(MD5Val); + +private: + MD5_CTX ctx; +}; + +class SHA1Val : public HashVal { +public: + SHA1Val() : HashVal(new OpaqueType("sha1")) { } + +protected: + friend class Val; + + virtual bool Init() /* override */; + virtual bool Update(const void* data, size_t size) /* override */; + virtual StringVal* Finish() /* override */; + + DECLARE_SERIAL(SHA1Val); + +private: + SHA_CTX ctx; +}; + +class SHA256Val : public HashVal { +public: + SHA256Val() : HashVal(new OpaqueType("sha256")) { } + +protected: + friend class Val; + + virtual bool Init() /* override */; + virtual bool Update(const void* data, size_t size) /* override */; + virtual StringVal* Finish() /* override */; + + DECLARE_SERIAL(SHA256Val); + +private: + SHA256_CTX ctx; +}; + +#endif diff --git a/src/SerialTypes.h b/src/SerialTypes.h index 52ef1651de..a25a73945b 100644 --- a/src/SerialTypes.h +++ b/src/SerialTypes.h @@ -98,6 +98,11 @@ SERIAL_VAL(RECORD_VAL, 10) SERIAL_VAL(ENUM_VAL, 11) SERIAL_VAL(VECTOR_VAL, 12) SERIAL_VAL(MUTABLE_VAL, 13) +SERIAL_VAL(OPAQUE_VAL, 14) +SERIAL_VAL(HASH_VAL, 15) +SERIAL_VAL(MD5_VAL, 16) +SERIAL_VAL(SHA1_VAL, 17) +SERIAL_VAL(SHA256_VAL, 18) #define SERIAL_EXPR(name, val) SERIAL_CONST(name, val, EXPR) SERIAL_EXPR(EXPR, 1) diff --git a/src/Val.cc b/src/Val.cc index 79fa8a0c69..f9a59f6743 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -3114,6 +3114,38 @@ void VectorVal::ValDescribe(ODesc* d) const d->Add("]"); } +OpaqueVal::OpaqueVal(OpaqueType* t) : opaque_type(t) { } + +OpaqueVal::~OpaqueVal() + { + Unref(opaque_type); + } + +bool OpaqueVal::IsValid() const + { + return false; + } + +IMPLEMENT_SERIAL(OpaqueVal, SER_OPAQUE_VAL); + +bool OpaqueVal::DoSerialize(SerialInfo* info) const + { + DO_SERIALIZE(SER_OPAQUE_VAL, Val); + assert(opaque_type); + // TODO: how to serialize a serializable class? + //return SERIALIZE(*opaque_type); + return false; + } + +bool OpaqueVal::DoUnserialize(UnserialInfo* info) + { + DO_UNSERIALIZE(Val); + // TODO: how to deserialize a serializable class? + //opaque_type = new OpaqueType(); + //return UNSERIALIZE(opaque_type); + return false; + } + Val* check_and_promote(Val* v, const BroType* t, int is_init) { diff --git a/src/Val.h b/src/Val.h index c3ec5b04fb..925fb5a2b0 100644 --- a/src/Val.h +++ b/src/Val.h @@ -1013,6 +1013,24 @@ protected: VectorType* vector_type; }; +// See OpaqueVal.h for derived classes. +class OpaqueVal : public Val { +public: + OpaqueVal(OpaqueType* t); + virtual ~OpaqueVal(); + + // Determines whether the opaque value is in a valid state. + virtual bool IsValid() const; + +protected: + friend class Val; + OpaqueVal() { } + + DECLARE_SERIAL(OpaqueVal); + + OpaqueType* opaque_type; +}; + // Checks the given value for consistency with the given type. If an // exact match, returns it. If promotable, returns the promoted version,