gpt4 book ai didi

c++ - boost asio ssl async_shutdown总是以错误结束?

转载 作者:太空宇宙 更新时间:2023-11-03 12:38:02 25 4
gpt4 key购买 nike

我有一个小型的ssl客户端,我已经在boost 1.55 asio中进行了编程,我试图弄清楚boost::asio::ssl::stream::async_shutdown()为什么总是失败。该客户端与boost文档中的ssl客户端示例非常相似(几乎相同),因为它经历了boost::asio::ip::tcp::resolver::async_resolve()-> boost::asio::ssl::stream::async_connect()-> boost::asio::ssl::stream::async_handshake()回调序列。所有这一切都按预期工作,并且async_handshake()回调获得一个清晰的boost::system::error_code

async_handshake()回调中,我调用async_shutdown()(我不传输任何数据-此对象更多用于测试握手):

void ClientCertificateFinder::handle_handshake(const boost::system::error_code& e)
{
if ( !e )
{
m_socket.async_shutdown( boost::bind( &ClientCertificateFinder::handle_shutdown_after_success,
this,
boost::asio::placeholders::error ) );
}
else
{
m_handler( e, IssuerNameList() );
}
}

然后调用 handle_shutdown_after_success(),但总是出错?错误是 asio.misc中的value = 2,它是“文件末尾”。我已经在各种ssl服务器上进行了尝试,但似乎总是收到 asio.misc错误。那不是潜在的openssl错误向我暗示我可能以某种方式滥用了asio ...?

有人知道为什么会这样吗?我的印象是,关闭与 async_shutdown()的连接是正确的事情,但是我想我可以调用 boost::asio::ssl::stream.lowestlayer().close()从openssl下关闭套接字(如果这是这样做的预期方式)(实际上是asio ssl示例似乎表明这是关闭的正确方法)。

最佳答案

对于加密安全的关闭,双方必须通过调用boost::asio::ssl::streamshutdown()并运行async_shutdown() io_service 执行关闭操作。如果操作以没有SSL categoryerror_code完成,并且未在部分关闭发生之前被取消,则说明该连接已安全关闭,并且基础传输可以重新使用或关闭。简单地关闭最低层可能会使 session 容易受到truncation attack攻击。

协议(protocol)和Boost.Asio API

在标准化TLS协议(protocol)和非标准化SSLv3协议(protocol)中,安全关闭涉及各方交换close_notify消息。就Boost.Asio API而言,任何一方都可以通过调用shutdown()async_shutdown()来启动关闭操作,从而将close_notify消息发送给另一方,从而通知接收者发起者将不会在SSL连接上发送更多消息。根据规范,接收者必须以close_notify消息作为响应。 Boost.Asio不会自动执行此行为,并且要求接收者显式调用shutdown()async_shutdown()

该规范允许关闭的启动器在收到close_notify响应之前关闭其连接的读取侧。在应用协议(protocol)不希望重用基础协议(protocol)的情况下使用此方法。不幸的是,Boost.Asio当前(1.56)尚未为此功能提供直接支持。在Boost.Asio中,如果发生错误或当事方已发送和接收shutdown()消息,则close_notify操作被视为完成。操作完成后,应用程序可以重新使用基础协议(protocol)或将其关闭。

方案和错误代码

建立SSL连接后,关机期间会出现以下错误代码:

  • 一方发起关闭,而远程方在不关闭协议(protocol)的情况下关闭或已经关闭了基础传输:
  • 启动器的shutdown()操作将失败,并出现SSL短读取错误。
  • 一方发起关闭并等待远程方关闭协议(protocol):
  • 启动程序的关闭操作将以boost::asio::error::eof的错误值完成。
  • 远程用户的shutdown()操作成功完成。
  • 一方发起关闭,然后关闭基础协议(protocol),而无需等待远程方关闭协议(protocol):
  • 启动器的shutdown()操作将被取消,从而导致boost::asio::error::operation_aborted错误。这是以下详细信息中指出的解决方法的结果。
  • 远程用户的shutdown()操作成功完成。

  • 这些详细情况将在下面详细介绍。每个场景都用类似游标线的图来说明,指示每个参与者在完全相同的时间点正在做什么。

    在甲方关闭连接而不协商关机的情况下,甲方调用 shutdown()

    在这种情况下,PartyB通过关闭基础传输而不首先在流上调用 shutdown()来违反关闭过程。一旦基础传输关闭,PartyA就会尝试启动 shutdown()

     PartyA                              | PartyB
    -------------------------------------+----------------------------------------
    ssl_stream.handshake(...); | ssl_stream.handshake(...);
    ... | ssl_stream.lowest_layer().close();
    ssl_stream.shutdown(); |

    PartyA将尝试发送 close_notify消息,但是对基础传输的写入将失败,并带有 boost::asio::error::eof。由于PartyB违反了SSL关闭程序,Boost.Asio会将底层传输的 eof错误 explicitly map转换为SSL短读取错误。

    if ((error.category() == boost::asio::error::get_ssl_category())
    && (ERR_GET_REASON(error.value()) == SSL_R_SHORT_READ))
    {
    // Remote peer failed to send a close_notify message.
    }

    PartyA调用 shutdown(),然后PartyB关闭连接而不协商关闭。

    在这种情况下,甲方发起关闭。但是,当PartyB收到 close_notify消息时,PartyB违反了关闭过程,因为在关闭基础传输之前从未明确使用 shutdown()做出响应。

     PartyA                              | PartyB
    -------------------------------------+---------------------------------------
    ssl_stream.handshake(...); | ssl_stream.handshake(...);
    ssl_stream.shutdown(); | ...
    | ssl_stream.lowest_layer().close();

    一旦Boost.Asio的 shutdown()发送和接收完毕或发生错误,就认为Boost.Asio的 close_notify操作已完成,因此PartyA将发送 close_notify然后等待响应。甲方B在不发送 close_notify的情况下关闭了基础传输,这违反了SSL协议(protocol)。 PartyA的读取将以 boost::asio::error::eof失败,Boost.Asio会将其映射为SSL短读取错误。

    PartyA启动 shutdown()并等待PartyB用 shutdown()响应。

    在这种情况下,甲方将启动关机并等待甲方响应以关机。

     PartyA                              | PartyB
    -------------------------------------+----------------------------------------
    ssl_stream.handshake(...); | ssl_stream.handshake(...);
    ssl_stream.shutdown(); | ...
    ... | ssl_stream.shutdown();

    这是相当基本的关机,双方都发送和接收 close_notify消息。双方协商关闭后,基础传输可以重新使用或关闭。
  • PartyA的关闭操作将以boost::asio::error::eof的错误值完成。
  • PartyB的关闭操作将成功完成。

  • PartyA启动 shutdown(),但不等待PartyB响应。

    在这种情况下,PartyA将启动关闭,然后在发送了 close_notify后立即关闭基础传输。甲方不等待甲方响应 close_notify消息。根据规范,这种类型的协商关闭是允许的,并且在实现中相当普遍。

    如上所述,Boost.Asio不直接支持这种类型的关闭。 Boost.Asio的 shutdown()操作将等待远程对等方发送其 close_notify。但是,可以在仍坚持该规范的同时实现解决方法。

     PartyA                              | PartyB
    -------------------------------------+---------------------------------------
    ssl_stream.handshake(...); | ssl_stream.handshake(...)
    ssl_stream.async_shutdown(...); | ...
    const char buffer[] = ""; | ...
    async_write(ssl_stream, buffer, | ...
    [](...) { ssl_stream.close(); }) | ...
    io_service.run(); | ...
    ... | ssl_stream.shutdown();

    甲方将启动异步关闭操作,然后启动异步写操作。用于写操作的缓冲区的长度必须为非零(上面使用了空字符)。否则,Boost.Asio将优化对无操作的写入。当 shutdown()操作运行时,它将 close_notify发送给PartyB,导致SSL关闭PartyA的SSL流的写端,然后异步等待PartyB的 close_notify。但是,由于PartyA的SSL流的写端已关闭,因此 async_write()操作将失败,并显示SSL错误,指示该协议(protocol)已关闭。

    if ((error.category() == boost::asio::error::get_ssl_category())
    && (SSL_R_PROTOCOL_IS_SHUTDOWN == ERR_GET_REASON(error.value())))
    {
    ssl_stream.lowest_layer().close();
    }

    然后,失败的 async_write()操作将显式关闭基础传输,从而导致正在等待PartyB的 async_shutdown()被取消的 close_notify操作。
  • 尽管PartyA执行了SSL规范允许的关闭过程,但在关闭基础传输时,明确取消了shutdown()操作。因此,shutdown()操作的错误代码将具有boost::asio::error::operation_aborted的值。
  • PartyB的关闭操作将成功完成。


  • 总而言之,Boost.Asio的SSL关闭操作有些棘手。在适当关闭期间,发起方和远程对等方的错误代码之间的不一致会使处理有些尴尬。通常,只要错误代码的类别不是SSL类别,就可以安全地关闭协议(protocol)。

    关于c++ - boost asio ssl async_shutdown总是以错误结束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25587403/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com