如何在非阻塞套接字上处理 OpenSSL SSL_ERROR_WANT_READ / WANT_WRITE

2024-11-07 08:55:00
admin
原创
475
摘要:问题描述: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 引擎,一旦发生这种情况,您就可以重试发送出站数据。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用