- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个非常简单的客户端-服务器,它有一个阻塞套接字进行全双工通信。我已经为应用程序启用了 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_READ
或WANT_WRITE
指示时才调用poll
。
更新::您在阻塞和非阻塞方法之间有一个“各占一半”的混合体。这不可能工作。问题很简单:在调用 SSL_read
之前,您不知道它是否需要从套接字读取。如果您先调用 poll
,即使 SSL_read
不需要从套接字读取,您也会阻塞。如果您先调用 SSL_read
,如果确实需要从套接字读取数据,它将阻塞。 SSL_pending
对您没有帮助。如果 SSL_read
需要write 到套接字以取得前进的进展,SSL_pending
将返回零,但调用 poll
将永远阻止。
你有两个理智的选择:
阻止。让 socket 设置阻塞。当你想读的时候调用SSL_read
,当你想写的时候调用SSL_write
。他们会阻止。阻塞套接字可以阻塞,这就是它们的工作方式。
非阻塞。将套接字设置为非阻塞。当你想读的时候调用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/
这个问题在这里已经有了答案: How does Scala's apply() method magic work? (3 个回答) 9年前关闭。 假设我在 scala 中有一个 MyList 类,其
这个问题在这里已经有了答案: What is a non-capturing group in regular expressions? (18 个回答) Reference - What does
这个问题是针对嵌入式系统的! 我有以下选项来初始化一个对象: Object* o = new Object(arg); 这会将对象放入堆中并返回指向它的指针。我不喜欢在嵌入式软件中使用动态分配。 Ob
我自己搜索过,没能成功的正则表达式。 我有一个 html 文件,其中包含 [] 之间的变量我想把每一个字都写进去。 [client_name][client_company] [cl
我是 Python 新手。我不明白为什么这段代码不起作用: reOptions = re.search( "[\s+@twitter\s+(?P\w+):(?P.*?)\s+]", d
在过去 7 个月左右的时间里,我几乎一直在使用 .NET C# 进行编程。在那之前,我的大部分编程都是用 C++(从学校里学的)。在工作中,我可能需要在接下来的几个月里做一大堆 C 语言。我对 C 的
我是 RE 的新手,我正在尝试获取歌词并分离出歌词标题、和声和主唱: 下面是一些歌词的例子: [Intro] D.A. got that dope! [Chorus: Travis Scott] Ic
这可能是不可能的,但我想检查是否可以用一种简单的方式表达这样的事情: // obviously doesn't work class Foo : IFoo where T: Bar {
我们的应用程序中有“user”和“study”实体,存储在它们各自的表中。一项研究代表一种研究和已收集的数据。它们是多对多的关系,所以我们需要一个链接表:studies_users。 我们为用户分配角
将测试条件添加到 Visual Studio 2010 数据库单元测试(对于 SQL Server 2008)时,这些条件称为例如rowCountCondition1、rowCountConditio
在模拟器上,我可以从设置中卸载 SD 卡。 然后我可以将它安装到我的操作系统上,然后正常卸载它。 我一直无法弄清楚如何在模拟器上重新安装它(无需重新启动)。 提示: adb 命令 remount 是无
假设在一个分支上执行了一系列提交,但该分支尚未与主干重新同步。是否可以从提交中生成全局补丁?是否可以从一系列提交中生成“分组”补丁?如果是,如何? 最佳答案 svn diff -rXXX:YYY UR
在某些情况下,我想在我的应用程序中锁定调整大小功能,为此我尝试对属性进行数据绑定(bind),并且不允许在某些情况下更改它,但没有成功。 有没有办法这样做? 这是我不成功的尝试: XAML: Vie
当我的计算机连接多个显示器时,我可以检测它们,并根据从获取的值设置位置来向它们绘制图形 get(0, 'MonitorPositions') 但是,当我在 MATLAB 运行时断开监视器时,此属性不会
我们有一个grails应用程序,该应用程序在grails数据库中存储了各种域对象。该应用程序连接到第二个数据库,运行一些原始sql,并在表中显示结果。它基本上是一个报告服务器。 我们通过在DataSo
无法比较来自不同容器的迭代器(参见这里的示例: https://stackoverflow.com/a/4664519/225186 )(或者从技术上讲,它不需要有意义。) 这就提出了另一个问题,来自
我有以下情况: 家长 Activity : ParentActivityClass { private Intent intent; @Override public void onCreate(Bu
我经常将元素与附加功能 Hook ,例如: $('.myfav').autocomplete(); $('.myfav').datepicker(); $('.myfav').click(somefu
因此,我将 tooltipster.js 库用于工具提示,并尝试更改工具提示在不同屏幕尺寸上的默认距离。 所以这是默认的 init 的样子: $(inputTooltipTrigger).tool
我在 ARM7 嵌入式环境中工作。我使用的编译器不支持完整的 C++ 功能。它不支持的一项功能是动态类型转换。 有没有办法实现dynamic_cast<>() ? 我使用 Google 寻找代码,但到
我是一名优秀的程序员,十分优秀!