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

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/民意调查/ epoll照顾呢? 但是,首先应该写的信息呢?

还是应该读取失败后写入? 那么,当真正的parsing器位于主循环中时,什么防止从应用程序协议中读取字节,然后在应用程序的郊外的某个地方处理呢?

Solutions Collecting From Web of "如何在非阻塞套接字上处理OpenSSL SSL_ERROR_WANT_READ / WANT_WRITE"

对于非阻塞套接字, SSL_WANT_READ表示“等待套接字可读,然后再次调用此函数”。 ; 相反, SSL_WANT_WRITE表示“等待套接字是可写的,然后再次调用该函数”。 。 您可以从SSL_read()SSL_write()调用中获取SSL_WANT_WRITESSL_WANT_READ

你读了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是非阻塞的,当底层的BIO不能满足SSL_read()继续操作的需求时,SSL_read()也会返回。 在这种情况下,使用SSL_read()的返回值调用SSL_get_error(3)将产生SSL_ERROR_WANT_READ或SSL_ERROR_WANT_WRITE。 在任何时候都可以重新协商,所以调用SSL_read()也会导致写入操作! 调用过程必须在采取适当的措施以满足SSL_read()的需求之后重复调用。 行动取决于基础生物。 当使用非阻塞套接字时,不需要做任何事情,但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_read()操作中获得SSL_ERROR_WANT_WRITE ,则需要发送出站数据,或者至少等待套接字变为可写。 如果在ssl_write()操作中获得SSL_ERROR_WANT_READ ,则需要读取入站数据。

你应该订阅OpenSSL邮件列表 。 这个问题被问到很多。

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

同样,SSL_WANT_WRITE意味着SSL引擎正在等待您从中提取一些数据并将其发送给对等。

我曾经在2002年为Windows开发者期刊写过有关使用OpenSSL的非阻塞和异步套接字,虽然这篇文章表面上是针对Windows代码的,但其他平台的主体是一样的。 本文附带一些代码,它将OpenSSL与Windows上的异步套接字集成,并处理整个SSL_WANT_READ / SSL_WANT_WRITE问题。

从本质上讲,当你获得一个SSL_WANT_READ时,你需要对出站数据进行排队,直到读完成,并且你已经将新的入站数据传递到SSL引擎,一旦发生这种情况,你可以重试发送出站数据。