【问题标题】:Writing partial packet to SSL BIO将部分数据包写入 SSL BIO
【发布时间】:2018-04-20 00:19:30
【问题描述】:

我有一个读取和写入数据的套接字应用程序。我正在使用 OpenSSL 进行加密/解密。我的问题是“BIO_write”方法是否可以在内部缓冲数据,或者当我从套接字读取更多内容时我是否必须附加到不断增长的缓冲区。这就是我正在做的事情。

我从套接字读取,并使用下面的类方法将所有读入的字节写入 BIO:

int CSslConnectionContext::Store(BYTE* pbData, DWORD dwDataLength)
{
    int bytes = 0;
    if (dwDataLength > 0)
    {
        bytes = BIO_write(bio[BIO_RECV], pbData, dwDataLength);
    }

    return bytes;
}

然后我立即调用 SSL_read 方法获取解密数据:

int CSslConnectionContext::Read(BYTE* pbBuffer, DWORD dwBufferSize)
{
    int bytes = SSL_read(ssl, pbBuffer, dwBufferSize);
    return bytes;
}

如果 SSL_read 返回一个正数,那么我的应用程序就有可用的解密数据。

我不确定的是,当我的套接字读取没有在一次读取中捕获解密所需的所有数据时会发生什么。

所以如果我需要 100 字节才能解密数据并且第一次读取只有 80,我可以用那些 80 调用 BIO_write(),再进行一次套接字读取以获取下一个 20,然后调用 BIO_write()只有这 20 个字节?

或者我是否需要编写代码,所以当我阅读 80 时,我会执行以下操作:

  1. 使用 80 字节调用 BIO_write()。
  2. 如果返回失败指示符 - 保留这 80 个字节。
  3. 从套接字读取接下来的 20 个字节并将其附加到缓冲的 80 个字节。
  4. 使用 100 字节调用 BIO_write()

【问题讨论】:

  • SSL_read() 的手册页似乎处理了在 SSL_read 可以返回任何数据之前在底层 bio 中需要更多数据的情况。在这种情况下,SSL_read() 将返回一个负数,然后 SSL_get_error() 将返回一个对应于 SSL_WANT_READ 或 SSL_WANT_WRITE 的值。

标签: sockets ssl encryption openssl


【解决方案1】:

OpenSSL 将内部缓冲区(我们称之为 SSL 堆栈)保存在 TCP 堆栈之上。 OpenSSL 库处理 SSL 堆栈。 BIO_xxx() 函数可以在不同的端点上运行:即内存、套接字。 它的行为取决于它所操作的实际项目。例如,如果 BIO_write() 使用内存 (BIO_s_mem),则 BIO_write 永远不会失败,除非内存不足。但是如果它使用套接字,并且套接字是非阻塞的,它可以在失败时返回错误,或者它可以写入一些字节而不是套接字缓冲区已满的所有请求字节。

因此,如何使用/处理缓冲区取决于许多因素,但最值得注意的是:

  • 阻塞或非阻塞 IO
  • 操作的 BIO 对象(内存、套接字等)

例如,如果您使用 BIO_s_mem 和非阻塞套接字操作,则可以应用以下技术:

  1. 使用 BIO_write 写入缓冲区,并检查是否失败。如果没有失败,您可以确定您已将所有缓冲区写入 SSL 堆栈。
  2. 调用 Read_SSL 并检查错误,如果错误是 WANT_READ 或 WANT_WRITE,则需要向 SSL 堆栈写入更多数据才能读取有效记录。

对于问题和示例:

您可以部分写入(尽可能多,甚至 1 个字节)。例如,如果您从套接字读取 80 个字节,则使用 BIO_write 写入这些字节。然后调用 SSL_read 可能会失败(WANT_READ、WANT_WRITE 或其他)。然后您从套接字接收 20 个字节,然后使用 BIO_write 写入这些字节。然后再次调用 SSL_read。每当 SSL_read 返回时没有错误,这意味着 SSL 堆栈解码了一条有效记录。

但是理解等待非阻塞套接字使用 select() 来处理 SSL 读/写非常麻烦,这一点非常重要。当您已经在等待套接字的 READ 事件时,一次 SSL_write 可能会导致多次写入套接字。

【讨论】:

  • 谢谢哈亚提。您的示例(BIO_s_mem 和非阻塞套接字)正是我正在做的。这听起来像我写 80 个字节然后 20 个字节就可以的示例。这是它的工作方式吗?每个 BIO_write() 都会将数据追加到内部缓冲区,直到调用 SSL_read()?
  • 是的,它附加了内部 SSL 缓冲区。我还更新了我的答案以涵盖您的情况。
【解决方案2】:

请使用 bio_pending.. 了解 openssl.. 可用的所有字节。使用 bio_pending 的返回值循环。这应该在 bio_read 之前调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-05
    • 2012-05-05
    • 2014-05-10
    • 1970-01-01
    相关资源
    最近更新 更多