OpenSSL 3.0 的 TLS 握手失败,但 OpenSSL 1.1.0 的 TLS 握手成功

问题描述 投票:0回答:1

我正在将一些代码从 OpenSSL 1.1.0 迁移到 OpenSSL 3.0。
根据 OpenSSLWiki,在大多数情况下从 OpenSSL 1.1.1 升级到 OpenSSL 3.0 应该相对简单。
我的代码编译良好并与 OpenSSL 3.0 链接,因此没有问题。它也可以毫无问题地运行,直到调用

SSL_connect
为止。 TLS 握手失败,并显示“验证错误:num=20:无法获取本地颁发者证书”。然而,在 OpenSSL 1.1.0 中,TLS 握手成功,无需进行任何更改。 我按照

OpenSSL 证书颁发机构

教程设置了证书链。 所以该链由 3 个证书组成:

根 CA (SS)
  1. 中级 CA (RCA)
  2. 服务器(ICA)
  3. 根证书和中间证书合并在 1 个名为
ca-chain.cert.pem

的链文件中。

建立 TLS 连接的代码非常简单,基于以下简化的代码片段:

SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method()); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); SSL_CTX_load_verify_locations(ctx, "ca-chain.cert.pem", NULL); SSL *ssl = SSL_new(ctx); SSL_set_fd(ssl, sock_fd); SSL_connect(ssl); // Handshake fails in OpenSSL 3.0

为了测试,我使用 
s_server

命令:

openssl s_server -key server.key.pem -cert server.cert.pem -accept 5301

这适用于 OpenSSL 1.1.0。即使使用 
verify

命令(OpenSSL 3.0),这看起来也没什么问题:

openssl verify -CAfile ca-chain.cert.pem server.cert.pem 
server.cert.pem: OK

问题似乎是中间 CA 的证书不存在于 OpenSSL 3.0 的信任存储中(例如,是受信任的证书),而 OpenSSL 1.1.0 则认为它是受信任的。
当我向

-cert_chain ca.cert.pem
命令添加

s_server
选项时,它就开始工作了,该命令还将中间 CA 证书发送到客户端。在这种情况下,我也不需要
ca-chain.cert.pem
文件,只需加载
root.cert.pem
文件即可。
不过,我想保持与以前相同的行为(使用 OpenSSL 1.1.0)。有谁知道如何使用 OpenSSL 3.0 实现这一点?是否有我错过的(新)选项需要为此设置?
我还想知道为什么 OpenSSL 3.0 不再认为中级 CA 证书受信任,而 OpenSSL 1.1.0 仍然受信任。

ssl openssl ssl-certificate ca
1个回答
0
投票

在OpenSSL 3.0中,对证书验证有了更加严格和准确的实现。其中一项更改与处理证书链和信任存储有关。 OpenSSL 3.0 可能需要在验证过程中提供更完整的证书链,即使服务器的证书本身是有效且可信的。

在您的情况下,当您将 -cert_chain 选项与 s_server 命令一起使用时,它会在握手期间发送中间 CA 证书以及服务器的证书。这允许客户端构建完整的证书链直至受信任的根,从而实现成功的验证。

要使用 OpenSSL 3.0 在代码中实现类似的行为,您可能需要修改客户端代码以向 SSL_CTX 提供完整的证书链。具体方法如下:

SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method()); SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); X509_STORE *store = SSL_CTX_get_cert_store(ctx); X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); X509_LOOKUP_load_file(lookup, "ca-chain.cert.pem", X509_FILETYPE_PEM); SSL_CTX_set_client_cert_cb(ctx, your_certificate_callback_function); SSL *ssl = SSL_new(ctx); SSL_set_fd(ssl, sock_fd); SSL_connect(ssl);

在此代码中,your_certificate_callback_function 应该是在 TLS 握手期间加载并向客户端提供完整证书链的函数。您可以使用 OpenSSL 的 API 函数(例如 SSL_set_chain_and_key)来设置完整链。

© www.soinside.com 2019 - 2024. All rights reserved.