尝试使用Boost ASIO安全地连接到远程IMAP服务器时,服务器握手在每个连接上都会失败。异常消息读取:
handshake: unregistered scheme (STORE routines) [asio.ssl:369098857]
我的代码在下面( url
是 std :: string_view
包含主机URL):
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);
代码立即在最终行上抛出一个例外,阻塞同步握手。
前两行设置主机名验证,类似于完成。但是,这些检查似乎引起了问题,因为当它们被拆除时,握手会成功。显然,这不是一个好的解决方案。
踏上ASIO的一些内部内容后,我发现上述摘要的最后三行可以由以下方式替换:
SSL_set_verify(socket.native_handle(), SSL_VERIFY_PEER, nullptr);
socket.handshake(SSLSocket::client);
发生同样的错误。 ssl_set_verify
是一个openssl函数,设置无空回调直接导致相同问题的事实使我认为问题是我系统的OpenSSL环境而不是ASIO或主机名验证回调。但是,我无法确定错误的含义以及可能导致的误差。
这是我在故障排除时尝试过的事情的列表:
-
加载系统的证书(.pem)文件明确也许ASIO和/或OpenSSL无法加载正确的证书来完成验证,我在/private/etc/ssl/cert.pem
上找到了我的系统(Mac)证书文件。然后,我插入以下行:
ssl_context.load_verify_file(“/private/etc/etc/ssl/cert.pem”);
直接在 set_default_verify_paths()
被调用。我的程序在不抱怨的情况下加载此证书文件,但没有解决握手错误。
-
首先,我使用Apple的系统版本OpenSSL(实际上是Libressl 2.8.3),使用其他版本的OpenSSL 。然后,我使用Homebrew Package Manager的OpenSSL(OpenSSL 3.0.4)重建代码。即使我尝试调用 load_verify_file
,也没有解决问题。
- 。连接和URL/端口号是正确的,我尝试使用以下命令通过SSL连接到IMAP服务器:
openssl s_client -connect my.url.com:993 -crlf -verify 1
它运行良好,连接到IMAP服务器并使我能够发送/接收IMAP响应。
使用OpenSSL和ASIO时,是否有人遇到过类似的问题?我对设置SSL/TLS连接并不熟悉,但是我看不出可能导致问题的原因。
感谢您的帮助!
When attempting to securely connect to a remote IMAP server using Boost ASIO, the server handshake fails on every connection. The exception message reads:
handshake: unregistered scheme (STORE routines) [asio.ssl:369098857]
My code is below (url
is a std::string_view
containing the host URL):
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);
The code immediately throws an exception on the final line, which is a blocking synchronous handshake.
The prior two lines set up host name verification, similar to how it's done in the official ASIO tutorial. These checks seem to be causing an issue, however, because when they are removed the handshake succeeds. Obviously, this is not a good solution.
After stepping through some of ASIO's internals, I found that the last three lines of the above snippet could be replaced by:
SSL_set_verify(socket.native_handle(), SSL_VERIFY_PEER, nullptr);
socket.handshake(SSLSocket::client);
and the same error occurs. SSL_set_verify
is an OpenSSL function, and the fact that setting a null callback directly causes the same issue makes me think that the issue is with my system's OpenSSL environment and not ASIO or the host name verification callback. However, I have not been able to determine what exactly the error means and what could be causing it.
Here is a list of things I have tried while troubleshooting:
-
Load the system's certificate (.pem) file explicitly Thinking maybe ASIO and/or OpenSSL's were not able to load the right certificates to do the validation, I found my system's (a Mac) certificate file at /private/etc/ssl/cert.pem
. I then inserted the following line:
ssl_context.load_verify_file("/private/etc/ssl/cert.pem");
directly after set_default_verify_paths()
is called. My program loads this certificate file without complaining, but it doesn't fix the handshake error.
-
Use a different version of OpenSSL At first I was using Apple's system version of OpenSSL (which is really LibreSSL 2.8.3). I then rebuilt my code using the Homebrew package manager's version of OpenSSL (OpenSSL 3.0.4). This also did not fix the issue, even when I tried calling load_verify_file
as in point 1.
-
Sanity check using the OpenSSL command-line tool To make sure my network connection and URL/port number were correct, I tried connecting to the IMAP server over SSL using the following command:
openssl s_client -connect my.url.com:993 -crlf -verify 1
and it worked fine, connecting to the IMAP server and enabling me to send/receive IMAP responses.
Has anyone encountered similar issues when using OpenSSL and ASIO? I'm not very familiar with setting up an SSL/TLS connection, but I don't see what could be causing the problem.
Thanks for your help!
发布评论
评论(3)
鉴于
openssl s_client -connect my.url.com:993 -crlf -crlf -verify 1
成功,似乎没有很多错误。一件事引起了我的注意:我将在构建SSL流之前配置上下文:另外,
openssl
可能使用 sni Extensions :最后,确保
url
字符串视图包含正确的数据, 显然 这是一个有效的主机名和 null终止的字符串。在这种情况下,我宁愿使用保证无效终止的字符串表示:
Given that
openssl s_client -connect my.url.com:993 -crlf -verify 1
succeeds there is not a lot that seems wrong. One thing catches my eye: I'd configure the context before constructing an SSL stream from it:Also,
openssl
likely uses SNI extensions:Finally, make sure the
url
string view contains correct data, notably that it's a valid hostname and null-terminated string. In this case I'd prefer to use a string representation that guarantees null-termination:Summary
就我而言,我要求它与此功能一起使用:
因此,指向CA-Bundle文件而不是CERT文件。
In my case I manged to make it work with this:
so pointing to the ca-bundle file instead of the cert file.
我在Boost Asio中的握手也有一些挑战。我在Filemaker插件中使用它,当涉及到这一行时:
因此,它崩溃了整个应用程序。
经过数小时,更改设置,谷歌搜索并阅读文档后,我将该方法放入了一个小的独立应用程序中,就像在孤立的环境中对其进行测试一样。在插件代码和测试应用程序中都具有所有相同的Boost版本(1.82.0)和相同的OpenSSL库(3.1.4)。
在测试应用程序中,它可以按预期工作。代码从服务器检索数据。在具有相同代码的插件中,FileMaker崩溃。
在您的下方,您可以查看崩溃日志片段以及测试应用程序的代码。
崩溃日志
测试应用程序的工作来源与插件相同的代码
在显示通信的测试时示例输出,我得到了肥皂失误,但是由于我没有't实际上发送了任何有效的肥皂请求,预期。但是,它表明功能与服务器交换数据。
I have also some challenge with this handshake in boost asio. I am using it in a FileMaker Plugin, and when it comes to this line:
It consequently crash the whole application.
After trying for hours, changing the setup, googling, and reading the documentation, I put the method into a small stand-alone application made like a command-line utility to test it in a isolated environment. Having all the same boost version (1.82.0) and the same openSSL libraries (3.1.4) in both the plugin code and test application.
In the test application, it works as expected. The code retrieve data from the server. In the plugin with the same code, FileMaker crash.
Below you ca see the crash log snippet, and also the code of the test application.
Crash log
The Working Source of the test application that has the same code as the plugin
Sample output when testing that shows communication, I got a soap-fault, but since I didn't actually send any valid soap request, its expected. However, it shows that the function exchange data with the server.