-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Dynamically load OpenSSL (optionally) #5974
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
src/streams/openssl.c
Outdated
{ | ||
int err = 0; | ||
|
||
if ((openssl_handle = dlopen("libssl.so.1.1", RTLD_NOW)) == NULL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this is flexible enough to work with all linux distros. For example, I recall that RHEL derivatives have a completely different naming scheme for their OpenSSL libraries. This StackExchange answer gives an example of what I'm talking about. The RHEL library is named libssl.so.10
.
Would doing something like what is suggested in that answer be possible to dynamically look up the name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, we can definitely load libssl.so.10
. The tricky bit is going to be the API differences over the years, and identifying when to fallback to them because there's no "give me your version number" API in ye olde days. I think that we can determine this based on identifying whether symbols exist or not, but it's not going to be particularly pretty. 😭
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I spent some more time looking into this, and it does seem that in the newest versions, RHEL/CentOS have decided to ship OpenSSL 1.1 with standard naming scheme, so they do have libssl.so.1.1
. However, looking at .NET 5 - Supported OS versions, Microsoft is still supporting RHEL/CentOS 7, which just has the non-standard 1.0 name for the library. It doesn't look like this is changing for .NET 6 either.
Would it be possible to attempt to open libssl.so.1.1
and if that fails try libssl.so.10
and use that to determine which versions of the APIs to call?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to attempt to open libssl.so.1.1 and if that fails try libssl.so.10 and use that to determine which versions of the APIs to call?
Yes - this would be possible. But it's not yet clear to me whether libssl.so.10
always corresponds to a particular ABI - on my centos 7.5.1804 installation this is a link to libssl.1.0.2k
but I don't know if that's a guarantee across all centos 7 minors and the corresponding rhel releases. Need to do a little more investigation.
With dynamic loading it could make sense to make OpenSSL optional. If git_openssl_stream_global_init is postponed until the first time it is needed it should be possible to use the same package with or without OpenSSL. Perhaps a package maintainer can mark OpenSSL as recommended instead of required, and it should be possible to install without having to restart libgit2. diff --git a/src/libgit2.c b/src/libgit2.c
index 089c83590..908d14237 100644
--- a/src/libgit2.c
+++ b/src/libgit2.c
@@ -82,7 +82,6 @@ int git_libgit2_init(void)
git_merge_driver_global_init,
git_transport_ssh_global_init,
git_stream_registry_global_init,
- git_openssl_stream_global_init,
git_mbedtls_stream_global_init,
git_mwindow_global_init,
git_pool_global_init,
diff --git a/src/streams/openssl.c b/src/streams/openssl.c
index 919bbe48a..1bedf4d6f 100644
--- a/src/streams/openssl.c
+++ b/src/streams/openssl.c
@@ -1005,6 +1005,9 @@ static int openssl_stream_wrap(
{
openssl_stream *st;
+ if (git__ssl_ctx == NULL && git_openssl_stream_global_init() != 0)
+ return -1;
+
GIT_ASSERT_ARG(out);
GIT_ASSERT_ARG(in);
GIT_ASSERT_ARG(host);
@@ -1067,6 +1070,9 @@ int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
int git_openssl__set_cert_location(const char *file, const char *path)
{
+ if (git__ssl_ctx == NULL && git_openssl_stream_global_init() != 0)
+ return -1;
+
if (_SSL_CTX_load_verify_locations(git__ssl_ctx, file, path) == 0) {
char errmsg[256]; |
Yes, I've been thinking that as well. My first effort has been getting this working across multiple OpenSSL versions which has been 😡 I'm a bit stuck on our containerized build at the moment. My build on CentOS 7 seems to fail to find libssh2 when running in CI, but works great when I run it locally. Reproducibility was supposed to be the entire point of this dockerized build setup, so I'm both frustrated and stumped as to what's going on. I can unblock this by just turning off ssh support for those builds, I suppose, but I won't have a chance to get this next iteration pushed up until the weekend. After it's working across multiple different OpenSSL versions, I can think about delaying that dynamic load and init step until it's necessary. |
8741037
to
33224c9
Compare
Refactor the OpenSSL stream implementation so that the legacy code is better abstracted. This will enable future development.
Provide an interface around OpenSSL to dynamically load the libraries and symbols, so that users can distribute a libgit2 library that is not linked directly against OpenSSL. This enables users to target multiple distributions with a single binary. This mechanism is optional and disabled by default. Configure cmake with -DUSE_HTTPS=OpenSSL-Dynamic to use it.
b87d84d
to
05c1487
Compare
dlopen sets up some thread-local state that isn't cleaned up by `dlclose`. Additionally, now that we're linking against different versions of libssh2 and OpenSSL, we're seeing different leak signatures.
The ntlmclient dependency can now dynamically load OpenSSL.
Defer dlopen until it's needed when dynamically loading OpenSSL libraries.
Add Xenial, Bionic, CentOS 7 and 8 workflows with OpenSSL-Dynamic builds nightly.
429fe4b
to
314469f
Compare
I'm going to go ahead and merge this, I feel like it's not the prettiest of solutions but it's reasonable, it's seen a lot of local testing against different OpenSSL versions > 1.0 and has seen a lot of CI action across multiple platforms. |
@ethomson Since this is merged, do you feel it's ready to pull into LibGit2Sharp's native binaries package and then revert the managed HTTPS stuff, or would it be better to wait for it be part of a libgit2 release? |
@bording I'm feeling good about this but I'm also going to push for a v1.2.0 to this weekend. I want to pull in a few more PRs (esp around midx) and then 🚢 |
The OpenSSL dependency is a painful one for people who want to distribute pre-built binaries for a variety of Linux distributions. LibGit2Sharp is an example of this, and they have taken the steps to add their own https backend using .NET Core calls. This provides a second option for them.