Linux 如何在非阻塞套接字上处理 OpenSSL SSL_ERROR_WANT_READ / WANT_WRITE
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3952104/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to handle OpenSSL SSL_ERROR_WANT_READ / WANT_WRITE on non-blocking sockets
提问by dantje
The OpenSSL library allows to read from an underlying socket with SSL_read and write to it with SSL_write. These functions maybe return with SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE depending on their ssl protocol needs (for example when renegotiating a connection).
OpenSSL 库允许使用 SSL_read 从底层套接字读取并使用 SSL_write 写入它。这些函数可能会返回 SSL_ERROR_WANT_READ 或 SSL_ERROR_WANT_WRITE,具体取决于它们的 ssl 协议需求(例如,在重新协商连接时)。
I don't really understand what the API wants me to do with these results.
我真的不明白 API 想让我对这些结果做什么。
Imaging a server app that accepts client connections, sets up a new ssl session, makes the underlying socket non-blocking and then adds the filedescriptor to a select/poll/epoll loop.
对接受客户端连接的服务器应用程序进行映像,设置新的 ssl 会话,使底层套接字非阻塞,然后将文件描述符添加到选择/轮询/epoll 循环。
If a client sends data, the main loop will dispatch this to a ssl_read. What has to be done here if SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE is returned? WANT_READ might be easy, because the next main loop iteration could just lead to another ssl_read. But if the ssl_read return WANT_WRITE, with what parameters should it be called? And why doesn't the library issue the call itself?
如果客户端发送数据,主循环会将其分派给 ssl_read。如果返回 SSL_ERROR_WANT_READ 或 SSL_ERROR_WANT_WRITE,这里必须做什么?WANT_READ 可能很容易,因为下一次主循环迭代可能会导致另一个 ssl_read。但是如果ssl_read返回WANT_WRITE,应该用什么参数调用呢?为什么图书馆不发出调用本身?
If the server wants to send a client some data, it will use ssl_write. Again, what is to be done if WANT_READ or WANT_WRITE are returned? Can the WANT_WRITE be answered by repeating the very same call that just was invoked? And if WANT_READ is returned, should one return to the main loop and let the select/poll/epoll take care of this? But what about the message that should be written in the first place?
如果服务器想要向客户端发送一些数据,它将使用 ssl_write。同样,如果返回 WANT_READ 或 WANT_WRITE 该怎么办?WANT_WRITE 可以通过重复刚才调用的相同调用来回答吗?如果返回 WANT_READ,是否应该返回主循环并让 select/poll/epoll 处理这个问题?但是首先应该写的消息呢?
Or should the read be done right after the failed write? Then, what protects against reading bytes from the application protocol and then having to deal with it somewhere in the outskirts of the app, when the real parser sits in the mainloop?
还是应该在写入失败后立即进行读取?那么,当真正的解析器位于主循环中时,是什么防止从应用程序协议读取字节然后不得不在应用程序外围的某个地方处理它?
采纳答案by caf
With non-blocking sockets, SSL_WANT_READ
means "wait for the socket to be readable, then call this function again."; conversely, SSL_WANT_WRITE
means "wait for the socket to be writeable, then call this function again.". You can get either SSL_WANT_WRITE
or SSL_WANT_READ
from both an SSL_read()
or SSL_write()
call.
对于非阻塞套接字,SSL_WANT_READ
意味着“等待套接字可读,然后再次调用此函数”。; 相反,SSL_WANT_WRITE
表示“等待套接字可写,然后再次调用此函数”。. 你可以得到两种SSL_WANT_WRITE
或SSL_WANT_READ
来自一个SSL_read()
或SSL_write()
通话。
回答by Len Holgate
SSL_WANT_READ means that the SSL engine can't currently encrypt for you as it's waiting for more input data (either as part of the initial handshake or as part of a renegotiation), so, once your next read has completed and you've pushed the data that arrived through the SSL engine you can retry your write operation.
SSL_WANT_READ 意味着 SSL 引擎当前无法为您加密,因为它正在等待更多输入数据(作为初始握手的一部分或作为重新协商的一部分),因此,一旦您的下一次读取完成并且您已推送通过 SSL 引擎到达的数据,您可以重试写入操作。
Likewise, SSL_WANT_WRITE means that the SSL engine is waiting for you to extract some data from it and send it to the peer.
同样,SSL_WANT_WRITE 意味着 SSL 引擎正在等待您从中提取一些数据并将其发送给对等方。
I wrote about using OpenSSL with non blocking and async sockets back in 2002 for Windows Developer Journal (reprinted here) and although this article is ostensibly aimed at Windows code the principals are the same for other platforms. The article comes with some code that integrates OpenSSL with async sockets on Windows and which deals with the whole SSL_WANT_READ/SSL_WANT_WRITE issue.
早在 2002 年,我就为 Windows Developer Journal(在此处转载)撰写了关于使用 OpenSSL 和非阻塞和异步套接字的文章,尽管这篇文章表面上是针对 Windows 代码的,但其他平台的原理是相同的。这篇文章附带了一些将 OpenSSL 与 Windows 上的异步套接字集成在一起的代码,这些代码处理了整个 SSL_WANT_READ/SSL_WANT_WRITE 问题。
Essentially, when you get an SSL_WANT_READ you need to queue outbound data until you've had a read complete and you've passed the new inbound data into the SSL engine, once that has happened you can retry sending your outbound data.
本质上,当您获得 SSL_WANT_READ 时,您需要对出站数据进行排队,直到读取完成并将新的入站数据传递到 SSL 引擎,一旦发生这种情况,您就可以重试发送出站数据。
回答by Remy Lebeau
Did you read the OpenSSL documentation for ssl_readand ssl_get_erroryet?
您是否已阅读ssl_read和ssl_get_error的 OpenSSL 文档?
ssl_read:
ssl_读:
If the underlying BIO is blocking, SSL_read() will only return, once the read operation has been finished or an error occurred, except when a renegotiation take place, in which case a SSL_ERROR_WANT_READ may occur. This behaviour can be controlled with the SSL_MODE_AUTO_RETRY flag of the SSL_CTX_set_mode(3) call.
If the underlying BIO is non-blocking, SSL_read() will also return when the underlying BIO could not satisfy the needs of SSL_read() to continue the operation. In this case a call to SSL_get_error(3) with the return value of SSL_read() will yield SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE. As at any time a re-negotiation is possible, a call to SSL_read() can also cause write operations! The calling process then must repeat the call after taking appropriate action to satisfy the needs of SSL_read(). The action depends on the underlying BIO. When using a non-blocking socket, nothing is to be done, but select() can be used to check for the required condition.
如果底层 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_get_error:
SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE
The operation did not complete; the same TLS/SSL I/O function should be called again later. If, by then, the underlying BIO has data available for reading (if the result code is SSL_ERROR_WANT_READ) or allows writing data (SSL_ERROR_WANT_WRITE), then some TLS/SSL protocol progress will take place, i.e. at least part of an TLS/SSL record will be read or written. Note that the retry may again lead to a SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE condition. There is no fixed upper limit for the number of iterations that may be necessary until progress becomes visible at application protocol level.
For socket BIOs (e.g. when SSL_set_fd() was used), select() or poll() on the underlying socket can be used to find out when the TLS/SSL I/O function should be retried.
Caveat: Any TLS/SSL I/O function can lead to either of SSL_ERROR_WANT_READ and SSL_ERROR_WANT_WRITE. In particular, SSL_read() or SSL_peek() may want to write data and SSL_write() may want to read data. This is mainly because TLS/SSL handshakes may occur at any time during the protocol (initiated by either the client or the server); SSL_read(), SSL_peek(), and SSL_write() will handle any pending handshakes.
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 is implemented as a state machine. SSL_ERROR_WANT_READ
means that more inbound data, and SSL_ERROR_WANT_WRITE
means that more outbound data, is needed in order to make forward progress on the connection. If you get SSL_ERROR_WANT_WRITE
on an ssl_read() operation, you need to send outbound data, or at least wait for the socket to become writable. If you get SSL_ERROR_WANT_READ
on an ssl_write() operation, you need to read inbound data.
OpenSSL 是作为状态机实现的。 SSL_ERROR_WANT_READ
意味着需要更多的入站数据和SSL_ERROR_WANT_WRITE
更多的出站数据,以便在连接上取得进展。如果您SSL_ERROR_WANT_WRITE
进行 ssl_read() 操作,则需要发送出站数据,或者至少等待套接字变为可写状态。如果您SSL_ERROR_WANT_READ
进行 ssl_write() 操作,则需要读取入站数据。
You should subscribe to the OpenSSL mailing lists. This question gets asked alot.
您应该订阅OpenSSL 邮件列表。这个问题被问到很多。