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

2024-11-07 08:55:00
admin
原创
527
摘要:问题描述: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大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2482  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1533  
  PLM(产品生命周期管理)项目对于企业优化产品研发流程、提升产品质量以及增强市场竞争力具有至关重要的意义。然而,在项目推进过程中,范围蔓延是一个常见且棘手的问题,它可能导致项目进度延迟、成本超支以及质量下降等一系列不良后果。因此,有效避免PLM项目范围蔓延成为项目成功的关键因素之一。以下将详细阐述三大管控策略,助力企业...
plm系统   0  
  PLM(产品生命周期管理)项目管理在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和产品复杂度的提升,PLM项目面临着诸多风险。准确量化风险优先级并采取有效措施应对,是确保项目成功的关键。五维评估矩阵作为一种有效的风险评估工具,能帮助项目管理者全面、系统地评估风险,为决策提供有力支持。五维评估矩阵概述...
免费plm软件   0  
  引言PLM(产品生命周期管理)开发流程对于企业产品的全生命周期管控至关重要。它涵盖了从产品概念设计到退役的各个阶段,直接影响着产品质量、开发周期以及企业的市场竞争力。在当今快速发展的科技环境下,客户对产品质量的要求日益提高,市场竞争也愈发激烈,这就使得优化PLM开发流程成为企业的必然选择。缺陷管理工具和六西格玛方法作为...
plm产品全生命周期管理   0  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用