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

2024-11-07 08:55:00
admin
原创
508
摘要:问题描述: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大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2079  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1459  
  建筑行业正处于数字化转型的关键时期,建筑产品生命周期管理(PLM)系统的实施对于提升项目效率、质量和协同性至关重要。特别是在 2025 年,基于建筑信息模型(BIM)的项目进度优化工具成为众多建筑企业关注的焦点。这些工具不仅能够整合项目全生命周期的数据,还能通过精准的分析和模拟,为项目进度管理提供强大支持。BIM 与建...
plm是什么软件   0  
  PLM系统开发的重要性与现状PLM(产品生命周期管理)系统在现代企业的产品研发、生产与管理过程中扮演着至关重要的角色。它贯穿产品从概念设计到退役的整个生命周期,整合了产品数据、流程以及人员等多方面的资源,极大地提高了企业的协同效率和创新能力。通过PLM系统,企业能够实现产品信息的集中管理与共享,不同部门之间可以实时获取...
国产plm软件   0  
  PLM(产品生命周期管理)系统在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和技术的飞速发展,企业对PLM系统的迭代周期优化需求日益迫切。2025年敏捷认证对项目管理提出了新的要求,其中燃尽图作为一种强大的可视化工具,在PLM系统迭代周期优化中有着广泛且重要的应用。深入探讨这些应用,对于提升企业的项...
plm系统主要干什么的   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用