适配Boringssl和OpenSSL 3.0

2023-03-06 11:54:36 浏览数 (2)

前言

openssl 3.0发布好一阵子了,我的 atframe_utils 其实也挺早前就完成了对 openssl 3.0 和 boringssl 的适配。但是由于懒,一直没写这篇文章。在升级 [openssl] 3.0 和 boringssl 还是碰到了一些问题的,有些是由于接口变化,有些是由于功能支持还有些也和构建系统相关。还是有必要记录一下,至少能方便以后查找。

Boringssl

boringssl 是Goolge对早期 openssl 的fork和魔改。大部分接口是相同的,而且它原生支持了 cmake 构建系统,所以接入起来相对容易(特别是涉及交叉编译的时候)。但是这个 cmake 的支持还是有一些问题。

首先, boringssl 的代码兼容性感觉并没有 openssl 好,但是它非得开 /WX (MSVC) 和 -Werror (GCC/Clang)。于是有些编译环境,特别是高版本的编译器会有warning导致编译不过。其次它的子模块 boringssl_gtest 在Windows上编译成动态库是有问题的。最后更重要的问题, boringssl 的 cmake 脚本并没有正确设置 install 目标。所以首先构建系统上需要解决这些问题。

boringssl 我适配的这个版本的编译不过包含 utf-8 char 不能隐式转换到 const char* , 有代码申明为 int x509v3_a2i_ipadd(unsigned char ipout[16], const char *ipasc) 但是实现是 int x509v3_a2i_ipadd(unsigned char* ipout, const char *ipasc) 等等。

然后在代码适配层面,boringssl 比较激进似乎删掉了很多不是那么古老的算法,其中就包含 DH 密钥交换。于是我在使用 boringssl 接入 atframe_utils 的 crypto_dh 是不得不移除DH算法,仅保留 ECDH 。

OpenSSL 3.0

openssl 3.0 优化了很多流程,它输出的库目录更加标准化了,这也带来了一些 cmake 适配上的问题。首先,有些平台下 openssl 3.0 会把安装的库放在 lib64 目录下。但是 cmake 官方的 FindOpenSSL.cmake 脚本中(3.0-3.21版本都是如此),写死了只查找 lib 目录。我现在的解决方法是在编译 openssl 3.0 的时候强行指定 "--libdir=${PROJECT_THIRD_PARTY_INSTALL_DIR}/lib" ,这样可以兼容一些其他直接使用 cmake 的 FindOpenSSL.cmake 的第三方组件。

第二个问题之前的版本应该就有,只是没测试到位。在 cmake 不使用 * Makefile 而使用 Ninja 作为构建系统Generator时,CMAKE_MAKE_PROGRAM 这个变量指向的是 ninja 。而像 openssl 这类在 Unix Like 系统下只能用 Makefile 的 packages 来说,就不能透传 CMAKE_MAKE_PROGRAM 作为构建工具,必须自己查找。自己查找的话还有另一个问题是在 MinGW 环境下,是有可能没有安装 make 仅安装了 mingw32-make 的。这些都是构建系统上需要适配的内容。

在接口和功能上, openssl 正在逐步淘汰古老的低级API,转而使用高级版本的接口 EVP_PKEY_* 等。在 openssl 3.0 中,则是移除了 DH 算法的低级API,于是我们这里又要进行适配。详情可以见 migration_guide 中的 Main Changes from OpenSSL 1.1.1 。简单地说,新版本的 openssl 提供了一组高级接口的 OSSL 库,对多种不同的算法进行了流程上的统一封装。我们就可以使用这一组新的高级接口来操作 DH 密钥交换算法。

在重新适配接入 openssl 的 DH 密钥交换算法过程中,我还发现了一个坑,那就是 EVP_PKEY_set_bn_param() 无效,返回正确但是实际上并没有起任何作用,并不像 ECDH 可以直接用高级接口,我没有深究所以不清楚是 BUG 还是设计如此。在这方面, openssl 的文档还是有一些滞后和粗略,我们目前解决这个问题的方案仍然是通过看 openssl 3.0 的 OSSL_* 的相关的代码流程来自己完成类似的功能。这套接口的流程和代码位置和之前版本的 openssl 差异也比较大,找起来还挺费劲的。主要是把 EVP_PKEY_set_bn_param() 换成了 OSSL_PARAM_BLD_push_BN()

写在最后

大体上适配 openssl 3.0 和 boringssl 就这些问题。其中 boringssl 需要打patch,而且和版本相关性比较大,我写进了构建系统中,并且增加了 iOS、Android、iPhoneSimulator的交叉编译检测。可能后面 boringssl 我更新不会那么频繁,有些warning也许后面也会被修复一些。

最后也欢迎有兴趣的小伙伴们互相交流。

0 人点赞