gpt4 book ai didi

c - 具有全双工套接字通信的 SSL 重新协商

转载 作者:太空宇宙 更新时间:2023-11-03 12:56:06 25 4
gpt4 key购买 nike

我有一个非常简单的客户端-服务器,它有一个阻塞套接字进行全双工通信。我已经为应用程序启用了 SSL/TLS。该模型是典型的生产者-消费者模型。客户端产生数据,将其发送到服务器,然后服务器处理它们。唯一的问题是,服务器偶尔会将数据发送回客户端,客户端会相应地处理这些数据。下面是应用程序的一个非常简单的伪代码:

  1 Client:
2 -------
3 while (true)
4 {
5 if (poll(pollin, timeout=0) || 0 < SSL_pending(ssl))
6 {
7 SSL_read();
8 // Handle WANT_READ or WANT_WRITE appropriately.
9 // If no error, handle the received control message.
10 }
11 // produce data.
12 while (!poll(pollout))
13 ; // Wait until the pipe is ready for a send().
14 SSL_write();
15 // Handle WANT_READ or WANT_WRITE appropriately.
16 if (time to renegotiate)
17 SSL_renegotiate(ssl);
18 }
19
20 Server:
21 -------
22 while (true)
23 {
24 if (poll(pollin, timeout=1s) || 0 < SSL_pending(ssl))
25 {
26 SSL_read();
27 // Handle WANT_READ or WANT_WRITE appropriately.
28 // If no error, consume data.
29 }
30 if (control message needs to be sent)
31 {
32 while (!poll(pollout))
33 ; // Wait until the pipe is ready for a send().
34 SSL_write();
35 // Handle WANT_READ or WANT_WRITE appropriately.
36 }
37 }

当出于测试目的,我强制进行 SSL 重新协商(第 16-17 行)时,问题就出现了。 session 开始时很轻松,但过了一会儿,我收到以下错误:

Client:
-------
error:140940F5:SSL routines:SSL3_READ_BYTES:unexpected record

Server:
-------
error:140943F2:SSL routines:SSL3_READ_BYTES:sslv3 alert unexpected message

事实证明,大约在客户端发起重新协商的同时(第 14 行),服务器最终向客户端发送应用程序数据(第 34 行)。客户端作为重新协商过程的一部分接收此应用程序数据并以“意外记录”错误轰炸。类似地,当服务器进行后续接收(第 26 行)时,它在期望应用程序数据时最终接收到重新协商数据。

我做错了什么?我应该如何使用全双工 channel 处理/测试 SSL 重新协商。请注意,不涉及任何线程。这是一个简单的单线程模型,读/写发生在套接字的两端。

更新:为了验证我编写的应用程序没有任何问题,我什至可以使用 OpenSSL 的 s_client 和 s_server 实现轻松地重现它。我启动了一个 s_server,一旦 s_client 连接到服务器,我就以编程方式将一堆应用程序数据从服务器发送到客户端,并将一堆“R”(重新协商请求)从客户端发送到服务器。最终,它们都以与上述完全相同的方式失败。

s_client:

RENEGOTIATING
4840:error:140940F5:SSL routines:SSL3_READ_BYTES:unexpected record:s3_pkt.c:1258:

s_server:

Read BLOCK
ERROR
4838:error:140943F2:SSL routines:SSL3_READ_BYTES:sslv3 alert unexpected message:s3_pkt.c:1108:SSL alert number 10
4838:error:140940E5:SSL routines:SSL3_READ_BYTES:ssl handshake failure:s3_pkt.c:1185:

更新 2:好的。正如 David 所建议的,我重新设计了测试应用程序以使用非阻塞套接字,并且总是首先执行 SSL_read 和 SSL_write,然后根据它们返回的内容进行选择,但在重新协商期间我仍然遇到相同的错误(SSL_write 最终从重新谈判中的另一方)。问题是,在任何时间点,如果 SSL_read 返回 WANT_READ,我是否可以假设这是因为管道中没有任何内容并继续使用 SSL_write,因为我有东西要写?如果不是,那可能就是我最终出错的原因。要么,要么我在重新谈判时全错了。请注意,如果 SSL_read 返回 WANT_WRITE,我总是会执行一次选择并再次调用 SSL_read。

最佳答案

您正试图“看穿” SSL 黑匣子。这是一个巨大的错误。

     if (poll(pollin, timeout=0) || 0 < SSL_pending(ssl))
{
SSL_read();

您假设为了让 SSL_read 向前推进,它需要从套接字读取数据。这是一个可能是错误的假设。例如,如果正在进行重新协商,SSL 引擎接下来可能需要发送数据,而不是读取数据。

     while (!poll(pollout))
; // Wait until the pipe is ready for a send().
SSL_write();

你怎么知道 SSL 引擎要将数据写入管道?它是否给了您 WANT_WRITE 指示?如果不是,可能需要读取重新协商数据才能发送。

要在非阻塞模式下使用 SSL,只需尝试您想要执行的操作。如果要读取解密后的数据,调用SSL_read。如果要发送加密数据,调用SSL_write。仅当 SSL 引擎告诉您并带有WANT_READWANT_WRITE指示时才调用poll

更新::您在阻塞和非阻塞方法之间有一个“各占一半”的混合体。这不可能工作。问题很简单:在调用 SSL_read 之前,您不知道它是否需要从套接字读取。如果您先调用 poll,即使 SSL_read 不需要从套接字读取,您也会阻塞。如果您先调用 SSL_read,如果确实需要从套接字读取数据,它将阻塞。 SSL_pending 对您没有帮助。如果 SSL_read 需要write 到套接字以取得前进的进展,SSL_pending 将返回零,但调用 poll 将永远阻止。

你有两个理智的选择:

  1. 阻止。让 socket 设置阻塞。当你想读的时候调用SSL_read,当你想写的时候调用SSL_write。他们阻止。阻塞套接字可以阻塞,这就是它们的工作方式。

  2. 非阻塞。将套接字设置为非阻塞。当你想读的时候调用SSL_read,当你想写的时候调用SSL_write。他们不会阻止。如果您收到 WANT_READ 指示,请按读取方向进行轮询。如果您收到 WANT_WRITE 指示,请轮询写入方向。请注意,SSL_read 返回 WANT_WRITE 是完全正常的,然后您在写入方向进行轮询。同理,SSL_write可以返回WANT_READ,然后你轮询读取的方向。

如果 SSL_read 的实现基本上是“读取一些数据然后解密它”并且 SSL_write 是“加密一些数据并发送它”,那么您的代码将(大部分)工作。问题是,这些函数实际上运行一个复杂的状态机,它根据需要读取和写入套接字,并最终导致为您提供解密数据或加密数据并发送它的效果。

关于c - 具有全双工套接字通信的 SSL 重新协商,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18728355/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com