是否可以在同一应用程序中使用两个不同版本的 OpenSSL 库?
Is it possible to use two different versions of OpenSSL libraries in same application?
我知道这是一个很长的解释,但我正在尝试解释所有内容,而不必稍后回答很多问题或得到虚假答案。
有一个应用程序使用旧版本的 OpenSSL DLL(DLL 中没有版本信息)和更新版本使用更新的 OpenSSL 库用于 TLS 1.2 (1.0.2.5)。 OpenSSL 版本不兼容。该应用程序的两个版本都在该领域得到广泛使用。
核心应用程序还支持插件(由第 3 方开发)作为进程内 COM 服务器 - 其中一些可能还需要使用 SSL。
这意味着可以有两个或多个独立的代码源(核心和一个或多个插件)需要执行 SSL 通信。如果他们都使用 OpenSSL 那么他们可能会遇到问题。
在尝试使用 INDY 在 DELPHI 中为此应用程序创建插件时,我们 运行 遇到了以下问题:无法在动态 link 中找到序号 2821图书馆 LIBEAY32.DLL
AFAICT,这是由于给定版本的 Indy 使用了错误的 OpenSSL DLL 版本(这可能不正确,但似乎是这样)。
在插件中使用 Indy 10 并从特定路径加载库并不能解决问题,如果核心应用程序导致旧 DLL 被首先加载,因为 Windows 仍然尝试使用 in -DLL 的内存版本。如果我们能以某种方式强制首先加载新库,那么核心程序就会出错。
"normal" 解决方案是升级旧代码以使用新版本的 Indy 和 DLL(已经完成)——但是在某些情况下这是不可能的(最终用户不想要为核心应用程序的更新付费,或者他们有数百个安装需要更新,这在时间和精力上都是昂贵的,或者他们有一个他们依赖的遗留插件不再受支持,等等)。 =11=]
我们在创建插件时的问题是如何确保我们不会与不同版本的 OpenSSL 库发生冲突。
我能想到的或已经提出的可能的解决方案是:
使用与核心应用程序相同版本的 OpenSSL(或兼容的版本)创建插件。
创建一个 "proxy" 应用程序进行 SSL 通信并让插件与非 SSL 通信。
为 COM 服务器创建进程外代理。
使用不使用 OpenSSL 的完全不同的库。
选项 #1 的问题是我们必须维护单独的插件版本,这些插件仅对应于 OpenSSL 的核心应用程序的不同版本。此外,如果用户稍后更新核心应用程序,他们也必须更新到我们的新插件。此外,它不允许为旧核心版本创建的新插件使用 TLS1.2,因为旧版本的 OpenSSL DLL 不支持它。
选项 #2 是可行的,但需要大量额外工作,并且会为设计、设置和配置带来额外的复杂性。
我认为选项 #3 是可行的,但我以前没有这样做过,看起来它会遇到一些与 #2 相同的问题。
选项 #4 似乎是最简单和最好的,但我没有找到任何明确声明它们不使用 OpenSSL 的库。
我认为 WinHTTP 可以工作,但我们需要 TLS 1.2 支持,让 WinHTTP 在 Windows OS (Win 7) 的旧版本上工作是痛苦的(可能需要应用更新,然后需要修改注册表设置 - 可能会破坏现有已安装的应用程序)。
我认为我可以在 XE8 中使用新的 TNetHttpClient,但它似乎也在使用 WinHttp(或有类似的问题 - 我不能确定是哪个)。
如果以上任何内容明显不正确 - 请告诉我。我可能解释得不好或者有错误的信息 - 但这是我自己能想到的最好的。
所以...
假设我需要能够创建一个适用于新旧核心应用程序的插件,我的问题是:
有什么我遗漏的吗?
有没有办法在同一个应用程序中(有效地)加载两个不同版本的 OpenSSL 库而不发生冲突?
2a。这可以在交付的 INDY 10 中完成吗?还是需要修改 Indy 源代码?
是否有单独的 HTTP/SSL 库,它不使用我可以与 Delphi(7 或 XE8)一起使用的 OpenSLL?
是否有替代解决方案?
我在网上浏览了很多问题和答案,但没有找到解决方案。这个问题似乎最接近但没有解决我的问题:Indy “Could not load SSL library” Delphi XE2 IW14./29430528#29430528
Is it possible to use two different versions of OpenSSL libraries in same application?
简短的回答是……不。
据我所知,对于非托管 DLL 和 Unix & Linux 共享对象,没有作用域或命名空间机制。加载库后,所有符号解析都会通过该库进行。
较长的答案是...也许。
要使用多个版本,您实际上必须构建包装器 DLL 或共享对象。包装器 DLL 或共享对象将 link 到 static 版本的 OpenSSL 库,它们将 not 导出 OpenSSL 符号(仅手头库中的符号)。
Unix 和 Linux 共享对象可以避免使用 -Wl,--exclude-libs,all
重新导出符号。在为 Android 构建 OpnSSL 时这是必要的(更多内容见下文)。据我所知,Windows.
上没有类似的机制
我以为我几年前在 Windows 上问过 -Wl,--exclude-libs,all
的等效选项,但目前找不到。我认为 Visual Studio 人群轰炸了这个问题并删除了它。
问题是为什么 Android 是这样的问题。 Android 通常有一个旧的、过时的 OpenSSL 版本。 Android 图像实际上已被 OEM 放弃,因此永远不会更新库。
当 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 Zygote, , How to build OpenSSL as unversioned shared lib for Android?等
最后,请参阅 OpenSSL wiki 上的 Android | Wrapper Shared Objects。它试图解决 Android.
的问题
在 Windows 上,您可以使用 Side-By-Side manifests 允许多个版本的 DLL 跨模块边界在同一应用程序中共存。事实上,您的场景是 SxS 专门为(以及其他场景)设计的场景:
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.
因此,您可以为引用一组 OpenSSL DLL 的核心应用程序创建一个 SxS 清单,然后为引用一组不同 OpenSSL DLL 的每个受影响的插件创建一个单独的 SxS 清单。
也就是说,OpenSSL 是 Indy 的默认 SSL/TLS 提供程序,但 Indy 并没有锁定到 OpenSSL 具体。 Indy 使用 I/O 的模块化设计,所以如果你想在 Indy 中使用不同的 SSL/TLS 引擎,那么你只需要一个 TIdSSLIOHandlerSocketBase
派生的组件来包装引擎。例如,Eldos SecureBlackbox 为其自定义 SSL/TLS 引擎提供 Indy SSLIOHandler。或者你可以为你想使用的任何引擎编写你自己的包装器(例如微软的 Crypto/SChannel API,它可能会在未来的版本中直接添加到 Indy 中作为在 Windows 上使用 OpenSSL 的替代方法) .
使用dlopen("your_lib.so", RTLD_LOCAL | RTLD_DEEPBIND)
可以解决问题,但不幸的是无法使用地址清理。(https://github.com/google/sanitizers/issues/611)
DEEPBIND
非常重要,因为程序入口加载的其他 SSL 会覆盖当前的 SSL。
使用 dlmopen()
仍然无法使用 asan,因为像 __asan_init()
这样的符号在 dll 中标记为 UNDEF 并在 exe 中找到。
有关 dll 加载的更多信息:
我知道这是一个很长的解释,但我正在尝试解释所有内容,而不必稍后回答很多问题或得到虚假答案。
有一个应用程序使用旧版本的 OpenSSL DLL(DLL 中没有版本信息)和更新版本使用更新的 OpenSSL 库用于 TLS 1.2 (1.0.2.5)。 OpenSSL 版本不兼容。该应用程序的两个版本都在该领域得到广泛使用。
核心应用程序还支持插件(由第 3 方开发)作为进程内 COM 服务器 - 其中一些可能还需要使用 SSL。
这意味着可以有两个或多个独立的代码源(核心和一个或多个插件)需要执行 SSL 通信。如果他们都使用 OpenSSL 那么他们可能会遇到问题。
在尝试使用 INDY 在 DELPHI 中为此应用程序创建插件时,我们 运行 遇到了以下问题:无法在动态 link 中找到序号 2821图书馆 LIBEAY32.DLL
AFAICT,这是由于给定版本的 Indy 使用了错误的 OpenSSL DLL 版本(这可能不正确,但似乎是这样)。
在插件中使用 Indy 10 并从特定路径加载库并不能解决问题,如果核心应用程序导致旧 DLL 被首先加载,因为 Windows 仍然尝试使用 in -DLL 的内存版本。如果我们能以某种方式强制首先加载新库,那么核心程序就会出错。
"normal" 解决方案是升级旧代码以使用新版本的 Indy 和 DLL(已经完成)——但是在某些情况下这是不可能的(最终用户不想要为核心应用程序的更新付费,或者他们有数百个安装需要更新,这在时间和精力上都是昂贵的,或者他们有一个他们依赖的遗留插件不再受支持,等等)。 =11=]
我们在创建插件时的问题是如何确保我们不会与不同版本的 OpenSSL 库发生冲突。
我能想到的或已经提出的可能的解决方案是:
使用与核心应用程序相同版本的 OpenSSL(或兼容的版本)创建插件。
创建一个 "proxy" 应用程序进行 SSL 通信并让插件与非 SSL 通信。
为 COM 服务器创建进程外代理。
使用不使用 OpenSSL 的完全不同的库。
选项 #1 的问题是我们必须维护单独的插件版本,这些插件仅对应于 OpenSSL 的核心应用程序的不同版本。此外,如果用户稍后更新核心应用程序,他们也必须更新到我们的新插件。此外,它不允许为旧核心版本创建的新插件使用 TLS1.2,因为旧版本的 OpenSSL DLL 不支持它。
选项 #2 是可行的,但需要大量额外工作,并且会为设计、设置和配置带来额外的复杂性。
我认为选项 #3 是可行的,但我以前没有这样做过,看起来它会遇到一些与 #2 相同的问题。
选项 #4 似乎是最简单和最好的,但我没有找到任何明确声明它们不使用 OpenSSL 的库。
我认为 WinHTTP 可以工作,但我们需要 TLS 1.2 支持,让 WinHTTP 在 Windows OS (Win 7) 的旧版本上工作是痛苦的(可能需要应用更新,然后需要修改注册表设置 - 可能会破坏现有已安装的应用程序)。
我认为我可以在 XE8 中使用新的 TNetHttpClient,但它似乎也在使用 WinHttp(或有类似的问题 - 我不能确定是哪个)。
如果以上任何内容明显不正确 - 请告诉我。我可能解释得不好或者有错误的信息 - 但这是我自己能想到的最好的。
所以...
假设我需要能够创建一个适用于新旧核心应用程序的插件,我的问题是:
有什么我遗漏的吗?
有没有办法在同一个应用程序中(有效地)加载两个不同版本的 OpenSSL 库而不发生冲突?
2a。这可以在交付的 INDY 10 中完成吗?还是需要修改 Indy 源代码?
是否有单独的 HTTP/SSL 库,它不使用我可以与 Delphi(7 或 XE8)一起使用的 OpenSLL?
是否有替代解决方案?
我在网上浏览了很多问题和答案,但没有找到解决方案。这个问题似乎最接近但没有解决我的问题:Indy “Could not load SSL library” Delphi XE2 IW14./29430528#29430528
Is it possible to use two different versions of OpenSSL libraries in same application?
简短的回答是……不。
据我所知,对于非托管 DLL 和 Unix & Linux 共享对象,没有作用域或命名空间机制。加载库后,所有符号解析都会通过该库进行。
较长的答案是...也许。
要使用多个版本,您实际上必须构建包装器 DLL 或共享对象。包装器 DLL 或共享对象将 link 到 static 版本的 OpenSSL 库,它们将 not 导出 OpenSSL 符号(仅手头库中的符号)。
Unix 和 Linux 共享对象可以避免使用 -Wl,--exclude-libs,all
重新导出符号。在为 Android 构建 OpnSSL 时这是必要的(更多内容见下文)。据我所知,Windows.
我以为我几年前在 Windows 上问过 -Wl,--exclude-libs,all
的等效选项,但目前找不到。我认为 Visual Studio 人群轰炸了这个问题并删除了它。
问题是为什么 Android 是这样的问题。 Android 通常有一个旧的、过时的 OpenSSL 版本。 Android 图像实际上已被 OEM 放弃,因此永远不会更新库。
当 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 Zygote,
最后,请参阅 OpenSSL wiki 上的 Android | Wrapper Shared Objects。它试图解决 Android.
的问题在 Windows 上,您可以使用 Side-By-Side manifests 允许多个版本的 DLL 跨模块边界在同一应用程序中共存。事实上,您的场景是 SxS 专门为(以及其他场景)设计的场景:
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.
因此,您可以为引用一组 OpenSSL DLL 的核心应用程序创建一个 SxS 清单,然后为引用一组不同 OpenSSL DLL 的每个受影响的插件创建一个单独的 SxS 清单。
也就是说,OpenSSL 是 Indy 的默认 SSL/TLS 提供程序,但 Indy 并没有锁定到 OpenSSL 具体。 Indy 使用 I/O 的模块化设计,所以如果你想在 Indy 中使用不同的 SSL/TLS 引擎,那么你只需要一个 TIdSSLIOHandlerSocketBase
派生的组件来包装引擎。例如,Eldos SecureBlackbox 为其自定义 SSL/TLS 引擎提供 Indy SSLIOHandler。或者你可以为你想使用的任何引擎编写你自己的包装器(例如微软的 Crypto/SChannel API,它可能会在未来的版本中直接添加到 Indy 中作为在 Windows 上使用 OpenSSL 的替代方法) .
使用dlopen("your_lib.so", RTLD_LOCAL | RTLD_DEEPBIND)
可以解决问题,但不幸的是无法使用地址清理。(https://github.com/google/sanitizers/issues/611)
DEEPBIND
非常重要,因为程序入口加载的其他 SSL 会覆盖当前的 SSL。
使用 dlmopen()
仍然无法使用 asan,因为像 __asan_init()
这样的符号在 dll 中标记为 UNDEF 并在 exe 中找到。
有关 dll 加载的更多信息: