【问题标题】:OpenSSL Custom Memory BIO for a sockets library用于套接字库的 OpenSSL 自定义内存 BIO
【发布时间】:2020-03-11 07:36:29
【问题描述】:

我正在使用一个模拟 Berkeley 套接字 API 的传输库来使用它(包括阻塞和非阻塞模式)。需要给我发送的数据加上TLS加密,可以想到两种方法:

  1. 自定义 BIO:找到了 Socket BIO 的代码,因此考虑制作一个副本并将所有 berkeley 套接字调用替换为该库的函数。但是,我在网上找不到太多关于自定义 BIO 的信息,所以要小心我在没有得到太多帮助的情况下会遇到的陷阱。

  2. Memory BIO:这种方法有更多的追随者,也有不少例子。虽然,大多数人警告说,具有非阻塞套接字的内存 BIO 比阻塞路由复杂一个数量级。

关于内存 BIO 方法,我看到的源代码对我来说很有意义,但它是一个简单的回显客户端/服务器。让我很困惑的是当 SSL_Read/SSL_Write 返回 SSL_WANT_READ 或 SSL_WANT_WRITE 时该怎么办。我的理解是,在 Blocking Socket BIO 的情况下,您只需稍后重试调用,因为底层代码会处理这些事情。

如果是内存 BIO + 非阻塞套接字,例如如果 SSL_Read 返回 SSL_WANT_WRITE,这是否意味着我的代码应该从输出 BIO (BIO_read) 中读取并将其发送到套接字,并且在原始 SSL_Read 调用成功之前不允许任何 SSL_Read/SSL_Write?在此期间允许 SSL_Write 可以吗?

编辑:我将专门使用 TLS 1.3,只是发现它不支持重新协商。这是否意味着一旦建立连接,我就不必担心 SSL_Read 上的 WANT_WRITE 和 SSL_Write 上的 WANT_READ 了?

【问题讨论】:

    标签: openssl


    【解决方案1】:

    “在内存 BIO + 非阻塞套接字的情况下,例如如果 SSL_Read 返回 SSL_WANT_WRITE,这是否意味着我的代码应该从输出 BIO (BIO_read) 中读取并将其发送到套接字” - - 是的。获取输出 BIO 中的所有字节并将它们写入套接字。

    解释了here为什么会发生这种情况:

    任何 TLS/SSL I/O 函数都可能导致 SSL_ERROR_WANT_READ 和 SSL_ERROR_WANT_WRITE。特别是 SSL_read_ex()、SSL_read()、 SSL_peek_ex() 或 SSL_peek() 可能想要写入数据和 SSL_write() 或 SSL_write_ex() 可能想要读取数据。这主要是因为 TLS/SSL 在协议期间的任何时间都可能发生握手(由 客户端或服务器); SSL_read_ex()、SSL_read()、 SSL_peek_ex()、SSL_peek()、SSL_write_ex() 和 SSL_write() 将处理 任何未决的握手。

    一旦 SSL_read 以这种方式失败,我认为 SSL_read 的进一步尝试不会成功,直到您将更多字节写入输入 bio。

    与此同时,您可以进一步尝试 SSL_write;只需检查返回码和 SSL 状态以检查数据是否部分或完全传输。

    我有一些示例代码写在github

    【讨论】:

    • 您的代码是否经过彻底的错误测试?它看起来比我预期的要简单。例如。在 do_encrypt 中,如果 SSL_Write 返回 WANT_READ,则无法处理这种情况,并且循环将立即重试 SSL_Write。对吗?
    • 这是示例代码,不保证没有错误或完全正确(尽管我在产品中使用它的变体已有几年了)。如果 SSL_write 不成功(例如 WANT_READ),则函数返回选择/轮询循环。看这里,当使用非阻塞套接字时,什么都不用做,但是可以使用 select() 来检查需要的条件。 [openssl.org/docs/man1.0.2/man3/SSL_write.html]
    • 我刚刚在我的问题中添加了一条注释,基本上,我将专门使用 TLS 1.3,所以一旦建立连接,我认为我不需要担心 WANT_WRITE 和 WANT_READ。相关问题:OpenSSL 文档说 SSL_Read 将返回 TLS 记录。这是否意味着每个 SSL_Write 中的数据都被视为单独的记录(消息),并且 SSL_Read 将继续请求数据,直到它能够组装完整的记录(消息)?
    • 关于 TLS 1.3 的有趣点。对于 SSL_read,根据文档,它似乎是肯定的,它“基于 SSL/TLS 记录......只有在完全接收到记录时,才能处理它”。至于SSL_write,我觉得单次调用可以生成多条记录。
    • 可以从两个不同的线程同时调用 SSL_read 和 SSL_write 吗?例如如果 SSL_read 被阻塞(阻塞套接字)等待数据,是否可以让另一个线程调用 SSL_write?
    猜你喜欢
    • 1970-01-01
    • 2016-05-14
    • 1970-01-01
    • 2021-02-03
    • 2016-11-25
    • 1970-01-01
    • 2016-01-27
    • 2019-03-26
    • 2019-06-12
    相关资源
    最近更新 更多