【问题标题】:IO Completion Ports and OpenSSLIO 完成端口和 OpenSSL
【发布时间】:2010-12-09 22:32:50
【问题描述】:

我有一些使用 OpenSSL 进行通信的遗留代码。就像任何其他会话一样,它使用 SSL 功能进行握手,然后通过 TCP 加密通信。我们最近更改了代码以使用 IO 完成端口。它的工作方式与 OpenSSL 的相反。基本上,我很难将我们的安全通信代码从完全使用 OpenSSL 迁移到 IOCP 套接字和 OpenSSL 加密。

是否有人/有人知道任何可以帮助我完成此类任务的参考资料? TLS 握手如何通过 IOCP 工作?

【问题讨论】:

    标签: c++ openssl


    【解决方案1】:

    为了使用 OpenSSL 进行加密,但做你自己的套接字 IO,你基本上要做的是创建一个内存 BIO,你可以读取和写入套接字数据,然后将其附加到 SSL 上下文。

    每次执行 SSL_write 调用时,都会调用内存 BIO 以查看其读取缓冲区中是否有数据,将其读出并发送。 相反,当数据通过您的 io 完成端口机制到达套接字时,您将其写入 BIO 并调用 SSL_read 以读取数据。 SSL_read 可能会返回一个错误代码,表明它处于握手状态,这通常意味着它生成了更多要写入的数据 - 您可以通过再次读取内存 BIO 来处理这些数据。


    为了创建我的 SSL 会话,我这样做:

    // This creates a SSL session, and an in, and an out, memory bio and
    // attaches them to the ssl session.
    SSL* conn = SSL_new(ctx);
    BIO* bioIn = BIO_new(BIO_s_mem());
    BIO* bioOut = BIO_new(BIO_s_mem());
    SSL_set_bio(conn,bioIn,bioOut);
    // This tells the ssl session to start the negotiation.
    SSL_set_connect_state(conn);
    

    当我从网络层接收数据时:

    // buf contains len bytes read from the socket.
    BIO_write(bioIn,buf,len);
    SendPendingHandshakeData();
    TryResendBufferedData(); // see below
    int cbPlainText;
    while( cbPlainText = SSL_read(ssl,&plaintext,sizeof(plaintext)) >0)
    {
      // Send the decoded data to the application
      ProcessPlaintext(plaintext,cbPlaintext);
    }
    

    当我从应用程序接收到要发送的数据时,您需要为 SSL_write 失败做好准备,因为握手正在进行中,在这种情况下,您可以缓冲数据,并在未来收到一些数据后尝试再次发送.

    if( SSL_write(conn,buf,len) < 0)
    {
      StoreDataForSendingLater(buf,len);
    }
    SendPendingHandshakeData();
    

    SendPendingHandshakeData 发送 SSL 需要发送的任何数据(握手或密文)。

    while(cbPending = BIO_ctrl_pending(bioOut))
    {
      int len = BIO_read(bioOut,buf,sizeof(buf));
      SendDataViaSocket(buf,len); // you fill this in here.
    }
    

    简而言之就是这个过程。代码示例并不完整,因为我必须从一个更大的库中提取它们,但我相信它们足以开始使用 SSL。在实际代码中,当 SSL_read/write / BIO_read/write 失败时,最好调用 SSL_get_error 并根据结果决定要做什么: SSL_ERROR_WANT_READ 是重要的,意味着你不能再 SSL_write 任何数据,因为它需要你首先读取并发送 bioOut BIO 中的待处理数据。

    【讨论】:

    • 这是一个很好的例子。在我是服务器的情况下,我是否只需将 SSL_set_connect_state() 调用替换为 SSL_set_accept_state() 调用?
    • 我只使用过客户端套接字和 OpenSSL,但根据我对文档的理解,它应该就这么简单。
    • 好的。另外,为什么在任何地方都调用 SendPendingHandshakeData() 是谨慎的?我假设握手只发生一次,在会话开始时。还是每次发送数据包时都会发生这种情况?
    • 理论上,如果连接的另一端有策略要求,则可以随时重新触发 ssl 握手。另外,编写这样的代码可以很好地实现无状态,因此它不需要从“协商”状态变为“连接”状态。
    【解决方案2】:

    你应该看看Boost.Asio

    【讨论】:

    • 是的,我发布的链接中有一些示例。
    • 即使它不能完全回答问题,boost::asio 也有足够的魅力值得 +1。
    猜你喜欢
    • 2021-08-05
    • 2014-02-08
    • 1970-01-01
    • 1970-01-01
    • 2015-04-23
    • 1970-01-01
    • 2021-08-30
    • 2010-11-13
    • 2014-08-15
    相关资源
    最近更新 更多