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

mefy6pfw  于 2023-01-01  发布在  Linux
关注(0)|答案(3)|浏览(529)

OpenSSL库允许使用SSL_read从底层套接字读取,并使用SSL_write向其写入。这些函数可能返回SSL_ERROR_WANT_READ或SSL_ERROR_WANT_WRITE,具体取决于它们的ssl协议需要(例如,当重新协商连接时)。
我真的不明白API想让我对这些结果做什么。
想象一个接受客户端连接的服务器应用程序,建立一个新的ssl会话,使底层套接字不阻塞,然后将filedescriptor添加到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处理这个问题?但是,一开始就应该写的信息呢?
还是应该在写操作失败后立即执行读操作?那么,当真实的的解析器位于主循环中时,如何防止从应用协议阅读字节,然后不得不在应用外围的某个地方处理它呢?

blmhpbnm

blmhpbnm1#

对于非阻塞套接字,SSL_WANT_READ意味着 “等待套接字可读,然后再次调用此函数。";相反,SSL_WANT_WRITE表示 “等待套接字变为可写,然后再次调用此函数。".您可以从SSL_read()SSL_write()调用中获取SSL_WANT_WRITESSL_WANT_READ

iqxoj9l9

iqxoj9l92#

您是否已阅读SSL_read()SSL_get_error()的OpenSSL文档?
SSL_read()
如果底层BIO阻塞,则SSL_read()仅在读取操作完成或发生错误时返回,除非发生重新协商,在这种情况下可能发生SSL_ERROR_WANT_READ。此行为可通过SSL_CTX_set_mode(3)调用的SSL_MODE_AUTO_RETRY标志控制。
如果底层BIO是非阻塞的,则SSL_read当底层BIO无法满足SSL_read的需求时,也会返回()以继续操作。在本例中,调用SSL_get_error(3)返回值为SSL_read()将生成SSL_ERROR_WANT_READ或SSL_ERROR_WANT_WRITE。由于在任何时候都可能进行重新协商,调用SSL_read()也可能导致写操作!调用进程必须在采取适当的操作以满足SSL_read的需要后重复调用动作取决于底层的BIO。当使用非阻塞套接字时,什么也不用做,但可以使用select()来检查所需的条件。
SSL_get_error()
SSL错误希望读取、SSL错误希望写入
操作未完成;相同的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 mailing lists。这个问题经常被问到。

mcdcgff0

mcdcgff03#

SSL_WANT_READ意味着SSL引擎当前无法为您加密,因为它正在等待更多输入数据(作为初始握手的一部分或作为重新协商的一部分),因此,一旦您的下一次读取完成,并且您已经通过SSL引擎推送了到达的数据,您就可以重试写入操作。
同样,SSL_WANT_WRITE意味着SSL引擎正在等待您从中提取一些数据并将其发送给对等方。
早在2002年,我就为Windows Developer Journal(转载于here)写过关于使用OpenSSL与非阻塞和异步套接字的文章,尽管这篇文章表面上是针对Windows代码的,但原理在其他平台上是相同的。这篇文章附带了一些代码,这些代码将OpenSSL与Windows上的异步套接字集成在一起,并处理了整个SSL_WANT_READ/SSL_WANT_WRITE问题。
本质上,当您收到SSL_WANT_READ时,您需要对出站数据进行排队,直到您完成读取并将新的入站数据传递到SSL引擎中,一旦发生这种情况,您就可以重试发送出站数据。

相关问题