SSL_shutdown() returns -1 且 errno 为 0

SSL_shutdown() returns -1 and errno is 0

在我的 C++ 应用程序中,我使用 OpenSSL 连接到使用非阻塞 BIO 的服务器。我正在为 mac OS X 和 iOS 开发。

第一次调用SSL_shutdown() returns 0。这意味着我必须再次调用SSL_shutdown()

The following return values can occur:

0 The shutdown is not yet finished. Call SSL_shutdown() for a second time, if a bidirectional shutdown shall be performed. The output of SSL_get_error may be misleading, as an erroneous SSL_ERROR_SYSCALL may be flagged even though no error occurred.

<0 The shutdown was not successful because a fatal error occurred either at the protocol level or a connection failure occurred. It can also occur if action is need to continue the operation for non-blocking BIOs. Call SSL_get_error with the return value ret to find out the reason.

https://www.openssl.org/docs/ssl/SSL_shutdown.html

到目前为止,上帝。第二次调用 SSL_shutdown() 时出现问题。 returns -1 这意味着发生了错误(见上文)。现在,如果我用 SSL_get_error() 检查,我会得到错误 SSL_ERROR_SYSCALL,这反过来应该意味着发生了系统错误。但现在抓住了。如果我检查 errno 它 returns 0 -> 未知错误。到目前为止,我所读到的关于这个问题的内容是,这可能意味着服务器只做了 "hang up",但老实说,这并不能让我满意。

这是我的关机实现:

int result = 0;
int shutdownResult;
while ((shutdownResult = SSL_shutdown(sslHandle)) != 1) { //close connection 1 means everything is shut down ok
  if (shutdownResult == 0) { //we are supposed to call shutdown again
    continue;
  } else if (SSL_get_error(sslHandle, shutdownResult) == SSL_ERROR_WANT_READ) {
                [...] //omitted want read code, in this case the application never reaches this point
  } else if (SSL_get_error(sslHandle, shutdownResult) == SSL_ERROR_WANT_WRITE) {
                [...] //omitted want write code, in this case the application never reaches this point
  } else {
    logError("Error in ssl shutdown, ssl error: " + std::to_string(SSL_get_error(sslHandle, shutdownResult)) + ", system error: " + std::string(strerror(errno))); //something went wrong
    break;
  }
} 

当 运行 应用程序记录时:

ERROR:: Error in ssl shutdown, ssl error: 5, system error: Undefined error: 0

那么这里只是服务器关闭了连接还是存在更严重的问题?我只是错过了一些非常明显的东西吗?

完全关闭 SSL 包括两部分:

  • 向对等方发送 'close notify' 警报
  • 收到来自同行的 'close notify' 警报

第一个 SSL_shutdown 返回 0,这意味着它确实将 'close notify' 发送给了对等方,但尚未收到任何回复。 SSL_shutdown 的第二次调用失败,因为对等点没有执行正确的 SSL 关闭并发回 'close notify',而是关闭了底层的 TCP 连接。

这种行为实际上很常见,您通常可以忽略该错误。底层的 TCP 连接是否应该关闭并不重要。但是当你想在同一个 TCP 连接上以纯文本形式继续时,通常需要适当的 SSL 关闭,就像 FTPS 连接中的 CCC 命令所需要的那样(但即使有各种实现也无法正确处理这种情况)。