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

dan*_*tje 37 sockets linux openssl

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处理这个问题?但是首先应该写的信息呢?

或者应该在写入失败后立即完成读取?那么,当真正的解析器位于主循环中时,什么可以防止从应用程序协议中读取字节,然后在应用程序的郊区某处处理它?

caf*_*caf 55

使用非阻塞套接字,SSL_WANT_READ意味着"等待套接字可读,然后再次调用此函数".; 相反,SSL_WANT_WRITE意味着"等待套接字可写,然后再次调用此函数." .您既可以获得一个SSL_WANT_WRITESSL_WANT_READ两个SSL_read()或一个SSL_write()电话.


Rem*_*eau 16

您是否阅读过ssl_readssl_get_error的OpenSSL文档?

ssl_read:

如果底层BIO阻塞,则SSL_read()将仅在读取操作完成或发生错误时返回,除非发生重新协商,在这种情况下可能会发生SSL_ERROR_WANT_READ.可以使用SSL_CTX_set_mode(3)调用的SSL_MODE_AUTO_RETRY标志来控制此行为.

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.

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.

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_WANT_READ确实*不*要求我发出SSL_read(),SSL_WANT_WRITE也没有要求我调用SSL_write(),但只是表明我应该重试同样的当下面的套接字变为可读或可写时,调用刚刚返回.因此,应该将它们解释为SSL_WANTS_A_READABLE_SOCKET和SSL_WANTS_A_WRITEABLE_SOCKET. (20认同)

Len*_*ate 7

SSL_WANT_READ表示SSL引擎当前无法为您加密,因为它正在等待更多输入数据(作为初始握手的一部分或作为重新协商的一部分),因此,一旦您的下一次读取完成并且您已推送通过SSL引擎到达的数据,您可以重试您的写入操作.

同样,SSL_WANT_WRITE表示SSL引擎正在等待您从中提取一些数据并将其发送给对等方.

我在2002年为Windows Developer Journal撰写了关于使用OpenSSL和非阻塞和异步套接字的文章(在此重印))文章,虽然这篇文章表面上是针对Windows代码的,但其他平台的主体是相同的.本文附带了一些代码,这些代码在Windows上将OpenSSL与异步套接字集成,并处理整个SSL_WANT_READ/SSL_WANT_WRITE问题.

基本上,当您获得SSL_WANT_READ时,您需要将出站数据排队,直到您完成读取并且已将新的入站数据传递到SSL引擎,一旦发生这种情况,您可以重试发送出站数据.