Commit 3bd9bb8d77521f3fb0181366463e1c93d48aaa2e

Edward Thomson 2022-04-04T13:28:40

sha256: support dynamically loaded openssl

diff --git a/cmake/SelectHashes.cmake b/cmake/SelectHashes.cmake
index 29a50b6..faf9e2e 100644
--- a/cmake/SelectHashes.cmake
+++ b/cmake/SelectHashes.cmake
@@ -26,6 +26,10 @@ if(USE_SHA1 STREQUAL "CollisionDetection")
 	set(GIT_SHA1_COLLISIONDETECT 1)
 elseif(USE_SHA1 STREQUAL "OpenSSL")
 	set(GIT_SHA1_OPENSSL 1)
+elseif(USE_SHA1 STREQUAL "OpenSSL-Dynamic")
+	set(GIT_SHA1_OPENSSL 1)
+	set(GIT_SHA1_OPENSSL_DYNAMIC 1)
+	list(APPEND LIBGIT2_SYSTEM_LIBS dl)
 elseif(USE_SHA1 STREQUAL "CommonCrypto")
 	set(GIT_SHA1_COMMON_CRYPTO 1)
 elseif(USE_SHA1 STREQUAL "mbedTLS")
@@ -58,6 +62,10 @@ if(USE_SHA256 STREQUAL "Builtin")
 	set(GIT_SHA256_BUILTIN 1)
 elseif(USE_SHA256 STREQUAL "OpenSSL")
 	set(GIT_SHA256_OPENSSL 1)
+elseif(USE_SHA256 STREQUAL "OpenSSL-Dynamic")
+	set(GIT_SHA256_OPENSSL 1)
+	set(GIT_SHA256_OPENSSL_DYNAMIC 1)
+	list(APPEND LIBGIT2_SYSTEM_LIBS dl)
 elseif(USE_SHA256 STREQUAL "CommonCrypto")
 	set(GIT_SHA256_COMMON_CRYPTO 1)
 elseif(USE_SHA256 STREQUAL "mbedTLS")
diff --git a/src/features.h.in b/src/features.h.in
index f6510ae..e14e833 100644
--- a/src/features.h.in
+++ b/src/features.h.in
@@ -46,12 +46,14 @@
 #cmakedefine GIT_SHA1_WIN32 1
 #cmakedefine GIT_SHA1_COMMON_CRYPTO 1
 #cmakedefine GIT_SHA1_OPENSSL 1
+#cmakedefine GIT_SHA1_OPENSSL_DYNAMIC 1
 #cmakedefine GIT_SHA1_MBEDTLS 1
 
 #cmakedefine GIT_SHA256_BUILTIN 1
 #cmakedefine GIT_SHA256_WIN32 1
 #cmakedefine GIT_SHA256_COMMON_CRYPTO 1
 #cmakedefine GIT_SHA256_OPENSSL 1
+#cmakedefine GIT_SHA256_OPENSSL_DYNAMIC 1
 #cmakedefine GIT_SHA256_MBEDTLS 1
 
 #cmakedefine GIT_RAND_GETENTROPY 1
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
index 6ac8bfe..b283395 100644
--- a/src/util/CMakeLists.txt
+++ b/src/util/CMakeLists.txt
@@ -33,7 +33,7 @@ if(USE_SHA1 STREQUAL "CollisionDetection")
 	target_compile_definitions(util PRIVATE SHA1DC_NO_STANDARD_INCLUDES=1)
         target_compile_definitions(util PRIVATE SHA1DC_CUSTOM_INCLUDE_SHA1_C=\"git2_util.h\")
         target_compile_definitions(util PRIVATE SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C=\"git2_util.h\")
-elseif(USE_SHA1 STREQUAL "OpenSSL")
+elseif(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA1 STREQUAL "OpenSSL-Dynamic")
 	file(GLOB UTIL_SRC_SHA1 hash/openssl.*)
 elseif(USE_SHA1 STREQUAL "CommonCrypto")
 	file(GLOB UTIL_SRC_SHA1 hash/common_crypto.*)
@@ -49,7 +49,7 @@ list(SORT UTIL_SRC_SHA1)
 
 if(USE_SHA256 STREQUAL "Builtin")
 	file(GLOB UTIL_SRC_SHA256 hash/builtin.* hash/rfc6234/*)
-elseif(USE_SHA256 STREQUAL "OpenSSL")
+elseif(USE_SHA256 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL-Dynamic")
 	file(GLOB UTIL_SRC_SHA256 hash/openssl.*)
 elseif(USE_SHA256 STREQUAL "CommonCrypto")
 	file(GLOB UTIL_SRC_SHA256 hash/common_crypto.*)
diff --git a/src/util/hash/openssl.c b/src/util/hash/openssl.c
index f95ddb7..649358c 100644
--- a/src/util/hash/openssl.c
+++ b/src/util/hash/openssl.c
@@ -7,10 +7,67 @@
 
 #include "openssl.h"
 
+#ifdef GIT_OPENSSL_DYNAMIC
+# include <dlfcn.h>
+
+int handle_count;
+void *openssl_handle;
+
+static int git_hash_openssl_global_shutdown(void)
+{
+	if (--handle_count == 0) {
+		dlclose(openssl_handle);
+		openssl_handle = NULL;
+	}
+
+	return 0;
+}
+
+static int git_hash_openssl_global_init(void)
+{
+	if (!handle_count) {
+		if ((openssl_handle = dlopen("libssl.so.1.1", RTLD_NOW)) == NULL &&
+		    (openssl_handle = dlopen("libssl.1.1.dylib", RTLD_NOW)) == NULL &&
+		    (openssl_handle = dlopen("libssl.so.1.0.0", RTLD_NOW)) == NULL &&
+		    (openssl_handle = dlopen("libssl.1.0.0.dylib", RTLD_NOW)) == NULL &&
+		    (openssl_handle = dlopen("libssl.so.10", RTLD_NOW)) == NULL) {
+			git_error_set(GIT_ERROR_SSL, "could not load ssl libraries");
+			return -1;
+		}
+	}
+
+	if (git_hash_openssl_global_shutdown() < 0)
+		return -1;
+
+	handle_count++;
+	return 0;
+}
+
+#endif
+
 #ifdef GIT_SHA1_OPENSSL
 
+# ifdef GIT_OPENSSL_DYNAMIC
+static int (*SHA1_Init)(SHA_CTX *c);
+static int (*SHA1_Update)(SHA_CTX *c, const void *data, size_t len);
+static int (*SHA1_Final)(unsigned char *md, SHA_CTX *c);
+# endif
+
 int git_hash_sha1_global_init(void)
 {
+#ifdef GIT_OPENSSL_DYNAMIC
+	if (git_hash_openssl_global_init() < 0)
+		return -1;
+
+	if ((SHA1_Init = dlsym(openssl_handle, "SHA1_Init")) == NULL ||
+	    (SHA1_Update = dlsym(openssl_handle, "SHA1_Update")) == NULL ||
+	    (SHA1_Final = dlsym(openssl_handle, "SHA1_Final")) == NULL) {
+		const char *msg = dlerror();
+		git_error_set(GIT_ERROR_SSL, "could not load hash function: %s", msg ? msg : "unknown error");
+		return -1;
+	}
+#endif
+
 	return 0;
 }
 
@@ -64,8 +121,27 @@ int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx)
 
 #ifdef GIT_SHA256_OPENSSL
 
+# ifdef GIT_OPENSSL_DYNAMIC
+static int (*SHA256_Init)(SHA256_CTX *c);
+static int (*SHA256_Update)(SHA256_CTX *c, const void *data, size_t len);
+static int (*SHA256_Final)(unsigned char *md, SHA256_CTX *c);
+#endif
+
 int git_hash_sha256_global_init(void)
 {
+#ifdef GIT_OPENSSL_DYNAMIC
+	if (git_hash_openssl_global_init() < 0)
+		return -1;
+
+	if ((SHA256_Init = dlsym(openssl_handle, "SHA256_Init")) == NULL ||
+	    (SHA256_Update = dlsym(openssl_handle, "SHA256_Update")) == NULL ||
+	    (SHA256_Final = dlsym(openssl_handle, "SHA256_Final")) == NULL) {
+		const char *msg = dlerror();
+		git_error_set(GIT_ERROR_SSL, "could not load hash function: %s", msg ? msg : "unknown error");
+		return -1;
+	}
+#endif
+
 	return 0;
 }
 
diff --git a/src/util/hash/openssl.h b/src/util/hash/openssl.h
index ff4b6d6..7cb089a 100644
--- a/src/util/hash/openssl.h
+++ b/src/util/hash/openssl.h
@@ -10,7 +10,25 @@
 
 #include "hash/sha.h"
 
-#include <openssl/sha.h>
+#ifndef GIT_OPENSSL_DYNAMIC
+# include <openssl/sha.h>
+#else
+
+typedef struct {
+	unsigned int h0, h1, h2, h3, h4;
+	unsigned int Nl, Nh;
+	unsigned int data[16];
+	unsigned int num;
+} SHA_CTX;
+
+typedef struct {
+	unsigned int h[8];
+	unsigned int Nl, Nh;
+	unsigned int data[16];
+	unsigned int num, md_len;
+} SHA256_CTX;
+
+#endif
 
 #ifdef GIT_SHA1_OPENSSL
 struct git_hash_sha1_ctx {