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

时间:2010-10-17 05:06:49

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

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

3 个答案:

答案 0 :(得分:47)

对于非阻塞套接字,SSL_WANT_READ表示“等待套接字可读,然后再次调用此函数。”;相反,SSL_WANT_WRITE表示“等待套接字可写,然后再次调用此函数。”。您可以通过SSL_WANT_WRITESSL_WANT_READ来电获得SSL_read()SSL_write()

答案 1 :(得分:14)

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

ssl_read:

  

如果底层BIO阻塞,   SSL_read()只会返回一次   读取操作已完成或已完成   发生错误,除了a   重新谈判发生在其中   情况可能会发生SSL_ERROR_WANT_READ。   可以使用控制此行为   SSL_MODE_AUTO_RETRY标志   SSL_CTX_set_mode(3)调用。

     

如果底层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_ERROR_WANT_READ,SSL_ERROR_WANT_WRITE

     

手术未完成;该   应该是相同的TLS / SSL I / O功能   稍后再打电话。那么,到那时,   底层BIO有可用的数据   阅读(如果结果代码是   SSL_ERROR_WANT_READ)或允许写入   数据(SSL_ERROR_WANT_WRITE),然后一些   将采用TLS / SSL协议进度   地方,即TLS / SSL的至少一部分   记录将被读取或写入。注意   重试可能再次导致a   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 mailing lists。这个问题很多人被问到了。

答案 2 :(得分:5)

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

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

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

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

相关问题