SSL_shutdown 手册页和程序行为之间无法理解

问题描述 投票:0回答:1

我尝试编写函数来处理 SSL 关闭。下面是服务器代码的一部分,我使用非块模式。

   int r = SSL_shutdown(ssl);
   if (r == 1)
   {
      return Success;
   }

   // according to man/SSL_shutdown, 0 means "in progress"
   if (r == 0)
   {
      switch ((r = SSL_get_error(ssl, r)))
      {
         case SSL_ERROR_WANT_READ:
            std::cout << "shutdown want read" << std::endl;
            ...
            return ...;

         case SSL_ERROR_WANT_WRITE:
            std::cout << "shutdown want write" << std::endl;
            ...
            return ...;

         default:
            std::cout << r << " " << strerror(errno) << std::endl;
            ...
            return ...;
      }
   }

这是客户端代码的一部分,我在其中使用阻塞模式。根据男人的说法,我应该调用两次。

   if (SSL_shutdown(ssl) == 0)
   {
      if (SSL_shutdown(ssl) != 1)
      {
         report_error_and_exit("SSL_shutdown");
      }
   }

在服务器中,SSL_shutdown 返回 0。根据手册页,SSL_get_error 应该返回 SSL_ERROR_WANT_READ 或 SSL_ERROR_WANT_WRITE。

引用:https://www.openssl.org/docs/manmaster/man3/SSL_shutdown.html

如果底层 BIO 是非阻塞的并且关闭过程尚未完成(例如,因为尚未从对等方收到 close_notify 警报消息,或者因为需要发送 close_notify 警报消息但当前会阻塞),则 SSL_shutdown ()返回0表示关闭过程仍在进行中;在这种情况下,调用 SSL_get_error(3) 将产生 SSL_ERROR_WANT_READ 或 SSL_ERROR_WANT_WRITE。

但是,我从默认情况下打印 r = 5 (SSL_ERROR_SYSCALL)。在这种情况下,该人说应该检查 errno,但 strerror 返回“成功”。一切都是那么的扑朔迷离。

c++ ssl openssl
1个回答
0
投票

好的,我想我现在可以回答这个问题了,因为我找到了一些更好的文档(好的旧Linux):

https://linux.die.net/man/3/ssl_shutdown

所以,引用那里:

关闭过程包括2个步骤:发送“关闭通知”关闭警报和接收对端的“关闭通知”关闭警报。

根据 TLS 标准,应用程序可以只发送关闭警报,然后关闭底层连接,而不等待对等方的响应(这样可以节省资源,因为进程已经可以终止或服务另一个连接) 。当底层连接用于更多通信时,必须执行完整的关闭过程(双向“关闭通知”警报),以便对等点保持同步。

所以 SSL_shutdown 确实是一个两步过程。然后它接着说(我的评论和细微的澄清编辑):

当应用程序是第一个发送“关闭通知”警报的一方时[我认为,这里就是这种情况],

SSL_shutdown()
将仅发送警报,然后设置
SSL_SENT_SHUTDOWN
标志(以便会话被认为是好的并将保存在缓存中)。

SSL_shutdown()
随后将返回
0
。如果单向关闭就足够了(即底层连接无论如何都应该关闭),第一次调用
SSL_shutdown()
就足够了

为了完成双向关闭握手,必须再次调用

SSL_shutdown()
。第二个调用将使
SSL_shutdown()
等待对等方的“关闭通知”关闭警报。成功后,第二次调用
SSL_shutdown()
将返回
1

换句话说,如果您打算处置

ssl
(在发布的代码中),那么调用
SSL_shutdown
一次就足够了(这就是我所做的)。 OTOH,如果您打算再次使用
ssl
,您可能需要调用它两次。

还有一些其他的障碍,但归根结底是,如果

SSL_shutdown
返回
0
,并且你想重用
ssl
,那么你必须再次调用它。如果它返回
1
,则您不会(无论您未来的计划如何
ssl
)。

最后,它这样说:

如果底层 BIO 阻塞,

SSL_shutdown()
仅在握手步骤完成或发生错误后才会返回。

我的意思是,对于阻塞套接字,您需要调用它一次。对于非阻塞套接字,您需要更加小心。但是,我对文档的阅读告诉我,对此进行编码的最可靠的方法(如果您打算重用

ssl
)将是:

int rc = SSL_shutdown (ssl);
if (rc == 0)
    rc = SSL_shutdown (ssl);
...

但是我永远不会在 OpenSSL 中使用非阻塞套接字,因为有太多陷阱。

很高兴得到明智的头脑对上述任何问题的纠正。谢谢。

© www.soinside.com 2019 - 2024. All rights reserved.