是否可以在同一个应用程序中使用两个不同版本的OpenSSL库?

时间:2016-10-31 21:36:57

标签: windows com openssl indy

我知道这是一个很长的解释,但我试图解释一切,而不必回答很多问题或得到虚假的答案。

有一个应用程序使用旧版本的OpenSSL DLL(DLL中没有版本信息)和后来更新的版本,它使用较新的OpenSSL库用于TLS 1.2(1.0.2.5)。 OpenSSL版本不兼容。这两个版本的应用程序都在该领域广泛使用。

核心应用程序还支持插件(由第三方开发)作为进程内COM服务器 - 其中一些可能还需要使用SSL。

这意味着可能有两个或更多需要执行SSL通信的独立代码源(核心和一个或多个插件)。如果他们都使用OpenSSL,那么他们可能会有问题。

在尝试使用INDY在DELPHI中为此应用程序创建插件时,我们遇到了以下问题:序号2821无法位于动态链接库LIBEAY32.DLL

AFAICT这是由于在给定版本的Indy中使用了错误的OpenSSL DLL版本(这可能是不正确的,但似乎是这种情况)。

在插件中使用Indy 10并从特定路径加载库并不能解决问题如果核心应用程序导致首先加载旧DLL,因为Windows仍然尝试使用DLL的内存版本。如果我们能以某种方式强制首先加载新库,那么核心程序就会出错。

"正常"解决方案是升级旧代码以使用较新版本的Indy和DLL(已经完成) - 但在某些情况下这是不可能的(最终用户不想支付更新费用)核心应用程序或他们有数百个需要更新的安装,这些安装需要花费大量时间和精力,或者他们有一个他们所依赖的遗留插件,不再受支持等等。)

创建插件时的问题是如何确保我们不会与不同版本的OpenSSL库发生冲突。

我能想到或已被建议的可能解决方案是:

  1. 使用相同版本的OpenSSL(或兼容的版本)作为核心应用程序创建插件。

  2. 创建"代理"执行SSL通信并使插件与非SSL通信的应用程序。

  3. 为COM服务器创建进程外代理。

  4. 使用完全不同的库,不使用OpenSSL。

  5. 选项#1的问题是我们必须维护插件的单独版本,这些版本对应于仅适用于OpenSSL的核心应用程序的不同版本。此外,如果用户稍后更新核心应用程序,他们也必须更新到我们的新插件。此外,它不允许为旧核心版本创建的新插件使用TLS1.2,因为旧版本的OpenSSL DLL不支持它。

    选项#2是可行的,但需要做大量的额外工作,并为设计,设置和配置带来额外的复杂性。

    我认为选项#3是可行的,但我之前没有做过,似乎会遇到与#2相同的问题。

    选项#4似乎是最简单和最好的,但我找不到任何明确说明他们不使用OpenSSL的库。

    我认为WinHTTP可以工作但是我们需要TLS 1.2支持并且让WinHTTP在旧版本的Windows操作系统(Win 7)上工作很痛苦(可能需要更新应用,然后需要修改注册表设置 - 可能会破坏现有的已安装的应用程序)。

    我认为我可以在XE8中使用新的TNetHttpClient,但似乎也在使用WinHttp(或者有类似的问题 - 我无法确定哪个)。

    如果以上任何内容都是错误的 - 请告诉我。我可能解释得很差或有错误的信息 - 但它是我能想到的最好的。

    所以......

    假设我需要能够创建一个适用于新旧核心应用程序的插件,我的问题是:

    1. 我有什么遗漏的吗?

    2. 有没有办法在(有效)相同的应用程序中加载两个不同版本的OpenSSL库而不会产生冲突?

    3. 2a上。这可以在INDY 10中完成 - 或是否需要修改Indy源?

      1. 是否有单独的HTTP / SSL库没有使用OpenSLL,我可以使用Delphi(7或XE8)?

      2. 是否有替代解决方案?

      3. 我在没有找到解决方案的情况下在网上查看了很多问题和答案。这个问题似乎是最接近但不能解决我的问题:Indy “Could not load SSL library” Delphi XE2 IW14 ./ 29430528#29430528

2 个答案:

答案 0 :(得分:3)

在Windows上,您可以使用Side-By-Side manifests允许多个版本的DLL在跨模块边界的同一应用程序中共存。实际上,您的场景是SxS专门为(以及其他)设计的场景:

  

您的DLL应该设计为可以在同一个进程中同时运行多个版本而不会相互干扰。 例如,许多应用程序托管多个插件,每个插件都需要一个组件的不同版本。并行组件需要设计和测试的开发人员,以确保在同一个过程中同时运行时,组件的多个版本可以正常工作。

因此,您可以为您的核心应用程序创建一个SxS清单,引用一组OpenSSL DLL,然后为每个受影响的插件创建一个单独的SxS清单,该清单引用一组不同的OpenSSL DLL。

话虽这么说,OpenSSL是Indy的默认 SSL / TLS提供商,但Indy没有专门锁定到OpenSSL 。 Indy对I / O使用模块化设计,因此如果您想使用与Indy不同的SSL / TLS引擎,那么您只需要一个包裹引擎的TIdSSLIOHandlerSocketBase派生组件。例如,Eldos SecureBlackbox为其自定义SSL / TLS引擎提供了Indy SSLIOHandler。或者您可以为您想要使用的任何引擎编写自己的包装器(例如Microsoft的Crypto / SChannel API,它们可能会在未来的版本中直接添加到Indy,作为在Windows上使用OpenSSL的替代方案)。 / p>

答案 1 :(得分:1)

  

是否可以在同一个应用程序中使用两个不同版本的OpenSSL库?

简短的回答是......不。

据我所知,非托管DLL和Unix& Linux共享对象,没有范围或命名空间机制。加载库后,通过该库发生所有符号解析。

答案越长......也许。

要使用多个版本,您需要构建包装器DLL或共享对象。包装器DLL或共享对象将链接到OpenSSL库的 静态 版本,并且 导出OpenSSL符号(仅来自库中的符号)。

Unix& Linux共享对象可以避免使用 -Wl,--exclude-libs,all 重新导出符号。在构建适用于Android的OpnSSL时,这是必要的(下面有更多内容)。据我所知,Windows上没有类似的机制。

我以为几年前我曾在Windows上询问过 -Wl,--exclude-libs,all 的等效选项,但目前我找不到它。我认为Visual Studio人群轰炸了这个问题并开始删除它。

问题是Android出现这种问题的原因。 Android通常有一个旧的,过时的OpenSSL版本。 OEM有效地放弃了Android映像,因此库永远不会更新。

当Android启动时,所有进程的母亲 Zygote 会加载低级版本的OpenSSL。 Zygote是Unix& Linux等效是init。之后,当您的流程从Zygote分叉时,即使您的应用程序打包了较新版本的库,您也会获得旧的低级版本。

Android尝试使用可更新的提供商解决此问题;请参阅开发人员文档中的Updating Your Security Provider to Protect Against SSL Exploits

另请参阅Compile OpenSSL to different name due to Android ZygoteChanging OpenSSL library in Android app for HttpClientHow to build OpenSSL as unversioned shared lib for Android?

最后,请参阅OpenSSL wiki上的Android | Wrapper Shared Objects。它试图解决Android的问题。

相关问题