如何在非阻塞套接字上处理 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 希望我...

问题描述:

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 引擎,一旦发生这种情况,您就可以重试发送出站数据。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用