commit ae5f85ee913ad86b5e0d2c9e56bdb3ad7fae685b
parent 0c37d1a43650261685c1cea2c87adf7487f3c40b
Author: cfillion <cfillion@users.noreply.github.com>
Date: Sun, 8 May 2022 11:01:52 -0400
add support for Linux systems shipping with OpenSSL 3
Fixes #47
Diffstat:
5 files changed, 131 insertions(+), 10 deletions(-)
diff --git a/.appveyor.yml b/.appveyor.yml
@@ -10,6 +10,7 @@ build_script:
-DCMAKE_TOOLCHAIN_FILE=~/vcpkg/scripts/buildsystems/vcpkg.cmake
-DVCPKG_TARGET_TRIPLET=arch-env -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=$TOOLCHAIN
-DCMAKE_OSX_ARCHITECTURES=$ARCH -DCMAKE_OSX_DEPLOYMENT_TARGET=$DEPLOY_TARGET
+ -DRUNTIME_OPENSSL=YES
- cmake --build build
test_script:
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -1,5 +1,8 @@
cmake_minimum_required(VERSION 3.15)
+option(RUNTIME_OPENSSL
+ "Load OpenSSL at runtime instead of linking against a specific version" OFF)
+
if(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
CACHE STRING "")
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
@@ -139,7 +139,11 @@ target_link_libraries(reapack
)
if(OPENSSL_FOUND)
- target_link_libraries(reapack OpenSSL::Crypto)
+ if(RUNTIME_OPENSSL)
+ target_compile_definitions(reapack PRIVATE RUNTIME_OPENSSL)
+ else()
+ target_link_libraries(reapack OpenSSL::Crypto)
+ endif()
endif()
if(SWELL_FOUND)
diff --git a/src/hash.cpp b/src/hash.cpp
@@ -111,14 +111,9 @@ private:
unsigned long m_hashLength;
};
-#else // Unix systems
-
-# ifdef __APPLE__
-# define COMMON_DIGEST_FOR_OPENSSL
-# include <CommonCrypto/CommonDigest.h>
-# else
-# include <openssl/sha.h>
-# endif
+#elif __APPLE__
+# define COMMON_DIGEST_FOR_OPENSSL
+# include <CommonCrypto/CommonDigest.h>
class Hash::SHA256Context : public Hash::Context {
public:
@@ -146,6 +141,120 @@ private:
SHA256_CTX m_context;
};
+#else
+# include <openssl/evp.h>
+
+# ifdef RUNTIME_OPENSSL
+# include <dlfcn.h>
+
+static struct OpenSSL {
+ OpenSSL()
+ : m_loaded { true }
+ {
+ constexpr const char *names[] { "libcrypto.so.3", "libcrypto.so.1.1" };
+
+ for(const char *name : names) {
+ if((m_so = dlopen(name, RTLD_LAZY)))
+ return;
+ }
+
+ m_loaded = false;
+ }
+
+ ~OpenSSL()
+ {
+ if(m_so)
+ dlclose(m_so);
+ }
+
+ bool isLoaded() const { return m_loaded; }
+
+ template<typename T> T get(const char *name)
+ {
+ const T func { m_so ? reinterpret_cast<T>(dlsym(m_so, name)) : nullptr };
+ if(!func)
+ m_loaded = false;
+ return func;
+ }
+
+private:
+ void *m_so;
+ bool m_loaded;
+} g_openssl;
+
+# define IMPORT_OPENSSL(func) \
+ static auto _##func { g_openssl.get<decltype(&func)>(#func) };
+
+IMPORT_OPENSSL(EVP_DigestFinal_ex);
+# define EVP_DigestFinal_ex _EVP_DigestFinal_ex
+IMPORT_OPENSSL(EVP_DigestInit_ex);
+# define EVP_DigestInit_ex _EVP_DigestInit_ex
+IMPORT_OPENSSL(EVP_DigestUpdate);
+# define EVP_DigestUpdate _EVP_DigestUpdate
+IMPORT_OPENSSL(EVP_MD_CTX_new);
+# define EVP_MD_CTX_new _EVP_MD_CTX_new
+IMPORT_OPENSSL(EVP_MD_CTX_free);
+# define EVP_MD_CTX_free _EVP_MD_CTX_free
+# ifdef EVP_MD_size // OpenSSL 3
+IMPORT_OPENSSL(EVP_MD_get_size);
+# undef EVP_MD_size
+# define EVP_MD_size _EVP_MD_get_size
+# else
+IMPORT_OPENSSL(EVP_MD_size);
+# define EVP_MD_size _EVP_MD_size
+# endif
+IMPORT_OPENSSL(EVP_sha256);
+# define EVP_sha256 _EVP_sha256
+# endif
+
+class Hash::EVPContext : public Hash::Context {
+public:
+ static const EVP_MD *getAlgo(const Algorithm algo)
+ {
+#ifdef RUNTIME_OPENSSL
+ if(!g_openssl.isLoaded())
+ return nullptr;
+#endif
+
+ switch(algo) {
+ case SHA256:
+ return EVP_sha256();
+ default:
+ return nullptr;
+ }
+ }
+
+ EVPContext(const EVP_MD *md)
+ : m_md { md }
+ {
+ m_ctx = EVP_MD_CTX_new();
+ EVP_DigestInit_ex(m_ctx, m_md, nullptr);
+ }
+
+ ~EVPContext()
+ {
+ EVP_MD_CTX_free(m_ctx);
+ }
+
+ size_t hashSize() const override
+ {
+ return EVP_MD_size(m_md);
+ }
+
+ void addData(const char *data, const size_t len) override
+ {
+ EVP_DigestUpdate(m_ctx, data, len);
+ }
+
+ void getHash(unsigned char *out) override
+ {
+ EVP_DigestFinal_ex(m_ctx, out, nullptr);
+ }
+
+private:
+ EVP_MD_CTX *m_ctx;
+ const EVP_MD *m_md;
+};
#endif
Hash::Hash(const Algorithm algo)
@@ -154,12 +263,15 @@ Hash::Hash(const Algorithm algo)
#ifdef _WIN32
if(const auto &algoProvider = CNGAlgorithmProvider::get(algo))
m_context = std::make_unique<CNGContext>(algoProvider);
-#else
+#elif __APPLE__
switch(algo) {
case SHA256:
m_context = std::make_unique<SHA256Context>();
break;
}
+#else
+ if(const auto &algoDesc = EVPContext::getAlgo(algo))
+ m_context = std::make_unique<EVPContext>(algoDesc);
#endif
}
diff --git a/src/hash.hpp b/src/hash.hpp
@@ -46,6 +46,7 @@ private:
class CNGContext;
class SHA256Context;
+ class EVPContext;
Algorithm m_algo;
std::string m_value;