如何在非阻塞套接字上处理 OpenSSL SSL_ERROR_WANT_READ / WANT_WRITE
- 2024-11-07 08:55:00
- admin 原创
- 31
问题描述:
OpenSSL 库允许使用 SSL_read 从底层套接字读取数据,并使用 SSL_write 向其写入数据。这些函数可能返回 SSL_ERROR_WANT_READ 或 SSL_ERROR_WANT_WRITE,具体取决于它们的 SSL 协议需求(例如,重新协商连接时)。
我不太明白 API 希望我用这些结果做什么。
想象一个接受客户端连接的服务器应用程序,设置一个新的 ssl 会话,使底层套接字非阻塞,然后将文件描述符添加到 select/poll/epoll 循环中。
如果客户端发送数据,主循环将把该数据分派给 ssl_read。如果返回 SSL_ERROR_WANT_READ 或 SSL_ERROR_WANT_WRITE,这里该做什么?WANT_READ 可能很简单,因为下一个主循环迭代可能只会导致另一个 ssl_read。但是如果 ssl_read 返回 WANT_WRITE,应该使用什么参数来调用它?为什么库不自己发出调用?
如果服务器想要向客户端发送一些数据,它将使用 ssl_write。同样,如果返回了 WANT_READ 或 WANT_WRITE,该怎么办?可以通过重复刚刚调用的相同调用来回答 WANT_WRITE 吗?如果返回了 WANT_READ,是否应该返回主循环并让 select/poll/epoll 处理此问题?但是首先应该写入的消息怎么办?
或者应该在写入失败后立即进行读取?那么,当真正的解析器位于主循环中时,如何防止从应用程序协议读取字节,然后不得不在应用程序外围的某个地方处理它?
解决方案 1:
对于非阻塞套接字,SSL_WANT_READ
意味着“等待套接字可读,然后再次调用此函数。”;相反,SSL_WANT_WRITE
意味着“等待套接字可写,然后再次调用此函数。”。您可以从或调用中获取其中一个SSL_WANT_WRITE
或。SSL_WANT_READ
`SSL_read()`SSL_write()
解决方案 2:
SSL_read()
您是否已经阅读过OpenSSL 文档SSL_get_error()
?
SSL_read()
:
如果底层 BIO 阻塞,则 SSL_read() 仅在读取操作完成或发生错误后返回,除非重新协商,在这种情况下可能会发生 SSL_ERROR_WANT_READ。此行为可以通过 SSL_CTX_set_mode(3) 调用的 SSL_MODE_AUTO_RETRY 标志来控制。
如果底层 BIO 是非阻塞的,当底层 BIO 无法满足 SSL_read() 继续操作的需求时,SSL_read() 也会返回。在这种情况下,使用 SSL_read() 的返回值调用 SSL_get_error(3) 将产生 SSL_ERROR_WANT_READ 或 SSL_ERROR_WANT_WRITE。由于随时可能重新协商,因此对 SSL_read() 的调用也可能导致写入操作!调用进程必须在采取适当操作以满足 SSL_read() 的需求后重复调用。操作取决于底层 BIO。使用非阻塞套接字时,无需执行任何操作,但可以使用 select() 检查所需的条件。
SSL_get_error()
:
SSL_ERROR_WANT_READ,SSL_ERROR_WANT_WRITE
操作未完成;稍后应再次调用相同的 TLS/SSL I/O 函数。如果到那时,底层 BIO 有可供读取的数据(如果结果代码为 SSL_ERROR_WANT_READ)或允许写入数据(SSL_ERROR_WANT_WRITE),则将发生一些 TLS/SSL 协议进展,即至少部分 TLS/SSL 记录将被读取或写入。请注意,重试可能再次导致 SSL_ERROR_WANT_READ 或 SSL_ERROR_WANT_WRITE 条件。在应用程序协议级别上看到进展之前,可能需要的迭代次数没有固定的上限。
对于套接字 BIO(例如当使用 SSL_set_fd() 时),可以使用底层套接字上的 select() 或 poll() 来查明何时应重试 TLS/SSL I/O 函数。
警告:任何 TLS/SSL I/O 函数都可能导致 SSL_ERROR_WANT_READ 和 SSL_ERROR_WANT_WRITE。具体来说,SSL_read() 或 SSL_peek() 可能想要写入数据,而 SSL_write() 可能想要读取数据。这主要是因为 TLS/SSL 握手可能在协议期间的任何时间发生(由客户端或服务器发起);SSL_read()、SSL_peek() 和 SSL_write() 将处理任何待处理的握手。
OpenSSL 作为状态机实现。SSL_ERROR_WANT_READ
意味着需要更多的入站数据,也SSL_ERROR_WANT_WRITE
意味着需要更多的出站数据才能使连接继续前进。
如果得到SSL_ERROR_WANT_WRITE
,则表明 OpenSSL 需要发送出站数据但无法发送,因为套接字不再可写(对等方的接收缓冲区无法再容纳任何数据),因此您需要等待套接字变得可写(对等方已释放缓冲区空间),然后再次重试该操作。
如果得到SSL_ERROR_WANT_READ
,则表明 OpenSSL 需要读取入站数据但无法读取,因为套接字不再可读(套接字的接收缓冲区为空),因此您需要等待套接字变得可读(更多数据已到达),然后再次重试该操作。
你应该订阅OpenSSL 邮件列表。这个问题经常被问到。
解决方案 3:
SSL_WANT_READ 意味着 SSL 引擎当前无法为您加密,因为它正在等待更多输入数据(作为初始握手的一部分或重新协商的一部分),因此,一旦您的下一次读取完成并且您推送了通过 SSL 引擎到达的数据,您就可以重试写入操作。
同样,SSL_WANT_WRITE 意味着 SSL 引擎正在等待您从中提取一些数据并将其发送给对等方。
早在 2002 年,我就曾在 Windows Developer Journal 上撰写过关于使用 OpenSSL 和无阻塞及异步套接字的文章(转载于此处),尽管这篇文章表面上是针对 Windows 代码的,但原理对于其他平台也是一样的。本文附带了一些代码,这些代码将 OpenSSL 与 Windows 上的异步套接字集成在一起,并处理整个 SSL_WANT_READ/SSL_WANT_WRITE 问题。
本质上,当您收到 SSL_WANT_READ 时,您需要对出站数据进行排队,直到读取完成并将新的入站数据传递到 SSL 引擎,一旦发生这种情况,您就可以重试发送出站数据。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件