尝试使用Boost ASIO安全连接到远程IMAP服务器时,服务器握手在每个连接上都失败。异常消息如下:
handshake: unregistered scheme (STORE routines) [asio.ssl:369098857]
我的代码如下(url
是包含主机URL的std::string_view
):
using boost::asio::ip::tcp;
namespace ssl = boost::asio::ssl;
using SSLSocket = ssl::stream<tcp::socket>;
boost::asio::io_context context;
ssl::context ssl_context(ssl::context::tls);
SSLSocket socket(context, ssl_context);
ssl_context.set_default_verify_paths();
tcp::resolver resolver(context);
auto endpoints = resolver.resolve(url, "993");
boost::asio::connect(socket.next_layer(), endpoints);
socket.set_verify_mode(ssl::verify_peer);
socket.set_verify_callback(ssl::host_name_verification(url.data()));
socket.handshake(SSLSocket::client);
代码立即在最后一行抛出异常,这是一个阻塞同步握手。
前两行设置了主机名验证,类似于in the official ASIO tutorial的做法,但是这些检查似乎会导致一个问题,因为当它们被删除时,握手会成功,显然,这不是一个好的解决方案。
在逐步了解ASIO的一些内部结构之后,我发现上面代码段的最后三行可以替换为:
SSL_set_verify(socket.native_handle(), SSL_VERIFY_PEER, nullptr);
socket.handshake(SSLSocket::client);
SSL_set_verify
是一个OpenSSL函数,直接设置空回调会导致同样的问题,这让我认为问题出在我的系统的OpenSSL环境中,而不是ASIO或主机名验证回调。但是,我无法确定错误的确切含义和原因。
以下是我在故障诊断过程中尝试过的操作列表:
1.显式加载系统的证书(.pem)文件我想可能是ASIO和/或OpenSSL无法加载正确的证书来进行验证,所以我在/private/etc/ssl/cert.pem
找到了系统(Mac)的证书文件。
ssl_context.load_verify_file("/private/etc/ssl/cert.pem");
在set_default_verify_paths()
被调用之后,我的程序加载这个证书文件时没有任何抱怨,但是它没有修复握手错误。
1.使用不同版本的OpenSSL起初我使用的是苹果系统版本的OpenSSL(实际上是LibreSSL 2.8.3)。然后我使用Homebrew软件包管理器版本的OpenSSL(OpenSSL 3.0.4)重建了我的代码。这也没有解决问题,即使我尝试像第1点那样调用load_verify_file
。
1.使用OpenSSL命令行工具进行健全性检查为确保网络连接和URL/端口号正确,我尝试使用以下命令通过SSL连接到IMAP服务器:
openssl s_client -connect my.url.com:993 -crlf -verify 1
而且它工作得很好,连接到IMAP服务器,使我能够发送/接收IMAP响应。
有人在使用OpenSSL和ASIO时遇到过类似的问题吗?我对设置SSL/TLS连接不太熟悉,但我不知道是什么原因导致了这个问题。
谢谢你的帮忙!
2条答案
按热度按时间omqzjyyz1#
考虑到
openssl s_client -connect my.url.com:993 -crlf -verify 1
的成功,似乎没有太多错误。有一件事引起了我的注意:我会在从上下文构造SSL流 * 之前 * 配置上下文:此外,
openssl
可能使用SNI extensions:最后,确保
url
字符串视图包含正确的数据,特别是它是一个有效的主机名和空终止的字符串。在这种情况下,我更喜欢使用一个保证空终止的字符串表示:总结
bvpmtnay2#
在我的情况下,我设法使它工作与此:
因此指向ca-bundle文件而不是cert文件。