Reputation: 390
I know this is a very long explanation but I'm trying to explain everything without having to answer a lot of questions later or get spurious answers.
There is an application that uses an old version of OpenSSL DLLs (no version info in the DLL's) and a later updated version that uses newer OpenSSL libraries for TLS 1.2 (1.0.2.5). The OpenSSL versions are not compatible. Both versions of the application are in wide use in the field.
The core application also supports plugins (developed by 3rd parties) as in-process COM servers - of which some may also need to use SSL.
This means that there can be two or more independent code sources (core and one or more plugins) that need to perform SSL communcations. If they both use OpenSSL then they can have problems.
While trying to create plugins for this application in DELPHI with INDY, we have been running into issues such as: The ordinal 2821 could not be located in the dynamic link library LIBEAY32.DLL
AFAICT this is due to using the wrong OpenSSL DLL version with a given version of Indy (this MAY be incorrect but seems to be the case).
Using Indy 10 in the plugin and loading the libraries from a specific path does not get rid of the problem if the core application causes the old DLLs to be loaded first as Windows still tries to use the in-memory version of the DLL. And if we could somehow force the new libraries to be loaded first then the core program gets an error.
The "normal" solution would be to upgrade the older code to use the newer version of Indy and DLL's (which has been done) - however that is just not possible in some cases (end users don't want to pay for updates of the core application or they have hundreds of installations that need to be updated and that is costly in time and effort, or they have a legacy plugin that they depend on that is no longer supported, etc.).
Our problem when creating a plugin is how to ensure that we don't get conflicts with different versions of OpenSSL libraries.
The possible solutions that I can think of, or have been suggested are:
Create the plugin using the same version of OpenSSL (or a version that is compatible) as the core application.
Create a "proxy" application that does the SSL communications and have the plugin communicate with that in non-SSL.
Create an out-of-process surrogate for the COM server.
Use a completely different library that doesn't use OpenSSL.
The problem with option #1 is that we then have to maintain separate versions of the plugin that correspond to the different versions of the core application ONLY for OpenSSL. In addition, if the user does later update the core application, they would have to update to our new plugin also. Also, it doesn't allow for new plugins created for the old core version to use TLS1.2 since the old version of OpenSSL DLLs don't support that.
Option #2 is workable but a lot of extra work and introduces extra complexity for design, setup and configuration.
I think option #3 is workable but I haven't done that before and seems like it would have some of the same issues as #2.
Option #4 seems the easiest and best but I am not finding any libraries that definitively state that they don't use OpenSSL.
I thought WinHTTP would work but we need TLS 1.2 support and getting WinHTTP to work on older versions of the Windows OS (Win 7) is painful (potentially needs updates applied and then the registry settings need to be modified - potentially breaking existing installed applications).
I thought that I might be able to use the new TNetHttpClient in XE8 but that appears to be using WinHttp also (or has similar problems - I can't tell for sure which).
If any of the above is blatently incorrect - please let me know. I may have explained it poorly or have wrong info - but its the best I can figure on my own.
So ...
Assuming I need to be able to create a plugin that works with the old and new core application, my questions are:
Is there something I have missed?
Is there a way to load two different versions of the OpenSSL libraries in (effectively) the same application without them conflicting?
2a. Can this be done in INDY 10 as is delivered - or does it require modifying the Indy source?
Is there a separate HTTP/SSL library that doesn't use OpenSLL that I can use with Delphi (7 or XE8)?
Is there an alternate solution?
I've looked through LOTS of questions and answers on the net without finding a solution. This question seems to be the closest but does not solve my problem: Indy “Could not load SSL library” Delphi XE2 IW14./29430528#29430528
Upvotes: 4
Views: 9651
Reputation: 576
Using dlopen("your_lib.so", RTLD_LOCAL | RTLD_DEEPBIND)
would solve it, but unfortunately the Address sanitize cannot be used.(https://github.com/google/sanitizers/issues/611)
The DEEPBIND
is so important since other SSL loaded by program entry override current one.
Using dlmopen()
still could not work with asan, since the symbol like __asan_init()
marked as UNDEF in dll and found in exe.
More about dll load: https://stackoverflow.com/a/69863334/12529885
Upvotes: 1
Reputation: 597941
On Windows, you can use Side-By-Side manifests to allow multiple versions of the DLLs to co-exist in the same application across module boundaries. In fact, your scenario is one that SxS was specifically designed for (amongst others):
Your DLLs should be designed so that multiple versions can run at the same time and in the same process without interfering with each other. For example, many applications host multiple plug-ins that each require a different version of one component. The developer the side-by-side assembly needs to design and test to ensure that multiple versions of the component work correctly when run at the same time in the same process.
So, you could create one SxS manifest for your core app that refers to one set of OpenSSL DLLs, and then create a separate SxS manifest for each affected plugin that refers to a different set of OpenSSL DLLs.
That being said, OpenSSL is Indy's default SSL/TLS provider, but Indy is not locked in to OpenSSL specifically. Indy uses a modular design for I/O, so if you want to use a different SSL/TLS engine with Indy then all you need is a TIdSSLIOHandlerSocketBase
-derived component that wraps the engine. Eldos SecureBlackbox, for example, provides an Indy SSLIOHandler for its custom SSL/TLS engine. Or you could write your own wrapper for whatever engine you want to use (such as Microsoft's Crypto/SChannel APIs, which will likely be added to Indy directly in a future version as an alternative to using OpenSSL on Windows).
Upvotes: 4
Reputation: 102376
Is it possible to use two different versions of OpenSSL libraries in same application?
The short answer is... No.
As far as I know for unmanaged DLLs and Unix & Linux shared objects, there is no scope or namespace mechanism. Once a library is loaded, all symbol resolution occurs through that library.
The longer answer is... Maybe.
To use multiple versions, you would effectively have to build wrapper DLLs or share objects. The wrapper DLLs or share objects would link to static versions of the OpenSSL libraries, and they would not export OpenSSL symbols (only symbols from the library at hand).
Unix & Linux shared objects can avoid re-exporting symbols with -Wl,--exclude-libs,all
. This is necessary when building OpnSSL for Android (more on it below). As far as I know, there is no similar mechanism on Windows.
I thought I asked about an equivalent option for -Wl,--exclude-libs,all
on Windows a few years ago, but I cannot find it at the moment. I think the Visual Studio crowd bombed the question and moved to delete it.
The issues is why Android is such a problem. Android usually has an old, outdated version of OpenSSL. The Android image is effectively abandoned by the OEM, so libraries are never updated.
When Android starts, the mother of all process, Zygote, loads the down level version of OpenSSL. Zygote is the Unix & Linux equivalnt is init
. Later, when your process is forked from Zygote, you get the old down level version even if your app packaged a newer version of the library.
Android tried to work around the problem with an updated-able provider; see Updating Your Security Provider to Protect Against SSL Exploits from the Developer documentation.
Also see Compile OpenSSL to different name due to Android Zygote, Changing OpenSSL library in Android app for HttpClient, How to build OpenSSL as unversioned shared lib for Android?, etc.
Finally, see Android | Wrapper Shared Objects on the OpenSSL wiki. It tries to address the issue for Android.
Upvotes: 2