diff --git a/src/Hash.cc b/src/Hash.cc index d139b2abb8..99dc21493b 100644 --- a/src/Hash.cc +++ b/src/Hash.cc @@ -45,7 +45,7 @@ void KeyedHash::InitializeSeeds(const std::array& seed // yes, we use the same buffer twice to initialize two different keys. This should not really be // a security problem of any kind: hmac-md5 is not really used anymore - and even if it was, the // hashes should not reveal any information about their initialization vector. - static_assert(sizeof(shared_highwayhash_key) == SHA256_DIGEST_LENGTH); + static_assert(sizeof(shared_highwayhash_key) == ZEEK_SHA256_DIGEST_LENGTH); calculate_digest(Hash_SHA256, (const u_char*)seed_data.data(), sizeof(seed_data) - 16, reinterpret_cast(shared_highwayhash_key)); memcpy(shared_siphash_key, reinterpret_cast(seed_data.data()) + 64, 16); diff --git a/src/OpaqueVal.cc b/src/OpaqueVal.cc index c323cb7a2e..8ab076e311 100644 --- a/src/OpaqueVal.cc +++ b/src/OpaqueVal.cc @@ -12,6 +12,9 @@ #include #include +#include +#include +#include #include #include "zeek/CompHash.h" @@ -20,9 +23,18 @@ #include "zeek/Reporter.h" #include "zeek/Scope.h" #include "zeek/Var.h" +#include "zeek/digest.h" #include "zeek/probabilistic/BloomFilter.h" #include "zeek/probabilistic/CardinalityCounter.h" +#if ( OPENSSL_VERSION_NUMBER < 0x10100000L ) || defined(LIBRESSL_VERSION_NUMBER) +inline void* EVP_MD_CTX_md_data(const EVP_MD_CTX* ctx) { return ctx->md_data; } +#endif + +#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) +#include +#endif + namespace zeek { // Helper to retrieve a broker value out of a broker::vector at a specified @@ -193,16 +205,189 @@ StringValPtr HashVal::DoGet() { HashVal::HashVal(OpaqueTypePtr t) : OpaqueVal(std::move(t)) { valid = false; } -MD5Val::MD5Val() : HashVal(md5_type) { memset(&ctx, 0, sizeof(ctx)); } +namespace { + +constexpr size_t MD5VAL_STATE_SIZE = sizeof(MD5_CTX); + +constexpr size_t SHA1VAL_STATE_SIZE = sizeof(SHA_CTX); + +constexpr size_t SHA256VAL_STATE_SIZE = sizeof(SHA256_CTX); -MD5Val::~MD5Val() { #if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - if ( IsValid() ) - EVP_MD_CTX_free(ctx); -#endif + +// -- MD5 + +auto* to_native_ptr(MD5Val::StatePtr ptr) { return reinterpret_cast(ptr); } + +auto* to_digest_ptr(MD5Val::StatePtr ptr) { return reinterpret_cast(ptr); } + +void do_init(MD5Val::StatePtr& ptr) { ptr = reinterpret_cast(detail::hash_init(detail::Hash_MD5)); } + +void do_clone(MD5Val::StatePtr out, MD5Val::StatePtr in) { hash_copy(to_digest_ptr(out), to_digest_ptr(in)); } + +void do_feed(MD5Val::StatePtr ptr, const void* data, size_t size) { + detail::hash_update(to_digest_ptr(ptr), data, size); } -void HashVal::digest_one(EVP_MD_CTX* h, const Val* v) { +void do_get(MD5Val::StatePtr ptr, u_char* digest) { detail::hash_final_no_free(to_digest_ptr(ptr), digest); } + +std::pair do_get_bytes(MD5Val::StatePtr ptr) { + auto* md = reinterpret_cast(EVP_MD_CTX_md_data(to_native_ptr(ptr))); + return {reinterpret_cast(md), sizeof(MD5_CTX)}; +} + +void do_set_bytes(MD5Val::StatePtr ptr, const char* bytes, size_t len) { + auto* md = reinterpret_cast(EVP_MD_CTX_md_data(to_native_ptr(ptr))); + memcpy(md, bytes, len); +} + +void do_destroy(MD5Val::StatePtr ptr) { hash_state_free(to_digest_ptr(ptr)); } + +// -- SHA1 + +auto* to_native_ptr(SHA1Val::StatePtr ptr) { return reinterpret_cast(ptr); } + +auto* to_digest_ptr(SHA1Val::StatePtr ptr) { return reinterpret_cast(ptr); } + +void do_init(SHA1Val::StatePtr& ptr) { + ptr = reinterpret_cast(detail::hash_init(detail::Hash_SHA1)); +} + +void do_clone(SHA1Val::StatePtr out, SHA1Val::StatePtr in) { detail::hash_copy(to_digest_ptr(out), to_digest_ptr(in)); } + +void do_feed(SHA1Val::StatePtr ptr, const void* data, size_t size) { + detail::hash_update(to_digest_ptr(ptr), data, size); +} + +void do_get(SHA1Val::StatePtr ptr, u_char* digest) { detail::hash_final_no_free(to_digest_ptr(ptr), digest); } + +std::pair do_get_bytes(SHA1Val::StatePtr ptr) { + auto* md = reinterpret_cast(EVP_MD_CTX_md_data(to_native_ptr(ptr))); + return {reinterpret_cast(md), sizeof(SHA_CTX)}; +} + +void do_set_bytes(SHA1Val::StatePtr ptr, const char* bytes, size_t len) { + auto* md = reinterpret_cast(EVP_MD_CTX_md_data(to_native_ptr(ptr))); + memcpy(md, bytes, len); +} + +void do_destroy(SHA1Val::StatePtr ptr) { hash_state_free(to_digest_ptr(ptr)); } + +// -- SHA256 + +auto* to_native_ptr(SHA256Val::StatePtr ptr) { return reinterpret_cast(ptr); } + +auto* to_digest_ptr(SHA256Val::StatePtr ptr) { return reinterpret_cast(ptr); } + +void do_init(SHA256Val::StatePtr& ptr) { + ptr = reinterpret_cast(detail::hash_init(detail::Hash_SHA256)); +} + +void do_clone(SHA256Val::StatePtr out, SHA256Val::StatePtr in) { + detail::hash_copy(to_digest_ptr(out), to_digest_ptr(in)); +} + +void do_feed(SHA256Val::StatePtr ptr, const void* data, size_t size) { + detail::hash_update(to_digest_ptr(ptr), data, size); +} + +void do_get(SHA256Val::StatePtr ptr, u_char* digest) { detail::hash_final_no_free(to_digest_ptr(ptr), digest); } + +std::pair do_get_bytes(SHA256Val::StatePtr ptr) { + auto* md = reinterpret_cast(EVP_MD_CTX_md_data(to_native_ptr(ptr))); + return {reinterpret_cast(md), sizeof(SHA256_CTX)}; +} + +void do_set_bytes(SHA256Val::StatePtr ptr, const char* bytes, size_t len) { + auto* md = reinterpret_cast(EVP_MD_CTX_md_data(to_native_ptr(ptr))); + memcpy(md, bytes, len); +} + +void do_destroy(SHA256Val::StatePtr ptr) { hash_state_free(to_digest_ptr(ptr)); } + +#else + +// -- MD5 + +auto* to_native_ptr(MD5Val::StatePtr ptr) { return reinterpret_cast(ptr); } + +void do_init(MD5Val::StatePtr& ptr) { + auto ctx = new MD5_CTX; + MD5_Init(ctx); + ptr = reinterpret_cast(ctx); +} + +void do_clone(MD5Val::StatePtr out, MD5Val::StatePtr in) { *to_native_ptr(out) = *to_native_ptr(in); } + +void do_feed(MD5Val::StatePtr ptr, const void* data, size_t size) { MD5_Update(to_native_ptr(ptr), data, size); } + +void do_get(MD5Val::StatePtr ptr, u_char* digest) { MD5_Final(digest, to_native_ptr(ptr)); } + +std::pair do_get_bytes(MD5Val::StatePtr ptr) { + return {reinterpret_cast(ptr), sizeof(MD5_CTX)}; +} + +void do_set_bytes(MD5Val::StatePtr ptr, const char* bytes, size_t len) { memcpy(ptr, bytes, len); } + +void do_destroy(MD5Val::StatePtr ptr) { delete to_native_ptr(ptr); } + +// -- SHA1 + +auto* to_native_ptr(SHA1Val::StatePtr ptr) { return reinterpret_cast(ptr); } + +void do_init(SHA1Val::StatePtr& ptr) { + auto ctx = new SHA_CTX; + SHA1_Init(ctx); + ptr = reinterpret_cast(ctx); +} + +void do_clone(SHA1Val::StatePtr out, SHA1Val::StatePtr in) { *to_native_ptr(out) = *to_native_ptr(in); } + +void do_feed(SHA1Val::StatePtr ptr, const void* data, size_t size) { SHA1_Update(to_native_ptr(ptr), data, size); } + +void do_get(SHA1Val::StatePtr ptr, u_char* digest) { SHA1_Final(digest, to_native_ptr(ptr)); } + +std::pair do_get_bytes(SHA1Val::StatePtr ptr) { + return {reinterpret_cast(ptr), sizeof(SHA_CTX)}; +} + +void do_set_bytes(SHA1Val::StatePtr ptr, const char* bytes, size_t len) { memcpy(ptr, bytes, len); } + +void do_destroy(SHA1Val::StatePtr ptr) { delete to_native_ptr(ptr); } + +// -- SHA256 + +auto* to_native_ptr(SHA256Val::StatePtr ptr) { return reinterpret_cast(ptr); } + +void do_init(SHA256Val::StatePtr& ptr) { + auto ctx = new SHA256_CTX; + SHA256_Init(ctx); + ptr = reinterpret_cast(ctx); +} + +void do_clone(SHA256Val::StatePtr out, SHA256Val::StatePtr in) { *to_native_ptr(out) = *to_native_ptr(in); } + +void do_feed(SHA256Val::StatePtr ptr, const void* data, size_t size) { SHA256_Update(to_native_ptr(ptr), data, size); } + +void do_get(SHA256Val::StatePtr ptr, u_char* digest) { SHA256_Final(digest, to_native_ptr(ptr)); } + +std::pair do_get_bytes(SHA256Val::StatePtr ptr) { + return {reinterpret_cast(ptr), sizeof(SHA256_CTX)}; +} + +void do_set_bytes(SHA256Val::StatePtr ptr, const char* bytes, size_t len) { memcpy(ptr, bytes, len); } + +void do_destroy(SHA256Val::StatePtr ptr) { delete to_native_ptr(ptr); } + +#endif + +} // namespace + +MD5Val::MD5Val() : HashVal(md5_type) { memset(&ctx, 0, sizeof(ctx)); } + +MD5Val::~MD5Val() { do_destroy(ctx); } + +void HashVal::digest_one(detail::HashDigestState* h, const Val* v) { if ( v->GetType()->Tag() == TYPE_STRING ) { const String* str = v->AsString(); detail::hash_update(h, str->Bytes(), str->Len()); @@ -214,7 +399,7 @@ void HashVal::digest_one(EVP_MD_CTX* h, const Val* v) { } } -void HashVal::digest_one(EVP_MD_CTX* h, const ValPtr& v) { digest_one(h, v.get()); } +void HashVal::digest_one(detail::HashDigestState* h, const ValPtr& v) { digest_one(h, v.get()); } ValPtr MD5Val::DoClone(CloneState* state) { auto out = make_intrusive(); @@ -222,12 +407,7 @@ ValPtr MD5Val::DoClone(CloneState* state) { if ( IsValid() ) { if ( ! out->Init() ) return nullptr; - -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - EVP_MD_CTX_copy_ex(out->ctx, ctx); -#else - out->ctx = ctx; -#endif + do_clone(out->ctx, ctx); } return state->NewClone(this, std::move(out)); @@ -235,23 +415,14 @@ ValPtr MD5Val::DoClone(CloneState* state) { bool MD5Val::DoInit() { assert(! IsValid()); -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - ctx = detail::hash_init(detail::Hash_MD5); -#else - MD5_Init(&ctx); -#endif + do_init(ctx); return true; } bool MD5Val::DoFeed(const void* data, size_t size) { if ( ! IsValid() ) return false; - -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - detail::hash_update(ctx, data, size); -#else - MD5_Update(&ctx, data, size); -#endif + do_feed(ctx, data, size); return true; } @@ -259,12 +430,8 @@ StringValPtr MD5Val::DoGet() { if ( ! IsValid() ) return val_mgr->EmptyString(); - u_char digest[MD5_DIGEST_LENGTH]; -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - detail::hash_final(ctx, digest); -#else - MD5_Final(digest, &ctx); -#endif + u_char digest[ZEEK_MD5_DIGEST_LENGTH]; + do_get(ctx, digest); return make_intrusive(detail::md5_digest_print(digest)); } @@ -274,12 +441,8 @@ broker::expected MD5Val::DoSerialize() const { if ( ! IsValid() ) return {broker::vector{false}}; -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - MD5_CTX* md = (MD5_CTX*)EVP_MD_CTX_md_data(ctx); - auto data = std::string(reinterpret_cast(md), sizeof(MD5_CTX)); -#else - auto data = std::string(reinterpret_cast(&ctx), sizeof(ctx)); -#endif + auto [bytes, len] = do_get_bytes(ctx); + auto data = std::string{bytes, len}; broker::vector d = {true, data}; return {std::move(d)}; @@ -306,31 +469,17 @@ bool MD5Val::DoUnserialize(const broker::data& data) { if ( ! s ) return false; -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - if ( sizeof(MD5_CTX) != s->size() ) -#else - if ( sizeof(ctx) != s->size() ) -#endif + if ( s->size() != MD5VAL_STATE_SIZE ) return false; Init(); -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - MD5_CTX* md = (MD5_CTX*)EVP_MD_CTX_md_data(ctx); - memcpy(md, s->data(), s->size()); -#else - memcpy(&ctx, s->data(), s->size()); -#endif + do_set_bytes(ctx, s->data(), s->size()); return true; } -SHA1Val::SHA1Val() : HashVal(sha1_type) { memset(&ctx, 0, sizeof(ctx)); } +SHA1Val::SHA1Val() : HashVal(sha1_type) {} -SHA1Val::~SHA1Val() { -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - if ( IsValid() ) - EVP_MD_CTX_free(ctx); -#endif -} +SHA1Val::~SHA1Val() { do_destroy(ctx); } ValPtr SHA1Val::DoClone(CloneState* state) { auto out = make_intrusive(); @@ -339,11 +488,7 @@ ValPtr SHA1Val::DoClone(CloneState* state) { if ( ! out->Init() ) return nullptr; -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - EVP_MD_CTX_copy_ex(out->ctx, ctx); -#else - out->ctx = ctx; -#endif + do_clone(out->ctx, ctx); } return state->NewClone(this, std::move(out)); @@ -351,11 +496,7 @@ ValPtr SHA1Val::DoClone(CloneState* state) { bool SHA1Val::DoInit() { assert(! IsValid()); -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - ctx = detail::hash_init(detail::Hash_SHA1); -#else - SHA1_Init(&ctx); -#endif + do_init(ctx); return true; } @@ -363,11 +504,7 @@ bool SHA1Val::DoFeed(const void* data, size_t size) { if ( ! IsValid() ) return false; -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - detail::hash_update(ctx, data, size); -#else - SHA1_Update(&ctx, data, size); -#endif + do_feed(ctx, data, size); return true; } @@ -376,11 +513,7 @@ StringValPtr SHA1Val::DoGet() { return val_mgr->EmptyString(); u_char digest[SHA_DIGEST_LENGTH]; -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - detail::hash_final(ctx, digest); -#else - SHA1_Final(digest, &ctx); -#endif + do_get(ctx, digest); return make_intrusive(detail::sha1_digest_print(digest)); } @@ -390,12 +523,8 @@ broker::expected SHA1Val::DoSerialize() const { if ( ! IsValid() ) return {broker::vector{false}}; -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - SHA_CTX* md = (SHA_CTX*)EVP_MD_CTX_md_data(ctx); - auto data = std::string(reinterpret_cast(md), sizeof(SHA_CTX)); -#else - auto data = std::string(reinterpret_cast(&ctx), sizeof(ctx)); -#endif + auto [bytes, len] = do_get_bytes(ctx); + auto data = std::string{bytes, len}; broker::vector d = {true, data}; @@ -423,30 +552,19 @@ bool SHA1Val::DoUnserialize(const broker::data& data) { if ( ! s ) return false; -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - if ( sizeof(SHA_CTX) != s->size() ) -#else - if ( sizeof(ctx) != s->size() ) -#endif + if ( s->size() != SHA1VAL_STATE_SIZE ) return false; Init(); -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - SHA_CTX* md = (SHA_CTX*)EVP_MD_CTX_md_data(ctx); - memcpy(md, s->data(), s->size()); -#else - memcpy(&ctx, s->data(), s->size()); -#endif + do_set_bytes(ctx, s->data(), s->size()); return true; } -SHA256Val::SHA256Val() : HashVal(sha256_type) { memset(&ctx, 0, sizeof(ctx)); } +SHA256Val::SHA256Val() : HashVal(sha256_type) {} SHA256Val::~SHA256Val() { -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - if ( IsValid() ) - EVP_MD_CTX_free(ctx); -#endif + if ( ctx != nullptr ) + do_destroy(ctx); } ValPtr SHA256Val::DoClone(CloneState* state) { @@ -456,11 +574,7 @@ ValPtr SHA256Val::DoClone(CloneState* state) { if ( ! out->Init() ) return nullptr; -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - EVP_MD_CTX_copy_ex(out->ctx, ctx); -#else - out->ctx = ctx; -#endif + do_clone(out->ctx, ctx); } return state->NewClone(this, std::move(out)); @@ -468,11 +582,7 @@ ValPtr SHA256Val::DoClone(CloneState* state) { bool SHA256Val::DoInit() { assert(! IsValid()); -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - ctx = detail::hash_init(detail::Hash_SHA256); -#else - SHA256_Init(&ctx); -#endif + do_init(ctx); return true; } @@ -480,11 +590,7 @@ bool SHA256Val::DoFeed(const void* data, size_t size) { if ( ! IsValid() ) return false; -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - detail::hash_update(ctx, data, size); -#else - SHA256_Update(&ctx, data, size); -#endif + do_feed(ctx, data, size); return true; } @@ -493,11 +599,7 @@ StringValPtr SHA256Val::DoGet() { return val_mgr->EmptyString(); u_char digest[SHA256_DIGEST_LENGTH]; -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - detail::hash_final(ctx, digest); -#else - SHA256_Final(digest, &ctx); -#endif + do_get(ctx, digest); return make_intrusive(detail::sha256_digest_print(digest)); } @@ -507,12 +609,8 @@ broker::expected SHA256Val::DoSerialize() const { if ( ! IsValid() ) return {broker::vector{false}}; -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - SHA256_CTX* md = (SHA256_CTX*)EVP_MD_CTX_md_data(ctx); - auto data = std::string(reinterpret_cast(md), sizeof(SHA256_CTX)); -#else - auto data = std::string(reinterpret_cast(&ctx), sizeof(ctx)); -#endif + auto [bytes, len] = do_get_bytes(ctx); + auto data = std::string{bytes, len}; broker::vector d = {true, data}; @@ -540,20 +638,11 @@ bool SHA256Val::DoUnserialize(const broker::data& data) { if ( ! s ) return false; -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - if ( sizeof(SHA256_CTX) != s->size() ) -#else - if ( sizeof(ctx) != s->size() ) -#endif + if ( s->size() != SHA256VAL_STATE_SIZE ) return false; Init(); -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - SHA256_CTX* md = (SHA256_CTX*)EVP_MD_CTX_md_data(ctx); - memcpy(md, s->data(), s->size()); -#else - memcpy(&ctx, s->data(), s->size()); -#endif + do_set_bytes(ctx, s->data(), s->size()); return true; } diff --git a/src/OpaqueVal.h b/src/OpaqueVal.h index 843bed1757..7ff0d1b37e 100644 --- a/src/OpaqueVal.h +++ b/src/OpaqueVal.h @@ -7,9 +7,6 @@ #endif #include -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) -#include -#endif #include #include // for u_char @@ -199,8 +196,8 @@ public: StringValPtr Get(); protected: - static void digest_one(EVP_MD_CTX* h, const Val* v); - static void digest_one(EVP_MD_CTX* h, const ValPtr& v); + static void digest_one(detail::HashDigestState* h, const Val* v); + static void digest_one(detail::HashDigestState* h, const ValPtr& v); explicit HashVal(OpaqueTypePtr t); @@ -215,19 +212,23 @@ private: class MD5Val : public HashVal { public: + struct State; + + using StatePtr = State*; + template - static void digest(const T& vlist, u_char result[MD5_DIGEST_LENGTH]) { + static void digest(const T& vlist, u_char result[ZEEK_MD5_DIGEST_LENGTH]) { digest_all(detail::Hash_MD5, vlist, result); } template - static void hmac(const T& vlist, u_char key[MD5_DIGEST_LENGTH], u_char result[MD5_DIGEST_LENGTH]) { + static void hmac(const T& vlist, u_char key[ZEEK_MD5_DIGEST_LENGTH], u_char result[ZEEK_MD5_DIGEST_LENGTH]) { digest(vlist, result); - for ( int i = 0; i < MD5_DIGEST_LENGTH; ++i ) + for ( int i = 0; i < ZEEK_MD5_DIGEST_LENGTH; ++i ) result[i] ^= key[i]; - detail::internal_md5(result, MD5_DIGEST_LENGTH, result); + detail::internal_md5(result, ZEEK_MD5_DIGEST_LENGTH, result); } MD5Val(); @@ -244,17 +245,17 @@ protected: DECLARE_OPAQUE_VALUE(MD5Val) private: -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - EVP_MD_CTX* ctx; -#else - MD5_CTX ctx; -#endif + StatePtr ctx = nullptr; }; class SHA1Val : public HashVal { public: + struct State; + + using StatePtr = State*; + template - static void digest(const T& vlist, u_char result[SHA_DIGEST_LENGTH]) { + static void digest(const T& vlist, u_char result[ZEEK_SHA_DIGEST_LENGTH]) { digest_all(detail::Hash_SHA1, vlist, result); } @@ -272,17 +273,17 @@ protected: DECLARE_OPAQUE_VALUE(SHA1Val) private: -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - EVP_MD_CTX* ctx; -#else - SHA_CTX ctx; -#endif + StatePtr ctx = nullptr; }; class SHA256Val : public HashVal { public: + struct State; + + using StatePtr = State*; + template - static void digest(const T& vlist, u_char result[SHA256_DIGEST_LENGTH]) { + static void digest(const T& vlist, u_char result[ZEEK_SHA256_DIGEST_LENGTH]) { digest_all(detail::Hash_SHA256, vlist, result); } @@ -300,11 +301,7 @@ protected: DECLARE_OPAQUE_VALUE(SHA256Val) private: -#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER) - EVP_MD_CTX* ctx; -#else - SHA256_CTX ctx; -#endif + StatePtr ctx = nullptr; }; class EntropyVal : public OpaqueVal { diff --git a/src/analyzer/protocol/mime/MIME.cc b/src/analyzer/protocol/mime/MIME.cc index 61fea9a938..e375529565 100644 --- a/src/analyzer/protocol/mime/MIME.cc +++ b/src/analyzer/protocol/mime/MIME.cc @@ -2,6 +2,8 @@ #include "zeek/zeek-config.h" +#include + #include "zeek/Base64.h" #include "zeek/NetVar.h" #include "zeek/Reporter.h" @@ -1123,8 +1125,7 @@ TableValPtr MIME_Message::ToHeaderTable(MIME_HeaderList& hlist) { return t; } -MIME_Mail::MIME_Mail(analyzer::Analyzer* mail_analyzer, bool orig, int buf_size) - : MIME_Message(mail_analyzer), md5_hash() { +MIME_Mail::MIME_Mail(analyzer::Analyzer* mail_analyzer, bool orig, int buf_size) : MIME_Message(mail_analyzer) { analyzer = mail_analyzer; min_overlap_length = zeek::detail::mime_segment_overlap_length; @@ -1179,7 +1180,7 @@ void MIME_Mail::Done() { MIME_Mail::~MIME_Mail() { if ( md5_hash ) - EVP_MD_CTX_free(md5_hash); + zeek::detail::hash_state_free(md5_hash); delete_strings(all_content); delete data_buffer; diff --git a/src/analyzer/protocol/mime/MIME.h b/src/analyzer/protocol/mime/MIME.h index 5d6a87ec3f..2ecdae6122 100644 --- a/src/analyzer/protocol/mime/MIME.h +++ b/src/analyzer/protocol/mime/MIME.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -9,6 +8,7 @@ #include "zeek/Reporter.h" #include "zeek/ZeekString.h" #include "zeek/analyzer/Analyzer.h" +#include "zeek/digest.h" namespace zeek { @@ -254,7 +254,7 @@ protected: int data_start; int compute_content_hash; int content_hash_length; - EVP_MD_CTX* md5_hash; + detail::HashDigestState* md5_hash = nullptr; std::vector entity_content; std::vector all_content; diff --git a/src/analyzer/protocol/ssh/ssh-analyzer.pac b/src/analyzer/protocol/ssh/ssh-analyzer.pac index b93402ce31..34b6f4b407 100644 --- a/src/analyzer/protocol/ssh/ssh-analyzer.pac +++ b/src/analyzer/protocol/ssh/ssh-analyzer.pac @@ -203,7 +203,7 @@ refine flow SSH_Flow += { %{ if ( ssh_server_host_key ) { - unsigned char digest[MD5_DIGEST_LENGTH]; + unsigned char digest[ZEEK_MD5_DIGEST_LENGTH]; zeek::detail::internal_md5(${key}.data(), ${key}.length(), digest); zeek::BifEvent::enqueue_ssh_server_host_key(connection()->zeek_analyzer(), @@ -225,7 +225,7 @@ refine flow SSH_Flow += { %{ if ( ssh_server_host_key ) { - unsigned char digest[MD5_DIGEST_LENGTH]; + unsigned char digest[ZEEK_MD5_DIGEST_LENGTH]; auto ctx = zeek::detail::hash_init(zeek::detail::Hash_MD5); // Fingerprint is calculated over concatenation of modulus + exponent. zeek::detail::hash_update(ctx, ${mod}.data(), ${mod}.length()); diff --git a/src/communityid.bif b/src/communityid.bif index d94321d0cd..562304e5f0 100644 --- a/src/communityid.bif +++ b/src/communityid.bif @@ -86,7 +86,7 @@ function community_id_v1%(cid: conn_id, seed: count &default=0, do_base64: bool std::swap(hash_src_port, hash_dst_port); } - auto digest_update = [](EVP_MD_CTX *ctx, const void* data, unsigned long len) { + auto digest_update = [](auto*ctx, const void* data, unsigned long len) { zeek::detail::hash_update(ctx, data, len); return len; }; @@ -102,7 +102,7 @@ function community_id_v1%(cid: conn_id, seed: count &default=0, do_base64: bool dlen += digest_update(ctx, &hash_src_port, 2); dlen += digest_update(ctx, &hash_dst_port, 2); - u_char digest[SHA_DIGEST_LENGTH]; + u_char digest[ZEEK_SHA_DIGEST_LENGTH]; zeek::detail::hash_final(ctx, digest); // We currently have no real versioning/hash configuration logic, @@ -115,7 +115,7 @@ function community_id_v1%(cid: conn_id, seed: count &default=0, do_base64: bool int outlen = 0; zeek::detail::Base64Converter enc{nullptr}; - enc.Encode(SHA_DIGEST_LENGTH, digest, &outlen, &outbuf); + enc.Encode(ZEEK_SHA_DIGEST_LENGTH, digest, &outlen, &outbuf); res = new zeek::String(ver + std::string(outbuf, outlen)); // When given outlen = 0, the Encode() method creates the // buffer it returns as outbuf, so we must delete it. diff --git a/src/digest.cc b/src/digest.cc index ac2d7d5e09..ab80baaa18 100644 --- a/src/digest.cc +++ b/src/digest.cc @@ -6,11 +6,38 @@ #include "zeek/digest.h" +#include +#include +#include + #include "zeek/Reporter.h" +#if ( OPENSSL_VERSION_NUMBER < 0x10100000L ) || defined(LIBRESSL_VERSION_NUMBER) +#define EVP_MD_CTX_new EVP_MD_CTX_create +#define EVP_MD_CTX_free EVP_MD_CTX_destroy +#endif + +static_assert(ZEEK_MD5_DIGEST_LENGTH == MD5_DIGEST_LENGTH); + +static_assert(ZEEK_SHA_DIGEST_LENGTH == SHA_DIGEST_LENGTH); + +static_assert(ZEEK_SHA224_DIGEST_LENGTH == SHA224_DIGEST_LENGTH); + +static_assert(ZEEK_SHA256_DIGEST_LENGTH == SHA256_DIGEST_LENGTH); + +static_assert(ZEEK_SHA384_DIGEST_LENGTH == SHA384_DIGEST_LENGTH); + +static_assert(ZEEK_SHA512_DIGEST_LENGTH == SHA512_DIGEST_LENGTH); + namespace zeek::detail { -EVP_MD_CTX* hash_init(HashAlgorithm alg) { +namespace { +auto* to_native_ptr(HashDigestState* ptr) { return reinterpret_cast(ptr); } +auto* to_native_ptr(const HashDigestState* ptr) { return reinterpret_cast(ptr); } +auto* to_opaque_ptr(EVP_MD_CTX* ptr) { return reinterpret_cast(ptr); } +} // namespace + +HashDigestState* hash_init(HashAlgorithm alg) { EVP_MD_CTX* c = EVP_MD_CTX_new(); const EVP_MD* md; @@ -33,19 +60,31 @@ EVP_MD_CTX* hash_init(HashAlgorithm alg) { if ( ! EVP_DigestInit_ex(c, md, NULL) ) reporter->InternalError("EVP_DigestInit failed"); - return c; + return to_opaque_ptr(c); } -void hash_update(EVP_MD_CTX* c, const void* data, unsigned long len) { - if ( ! EVP_DigestUpdate(c, data, len) ) +void hash_update(HashDigestState* c, const void* data, unsigned long len) { + if ( ! EVP_DigestUpdate(to_native_ptr(c), data, len) ) reporter->InternalError("EVP_DigestUpdate failed"); } -void hash_final(EVP_MD_CTX* c, u_char* md) { - if ( ! EVP_DigestFinal(c, md, NULL) ) - reporter->InternalError("EVP_DigestFinal failed"); +void hash_final(HashDigestState* c, u_char* md) { + hash_final_no_free(c, md); + EVP_MD_CTX_free(to_native_ptr(c)); +} - EVP_MD_CTX_free(c); +void hash_final_no_free(HashDigestState* c, u_char* md) { + if ( ! EVP_DigestFinal(to_native_ptr(c), md, NULL) ) + reporter->InternalError("EVP_DigestFinal failed"); +} + +void hash_state_free(HashDigestState* c) { + if ( c != nullptr ) + EVP_MD_CTX_free(to_native_ptr(c)); +} + +void hash_copy(HashDigestState* out, const HashDigestState* in) { + EVP_MD_CTX_copy_ex(to_native_ptr(out), to_native_ptr(in)); } unsigned char* internal_md5(const unsigned char* data, unsigned long len, unsigned char* out) { @@ -59,7 +98,7 @@ unsigned char* calculate_digest(HashAlgorithm alg, const unsigned char* data, ui if ( ! out ) out = static_out; // use static array for return, see OpenSSL man page - EVP_MD_CTX* c = hash_init(alg); + auto* c = hash_init(alg); hash_update(c, data, len); hash_final(c, out); return out; diff --git a/src/digest.h b/src/digest.h index bf297e9781..61b063742e 100644 --- a/src/digest.h +++ b/src/digest.h @@ -6,18 +6,31 @@ #pragma once -#include -#include -#include #include // for u_char #include +#include -#if ( OPENSSL_VERSION_NUMBER < 0x10100000L ) || defined(LIBRESSL_VERSION_NUMBER) -#define EVP_MD_CTX_new EVP_MD_CTX_create -#define EVP_MD_CTX_free EVP_MD_CTX_destroy +// Required buffer size for an MD5 digest. +#define ZEEK_MD5_DIGEST_LENGTH 16 -inline void* EVP_MD_CTX_md_data(const EVP_MD_CTX* ctx) { return ctx->md_data; } -#endif +// Required buffer size for an SHA1 digest. +#define ZEEK_SHA_DIGEST_LENGTH 20 + +// Required buffer size for an SHA224 digest. +#define ZEEK_SHA224_DIGEST_LENGTH 28 + +// Required buffer size for an SHA256 digest. +#define ZEEK_SHA256_DIGEST_LENGTH 32 + +// Required buffer size for an SHA384 digest. +#define ZEEK_SHA384_DIGEST_LENGTH 48 + +// Required buffer size for an SHA512 digest. +#define ZEEK_SHA512_DIGEST_LENGTH 64 + +// Buffer size for a digest of any type in hex representation plus size for at +// least a null terminator. +#define ZEEK_DIGEST_PRINT_LENGTH (ZEEK_SHA512_DIGEST_LENGTH * 2) + 1 namespace zeek::detail { @@ -26,29 +39,55 @@ namespace zeek::detail { enum HashAlgorithm { Hash_MD5, Hash_SHA1, Hash_SHA224, Hash_SHA256, Hash_SHA384, Hash_SHA512 }; inline const char* digest_print(const u_char* digest, size_t n) { - static char buf[256]; // big enough for any of md5/sha1/sha256 + static char buf[ZEEK_DIGEST_PRINT_LENGTH]; for ( size_t i = 0; i < n; ++i ) snprintf(buf + i * 2, 3, "%02x", digest[i]); return buf; } -inline const char* md5_digest_print(const u_char digest[MD5_DIGEST_LENGTH]) { - return digest_print(digest, MD5_DIGEST_LENGTH); +inline const char* md5_digest_print(const u_char digest[ZEEK_MD5_DIGEST_LENGTH]) { + return digest_print(digest, ZEEK_MD5_DIGEST_LENGTH); } -inline const char* sha1_digest_print(const u_char digest[SHA_DIGEST_LENGTH]) { - return digest_print(digest, SHA_DIGEST_LENGTH); +inline const char* sha1_digest_print(const u_char digest[ZEEK_SHA_DIGEST_LENGTH]) { + return digest_print(digest, ZEEK_SHA_DIGEST_LENGTH); } -inline const char* sha256_digest_print(const u_char digest[SHA256_DIGEST_LENGTH]) { - return digest_print(digest, SHA256_DIGEST_LENGTH); +inline const char* sha256_digest_print(const u_char digest[ZEEK_SHA256_DIGEST_LENGTH]) { + return digest_print(digest, ZEEK_SHA256_DIGEST_LENGTH); } -EVP_MD_CTX* hash_init(HashAlgorithm alg); +struct HashDigestState; -void hash_update(EVP_MD_CTX* c, const void* data, unsigned long len); +/** + * Allocates and initializes a new HashDigestState. + */ +HashDigestState* hash_init(HashAlgorithm alg); -void hash_final(EVP_MD_CTX* c, u_char* md); +/** + * Adds data to the digest. + */ +void hash_update(HashDigestState* c, const void* data, unsigned long len); + +/** + * Finalizes the digest, writes it to the given buffer and deletes it. + */ +void hash_final(HashDigestState* c, u_char* md); + +/** + * Finalizes the digest and writes it to the given buffer without deleting it afterwards. + */ +void hash_final_no_free(HashDigestState* c, u_char* md); + +/** + * Frees the HashDigestState. + */ +void hash_state_free(HashDigestState* c); + +/** + * Copies the HashDigestState from in to out. + */ +void hash_copy(HashDigestState* out, const HashDigestState* in); unsigned char* internal_md5(const unsigned char* data, unsigned long len, unsigned char* out); diff --git a/src/file_analysis/analyzer/x509/X509.cc b/src/file_analysis/analyzer/x509/X509.cc index 3235d38fb2..af6835edb8 100644 --- a/src/file_analysis/analyzer/x509/X509.cc +++ b/src/file_analysis/analyzer/x509/X509.cc @@ -16,6 +16,7 @@ #endif #include "zeek/Event.h" +#include "zeek/digest.h" #include "zeek/file_analysis/File.h" #include "zeek/file_analysis/Manager.h" #include "zeek/file_analysis/analyzer/x509/events.bif.h" diff --git a/src/probabilistic/BitVector.cc b/src/probabilistic/BitVector.cc index 3037e74e0a..3d0dafe655 100644 --- a/src/probabilistic/BitVector.cc +++ b/src/probabilistic/BitVector.cc @@ -403,7 +403,7 @@ BitVector::size_type BitVector::FindNext(size_type i) const { uint64_t BitVector::Hash() const { u_char buf[SHA256_DIGEST_LENGTH]; uint64_t digest; - EVP_MD_CTX* ctx = zeek::detail::hash_init(zeek::detail::Hash_SHA256); + auto* ctx = zeek::detail::hash_init(zeek::detail::Hash_SHA256); for ( size_type i = 0; i < Blocks(); ++i ) zeek::detail::hash_update(ctx, &bits[i], sizeof(bits[i])); diff --git a/src/probabilistic/Hasher.cc b/src/probabilistic/Hasher.cc index 96a2c0b076..47fb74ab98 100644 --- a/src/probabilistic/Hasher.cc +++ b/src/probabilistic/Hasher.cc @@ -14,9 +14,9 @@ namespace zeek::probabilistic::detail { Hasher::seed_t Hasher::MakeSeed(const void* data, size_t size) { - u_char buf[SHA256_DIGEST_LENGTH]; + u_char buf[ZEEK_SHA256_DIGEST_LENGTH]; seed_t tmpseed; - EVP_MD_CTX* ctx = zeek::detail::hash_init(zeek::detail::Hash_SHA256); + auto* ctx = zeek::detail::hash_init(zeek::detail::Hash_SHA256); assert(sizeof(tmpseed) == 16); diff --git a/src/zeek.bif b/src/zeek.bif index e4d59690ff..797d6d3519 100644 --- a/src/zeek.bif +++ b/src/zeek.bif @@ -586,7 +586,7 @@ function piped_exec%(program: string, to_write: string%): bool ## friends. function md5_hash%(...%): string %{ - unsigned char digest[MD5_DIGEST_LENGTH]; + unsigned char digest[ZEEK_MD5_DIGEST_LENGTH]; MD5Val::digest(@ARG@, digest); return zeek::make_intrusive(zeek::detail::md5_digest_print(digest)); %} @@ -606,7 +606,7 @@ function md5_hash%(...%): string ## friends. function sha1_hash%(...%): string %{ - unsigned char digest[SHA_DIGEST_LENGTH]; + unsigned char digest[ZEEK_SHA_DIGEST_LENGTH]; SHA1Val::digest(@ARG@, digest); return zeek::make_intrusive(zeek::detail::sha1_digest_print(digest)); %} @@ -626,7 +626,7 @@ function sha1_hash%(...%): string ## friends. function sha256_hash%(...%): string %{ - unsigned char digest[SHA256_DIGEST_LENGTH]; + unsigned char digest[ZEEK_SHA256_DIGEST_LENGTH]; SHA256Val::digest(@ARG@, digest); return zeek::make_intrusive(zeek::detail::sha256_digest_print(digest)); %} @@ -642,7 +642,7 @@ function sha256_hash%(...%): string ## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish function md5_hmac%(...%): string %{ - unsigned char hmac[MD5_DIGEST_LENGTH]; + unsigned char hmac[ZEEK_MD5_DIGEST_LENGTH]; MD5Val::hmac(@ARG@, zeek::detail::KeyedHash::shared_hmac_md5_key, hmac); return zeek::make_intrusive(zeek::detail::md5_digest_print(hmac)); %}